]> andersk Git - splint.git/blame - src/exprNode.c
Run LCLint on the code on cleaned things up a like.
[splint.git] / src / exprNode.c
CommitLineData
616915dd 1/*
2** LCLint - annotation-assisted static program checker
3** Copyright (C) 1994-2000 University of Virginia,
4** Massachusetts Institute of Technology
5**
6** This program is free software; you can redistribute it and/or modify it
7** under the terms of the GNU General Public License as published by the
8** Free Software Foundation; either version 2 of the License, or (at your
9** option) any later version.
10**
11** This program is distributed in the hope that it will be useful, but
12** WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14** General Public License for more details.
15**
16** The GNU General Public License is available from http://www.gnu.org/ or
17** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18** MA 02111-1307, USA.
19**
20** For information on 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
23*/
24/*
25** exprNode.c
26*/
27
28# include <ctype.h> /* for isdigit */
29# include "lclintMacros.nf"
30# include "basic.h"
31# include "cgrammar.h"
32# include "cgrammar_tokens.h"
33
34# include "exprChecks.h"
35# include "aliasChecks.h"
36# include "exprNodeSList.h"
37# include "exprData.i"
38
39static bool exprNode_isEmptyStatement (exprNode p_e);
40static /*@exposed@*/ exprNode exprNode_firstStatement (/*@returned@*/ exprNode p_e);
41static bool exprNode_isFalseConstant (exprNode p_e) /*@*/ ;
42static bool exprNode_isBlock (exprNode p_e);
43static void checkGlobUse (uentry p_glob, bool p_isCall, /*@notnull@*/ exprNode p_e);
44static void exprNode_addUse (exprNode p_e, sRef p_s);
45static bool exprNode_matchArgType (ctype p_ct, exprNode p_e);
46 exprNode exprNode_fakeCopy (exprNode p_e) /*@*/ ;
47static exprNode exprNode_statementError (/*@only@*/ exprNode p_e, /*@only@*/ lltok p_t);
48static bool exprNode_matchTypes (exprNode p_e1, exprNode p_e2);
49static void checkUniqueParams (exprNode p_fcn,
50 /*@notnull@*/ exprNode p_current, exprNodeList p_args,
51 int p_paramno, uentry p_ucurrent);
52static void updateAliases (/*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2);
53static 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);
56static 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);
58static void doAssign (/*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2, bool p_isInit);
59static void checkSafeUse (exprNode p_e, sRef p_s);
60static void reflectNullTest (/*@notnull@*/ exprNode p_e, bool p_isnull);
61static void checkMacroParen (exprNode p_e);
62static exprNodeSList exprNode_flatten (/*@dependent@*/ exprNode p_e);
63static void exprNode_checkSetAny (exprNode p_e, /*@dependent@*/ cstring p_name);
64static void exprNode_checkUse (exprNode p_e, sRef p_s, fileloc p_loc);
65static void exprNode_mergeUSs (exprNode p_res, exprNode p_other);
66static void exprNode_mergeCondUSs (exprNode p_res, exprNode p_other1, exprNode p_other2);
67static /*@only@*/ /*@notnull@*/ exprNode exprNode_fromIdentifierAux (/*@observer@*/ uentry p_c);
68static 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,
72 int p_specialArgs);
73static void checkOneArg (uentry p_ucurrent, /*@notnull@*/ exprNode p_current,
74 /*@dependent@*/ exprNode p_fcn, bool p_isSpec, int p_argno, int p_totargs);
75static void
76 checkUnspecCall (/*@notnull@*/ /*@dependent@*/ exprNode p_fcn, uentryList p_params, exprNodeList p_args);
77
78static /*@only@*/ exprNode exprNode_effect (exprNode p_e)
79 /*@globals internalState@*/ ;
80static /*@only@*/ cstring exprNode_doUnparse (exprNode p_e);
81static /*@observer@*/ cstring exprNode_rootVarName (exprNode p_e);
82static /*@exposed@*/ exprNode
83 exprNode_lastStatement (/*@returned@*/ exprNode p_e);
84
85static /*@null@*/ sRef defref = sRef_undefined;
86static /*@only@*/ exprNode mustExitNode = exprNode_undefined;
87
88static int checkArgsReal (uentry p_fcn, /*@dependent@*/ exprNode p_f,
89 uentryList p_cl,
90 exprNodeList p_args, bool p_isIter, exprNode p_ret);
91
92static bool inEffect = FALSE;
93static int nowalloc = 0;
94static int totalloc = 0;
95static int maxalloc = 0;
96
97static /*@only@*/ uentry regArg;
98static /*@only@*/ uentry outArg;
99static /*@only@*/ uentry outStringArg;
100static /*@exposed@*/ sRef stdinRef;
101static /*@exposed@*/ sRef stdoutRef;
102static /*@only@*/ uentry csArg;
103static /*@only@*/ uentry csOnlyArg;
104static ctype cstringType;
105static ctype ctypeType;
106static ctype filelocType;
107static bool initMod = FALSE;
108
109/*
110** must occur after library has been read
111*/
112
113void exprNode_initMod (void)
114 /*@globals undef regArg, undef outArg, undef outStringArg,
115 undef csOnlyArg, undef csArg;
116 @*/
117{
118 uentry ue;
119 idDecl tmp;
120
121 initMod = TRUE;
122 cstringType = ctype_unknown;
123 ctypeType = ctype_unknown;
124 filelocType = ctype_unknown;
125
126 defref = sRef_undefined;
127
128 if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
129 {
130 cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
131 }
132
133 if (usymtab_existsType (cstring_makeLiteralTemp ("ctype")))
134 {
135 ctypeType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("ctype"));
136 }
137
138 if (usymtab_existsType (cstring_makeLiteralTemp ("fileloc")))
139 {
140 filelocType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("fileloc"));
141 }
142
143 if (usymtab_existsGlob (cstring_makeLiteralTemp ("stdin")))
144 {
145 ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stdin"));
146 }
147 else /* define stdin */
148 {
149 ue = uentry_makeVariable (cstring_makeLiteralTemp ("stdin"),
150 ctype_unknown,
151 fileloc_getBuiltin (),
152 FALSE);
153 uentry_setHasNameError (ue);
154 ue = usymtab_supGlobalEntryReturn (ue);
155 }
156
157 stdinRef = sRef_makePointer (uentry_getSref (ue));
158
159 if (usymtab_existsGlob (cstring_makeLiteralTemp ("stdout")))
160 {
161 ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stdout"));
162 }
163 else
164 {
165 ue = uentry_makeVariable (cstring_makeLiteralTemp ("stdout"),
166 ctype_unknown,
167 fileloc_getBuiltin (),
168 FALSE);
169 uentry_setHasNameError (ue);
170 ue = usymtab_supGlobalEntryReturn (ue);
171 }
172
173 stdoutRef = sRef_makePointer (uentry_getSref (ue));
174
175 tmp = idDecl_create (cstring_undefined, qtype_create (ctype_unknown));
176
177 regArg = uentry_makeParam (tmp, PARAMUNKNOWN);
178
179 idDecl_setTyp (tmp,
180 qtype_addQual (qtype_create (ctype_makePointer (ctype_unknown)),
181 qual_createOut ()));
182
183 outArg = uentry_makeParam (tmp, PARAMUNKNOWN);
184
185 idDecl_setTyp (tmp, qtype_addQual (qtype_create (ctype_string),
186 qual_createOut ()));
187
188 outStringArg = uentry_makeParam (tmp, PARAMUNKNOWN);
189
190 idDecl_setTyp (tmp, qtype_addQual (qtype_addQual (qtype_create (cstringType),
191 qual_createOnly ()),
192 qual_createNull ()));
193
194 csOnlyArg = uentry_makeParam (tmp, PARAMUNKNOWN);
195
196 idDecl_setTyp (tmp, qtype_addQual (qtype_create (cstringType), qual_createNull ()));
197 csArg = uentry_makeParam (tmp, PARAMUNKNOWN);
198
199 idDecl_free (tmp);
200}
201
202void
203exprNode_destroyMod (void)
204 /*@globals killed regArg, killed outArg, killed outStringArg,
205 killed mustExitNode, initMod @*/
206{
207 if (initMod)
208 {
209 uentry_free (regArg);
210 uentry_free (outArg);
211 uentry_free (outStringArg);
212
213 exprNode_free (mustExitNode);
214 initMod = FALSE;
215 /*@-branchstate@*/
216 }
217 /*@=branchstate@*/
218}
219
220static void exprNode_resetSref (/*@notnull@*/ exprNode e)
221{
222 e->sref = defref;
223}
224
616915dd 225static bool isFlagKey (char key)
226{
227 return (key == '-' || key == '+' || key == ' ' || key == '#');
228}
229
230static void exprNode_combineControl (/*@notnull@*/ exprNode ret,
231 /*@notnull@*/ exprNode ifclause,
232 /*@notnull@*/ exprNode elseclause)
233{
234 ret->canBreak = ifclause->canBreak || elseclause->canBreak;
235
236 ret->mustBreak =
237 (ifclause->mustBreak || exprNode_mustEscape (ifclause))
238 && (elseclause->mustBreak || exprNode_mustEscape (elseclause));
239
240 ret->exitCode = exitkind_combine (ifclause->exitCode,
241 elseclause->exitCode);
242
243}
244
245/*
246** For exprNode's returned by exprNode_effect.
247*/
248
249static bool shallowKind (exprKind kind)
250{
251 return (kind == XPR_STRINGLITERAL
252 || kind == XPR_NUMLIT
253 || kind == XPR_EMPTY
254 || kind == XPR_BODY
255 || kind == XPR_NODE);
256}
257
258static void
259exprNode_freeIniter (/*@only@*/ exprNode e)
260{
261 if (!exprNode_isError (e))
262 {
263 switch (e->kind)
264 {
265 case XPR_FACCESS:
266 sfree (e->edata->field);
267 sfree (e->edata);
268 break;
269 case XPR_FETCH:
270 exprNode_free (e->edata->op->b);
271 /*@-compdestroy@*/ sfree (e->edata->op); /*@=compdestroy@*/
272 sfree (e->edata);
273 break;
274 default:
275 llbug (message ("other: %s", exprNode_unparse (e)));
276 }
277
278 multiVal_free (e->val);
279 cstring_free (e->etext);
280 fileloc_free (e->loc);
281 sRefSet_free (e->uses);
282 sRefSet_free (e->sets);
283 sRefSet_free (e->msets);
284 guardSet_free (e->guards);
285 sfree (e);
286 }
287}
288
289void
290exprNode_freeShallow (/*@only@*/ exprNode e)
291{
292 if (!exprNode_isError (e))
293 {
294 if (shallowKind (e->kind))
295 {
296 }
297 else
298 {
299 if (!inEffect)
300 {
301 if (e->kind == XPR_EMPTY
302 || e->kind == XPR_BODY
303 || e->kind == XPR_STRINGLITERAL
304 || e->kind == XPR_NUMLIT
305 || e->kind == XPR_NODE
306 || e->kind == XPR_OFFSETOF
307 || e->kind == XPR_ALIGNOFT
308 || e->kind == XPR_ALIGNOF
309 || e->kind == XPR_SIZEOFT
310 || e->kind == XPR_SIZEOF)
311 {
312 /* don't free anything */
313 }
314 else
315 {
316 /* multiVal_free (e->val); */
317 cstring_free (e->etext);
318 fileloc_free (e->loc);
319 sRefSet_free (e->uses);
320 sRefSet_free (e->sets);
321 sRefSet_free (e->msets);
322 guardSet_free (e->guards);
323 exprData_freeShallow (e->edata, e->kind);
324 nowalloc--;
325 /*@-compdestroy@*/ sfree (e); /*@=compdestroy@*/
326 /*@-branchstate@*/
327 }
328 }
329 } /*@=branchstate@*/
330 }
331 }
332
333void
334exprNode_free (exprNode e)
335{
336 if (!exprNode_isError (e))
337 {
338 if (!inEffect)
339 {
340 multiVal_free (e->val);
341 cstring_free (e->etext);
342 fileloc_free (e->loc);
343 sRefSet_free (e->uses);
344 sRefSet_free (e->sets);
345 sRefSet_free (e->msets);
346 guardSet_free (e->guards);
347 exprData_free (e->edata, e->kind);
348
349 nowalloc--;
350 sfree (e);
351 /*@-branchstate@*/
352 } /*@=branchstate@*/
353 }
354}
355
356exprNode
357exprNode_makeError ()
358{
359 return exprNode_undefined;
360}
361
362static /*@out@*/ /*@only@*/ /*@notnull@*/ exprNode
363exprNode_new (void)
364{
365 exprNode ret = (exprNode) dmalloc (sizeof (*ret));
366 /* static int lastexpnodes = 0; */
367
368 nowalloc++;
369 totalloc++;
370
371 if (nowalloc > maxalloc)
372 {
373 maxalloc = nowalloc;
374 }
375
376 return ret;
377}
378
379static /*@notnull@*/ /*@special@*/ exprNode
380 exprNode_createPlain (ctype c)
381 /*@defines result@*/
382 /*@post:isnull result->edata, result->loc, result->val, result->guards,
383 result->uses, result->sets, result->msets, result->etext @*/
384 /*@*/
385{
386 exprNode e = exprNode_new ();
387
388 e->typ = c;
389 e->kind = XPR_EMPTY;
390 e->val = multiVal_undefined;
391 e->sref = defref;
392 e->etext = cstring_undefined;
393 e->loc = fileloc_undefined;
394 e->guards = guardSet_undefined;
395 e->uses = sRefSet_undefined;
396 e->sets = sRefSet_undefined;
397 e->msets = sRefSet_undefined;
398 e->edata = exprData_undefined;
399 e->exitCode = XK_NEVERESCAPE;
400 e->canBreak = FALSE;
401 e->mustBreak = FALSE;
402 e->isJumpPoint = FALSE;
403 e->environment = environmentTable_undefined;
404 e->requiresConstraints = constraintList_new();
405 e->ensuresConstraints = constraintList_new();
406
407 return (e);
408}
409
410/*@observer@*/ exprNode exprNode_makeMustExit (void)
411{
412 if (exprNode_isUndefined (mustExitNode))
413 {
414 mustExitNode = exprNode_createPlain (ctype_unknown);
415 mustExitNode->exitCode = XK_MUSTEXIT;
416 }
417
418 return mustExitNode;
419}
420
421
422static /*@notnull@*/ /*@special@*/ exprNode exprNode_create (ctype c)
423 /*@defines result@*/
424 /*@post:isnull result->edata, result->guards, result->val,
425 result->uses, result->sets, result->msets@*/
426 /*@*/
427{
428 exprNode e = exprNode_createPlain (c);
429 e->loc = fileloc_copy (g_currentloc);
430 return (e);
431}
432
433static /*@notnull@*/ /*@special@*/ exprNode exprNode_createUnknown (void)
434 /*@defines result@*/
435 /*@post:isnull result->edata, result->guards,
436 result->uses, result->sets, result->msets@*/
437 /*@*/
438{
439 return (exprNode_create (ctype_unknown));
440}
441
442static /*@notnull@*/ /*@special@*/ exprNode
443 exprNode_createLoc (ctype c, /*@keep@*/ fileloc loc)
444 /*@defines result@*/
445 /*@post:isnull result->edata, result->guards, result->val,
446 result->uses, result->sets, result->msets@*/
447 /*@*/
448{
449 exprNode e = exprNode_createPlain (c);
450 e->loc = loc;
451 return (e);
452}
453
454static void
455 exprNode_copySets (/*@special@*/ /*@notnull@*/ exprNode ret, exprNode e)
456 /*@defines ret->guards, ret->uses, ret->sets, ret->msets@*/
457{
458 if (exprNode_isDefined (e))
459 {
460 ret->guards = guardSet_copy (e->guards);
461 ret->uses = sRefSet_newCopy (e->uses);
462 ret->sets = sRefSet_newCopy (e->sets);
463 ret->msets = sRefSet_newCopy (e->msets);
464 }
465 else
466 {
467 ret->guards = guardSet_undefined;
468 ret->uses = sRefSet_undefined;
469 ret->sets = sRefSet_undefined;
470 ret->msets = sRefSet_undefined;
471 }
472}
473
474static /*@notnull@*/ /*@special@*/ exprNode
475 exprNode_createPartialLocCopy (exprNode e, /*@only@*/ fileloc loc)
476 /*@defines result@*/
477 /*@post:isnull result->edata, result->etext@*/
478 /*@*/
479{
480 exprNode ret = exprNode_new ();
481
482 if (exprNode_isError (e))
483 {
484 ret->typ = ctype_unknown;
485 ret->val = multiVal_undefined;
486 ret->loc = loc;
487 ret->guards = guardSet_undefined;
488 ret->uses = sRefSet_undefined;
489 ret->sets = sRefSet_undefined;
490 ret->msets = sRefSet_undefined;
491 }
492 else
493 {
494 ret->typ = e->typ;
495 ret->val = multiVal_copy (e->val);
496 ret->loc = loc;
497 ret->guards = guardSet_copy (e->guards);
498 ret->uses = sRefSet_newCopy (e->uses);
499 ret->sets = sRefSet_newCopy (e->sets);
500 ret->msets = sRefSet_newCopy (e->msets);
501 }
502
503 ret->kind = XPR_EMPTY;
504 ret->sref = defref;
505 ret->etext = cstring_undefined;
506 ret->exitCode = XK_NEVERESCAPE;
507 ret->canBreak = FALSE;
508 ret->mustBreak = FALSE;
509 ret->isJumpPoint = FALSE;
510 ret->edata = exprData_undefined;
511
512 return (ret);
513}
514
515
516static /*@notnull@*/ /*@special@*/ exprNode
517 exprNode_createPartialCopy (exprNode e)
518 /*@defines result@*/
519 /*@post:isnull result->edata, result->etext@*/
520 /*@*/
521{
522 return (exprNode_createPartialLocCopy (e, fileloc_copy (exprNode_loc (e))));
523}
524
525static /*@notnull@*/ /*@special@*/ exprNode
526 exprNode_createPartialNVCopy (exprNode e)
527 /*@defines result@*/
528 /*@post:isnull result->edata, result->etext, result->val @*/
529 /*@*/
530{
531 exprNode ret = exprNode_new ();
532
533 if (exprNode_isError (e))
534 {
535 ret->typ = ctype_unknown;
536 ret->loc = fileloc_undefined;
537 ret->guards = guardSet_undefined;
538 ret->uses = sRefSet_undefined;
539 ret->sets = sRefSet_undefined;
540 ret->msets = sRefSet_undefined;
541 }
542 else
543 {
544 ret->typ = e->typ;
545 ret->loc = fileloc_copy (e->loc);
546 ret->guards = guardSet_copy (e->guards);
547 ret->uses = sRefSet_newCopy (e->uses);
548 ret->sets = sRefSet_newCopy (e->sets);
549 ret->msets = sRefSet_newCopy (e->msets);
550 }
551
552 ret->val = multiVal_undefined;
553 ret->kind = XPR_EMPTY;
554 ret->sref = defref;
555 ret->etext = cstring_undefined;
556 ret->exitCode = XK_NEVERESCAPE;
557 ret->canBreak = FALSE;
558 ret->mustBreak = FALSE;
559 ret->isJumpPoint = FALSE;
560 ret->edata = exprData_undefined;
561
562 return (ret);
563}
564
565static /*@notnull@*/ /*@special@*/ exprNode
566 exprNode_createSemiCopy (exprNode e)
567 /*@defines result@*/
568 /*@post:isnull result->edata, result->etext, result->sets,
569 result->msets, result->uses, result->guards@*/
570 /*@*/
571{
572 if (exprNode_isError (e))
573 {
574 return exprNode_createPlain (ctype_unknown);
575 }
576 else
577 {
578 exprNode ret = exprNode_new ();
579
580 ret->typ = e->typ;
581 ret->val = multiVal_copy (e->val);
582 ret->loc = fileloc_copy (e->loc);
583 ret->guards = guardSet_undefined;
584 ret->uses = sRefSet_undefined;
585 ret->sets = sRefSet_undefined;
586 ret->msets = sRefSet_undefined;
587
588 ret->kind = XPR_EMPTY;
589 ret->sref = defref;
590 ret->etext = cstring_undefined;
591 ret->exitCode = XK_NEVERESCAPE;
592 ret->canBreak = FALSE;
593 ret->mustBreak = FALSE;
594 ret->isJumpPoint = FALSE;
595 ret->edata = exprData_undefined;
596
597 return (ret);
598 }
599}
600
601bool
602exprNode_isNullValue (exprNode e)
603{
604 if (exprNode_isDefined (e))
605 {
606 multiVal m = exprNode_getValue (e);
607
608 if (multiVal_isInt (m))
609 {
610 return (multiVal_forceInt (m) == 0);
611 }
612 }
613
614 return FALSE;
615}
616
617static bool
618exprNode_isUnknownConstant (/*@notnull@*/ exprNode e)
619{
620 while (e->kind == XPR_PARENS)
621 {
622 e = exprData_getUopNode (e->edata);
623 llassert (exprNode_isDefined (e));
624 }
625
626 if (e->kind == XPR_CONST)
627 {
628 multiVal m = exprNode_getValue (e);
629
630 if (multiVal_isUnknown (m))
631 {
632 return TRUE;
633 }
634 }
635
636 return FALSE;
637}
638
639/*@only@*/ exprNode
640 exprNode_numLiteral (ctype c, /*@temp@*/ cstring t,
641 /*@only@*/ fileloc loc, long val)
642{
643 exprNode e = exprNode_createLoc (c, loc);
644
645 e->kind = XPR_NUMLIT;
646
647 llassert (multiVal_isUndefined (e->val));
648 e->val = multiVal_makeInt (val);
649 e->edata = exprData_makeLiteral (cstring_copy (t));
650
651 if (val == 0)
652 {
653 e->sref = sRef_makeUnknown ();
654 sRef_setDefNull (e->sref, e->loc);
655 }
656
657 DPRINTF (("Num lit: %s / %s", exprNode_unparse (e), ctype_unparse (exprNode_getType (e))));
658 return (e);
659}
660
661/*@only@*/ exprNode
662exprNode_charLiteral (char c, cstring text, /*@only@*/ fileloc loc)
663{
664 exprNode e = exprNode_createLoc (ctype_char, loc);
665
666 if (context_getFlag (FLG_CHARINTLITERAL))
667 {
668 e->typ = ctype_makeConj (ctype_char, ctype_int);
669 }
670
671 e->kind = XPR_NUMLIT;
672 e->val = multiVal_makeChar (c);
673
674 e->edata = exprData_makeLiteral (cstring_copy (text));
675 return (e);
676}
677
678/*@only@*/ exprNode
679exprNode_floatLiteral (double d, ctype ct, cstring text, /*@only@*/ fileloc loc)
680{
681 exprNode e = exprNode_createLoc (ct, loc);
682
683 e->kind = XPR_NUMLIT;
684 e->val = multiVal_makeDouble (d);
685 e->edata = exprData_makeLiteral (cstring_copy (text));
686 return (e);
687}
688
689multiVal exprNode_getValue (exprNode e)
690{
691 while (exprNode_isInParens (e)) {
692 if (e->edata != NULL) {
693 e = exprData_getUopNode (e->edata);
694 } else {
695 break;
696 }
697 }
698
699 if (exprNode_isDefined (e)) {
700 return e->val;
701 } else {
702 return multiVal_undefined;
703 }
704}
705
706/*@only@*/ exprNode
707exprNode_stringLiteral (/*@only@*/ cstring t, /*@only@*/ fileloc loc)
708{
709 exprNode e = exprNode_createLoc (ctype_string, loc);
710 int len = cstring_length (t) - 2;
711 char *ts = cstring_toCharsSafe (t);
712 char *s = cstring_toCharsSafe (cstring_create (len + 1));
713
714 if (context_getFlag (FLG_STRINGLITERALLEN))
715 {
716 if (len > context_getValue (FLG_STRINGLITERALLEN))
717 {
718 voptgenerror (FLG_STRINGLITERALLEN,
719 message
720 ("String literal length (%d) exceeds maximum "
721 "length (%d): %s",
722 len,
723 context_getValue (FLG_STRINGLITERALLEN),
724 t),
725 e->loc);
726 }
727 }
728
729 strncpy (s, ts+1, size_fromInt (len));
730 *(s + len) = '\0';
731
732
733 e->kind = XPR_STRINGLITERAL;
734 e->val = multiVal_makeString (cstring_fromCharsO (s));
735 e->edata = exprData_makeLiteral (t);
736 e->sref = sRef_makeType (ctype_string);
737 /* Start modifications */
738 /* This expr is null terminated, so we set the len and size */
739 sRef_setNullTerminatedState(e->sref);
740 /*
741 TPRINTF("Len is set to : %d\n\n", strlen((char *)multiVal_forceString(e->val)));
742 TPRINTF("Size is set to : %d\n\n", strlen((char *)multiVal_forceString(e->val)));
743 TPRINTF("State is set to: %d\n\n", e->sref->bufinfo.bufstate);
744 */
745 sRef_setLen(e->sref, strlen((char *)multiVal_forceString(e->val)));
746 sRef_setSize(e->sref, strlen((char *)multiVal_forceString(e->val)));
747
748 if (context_getFlag (FLG_READONLYSTRINGS))
749 {
750 sRef_setAliasKind (e->sref, AK_STATIC, fileloc_undefined);
751 sRef_setExKind (e->sref, XO_OBSERVER, loc);
752 }
753 else
754 {
755 sRef_setAliasKind (e->sref, AK_ERROR, fileloc_undefined);
756 }
757
758 return (e); /* s released */
759}
760
761exprNode exprNode_fromUIO (cstring c)
762{
763 fileloc loc = context_getSaveLocation ();
764 exprNode e = exprNode_createPlain (ctype_unknown);
765
766 e->kind = XPR_VAR;
767
768 if (fileloc_isUndefined (loc))
769 {
770 loc = fileloc_copy (g_currentloc);
771 }
772
773 e->loc = loc; /* save loc was mangled */
774 e->sref = defref;
775
776 if (usymtab_exists (c))
777 {
778 uentry ue = usymtab_lookupEither (c);
779
780 if (uentry_isDatatype (ue)
781 && uentry_isSpecified (ue))
782 {
783 llfatalerror
784 (message ("%q: Specified datatype %s used in code, but not defined. "
785 "(Cannot continue reasonably from this error.)",
786 fileloc_unparse (e->loc), c));
787 }
788 else
789 {
790 BADBRANCH;
791 }
792 }
793
794 llassertprint (!usymtab_exists (c), ("Entry exists: %s", c));
795
796 /*
797 ** was supercedeGlobalEntry...is this better?
798 */
799
800 if (!context_inIterEnd ())
801 {
802 if (context_inMacro ())
803 {
804 if (context_getFlag (FLG_UNRECOG))
805 {
806 voptgenerror
807 (FLG_MACROUNDEF,
808 message ("Unrecognized identifier in macro definition: %s", c), e->loc);
809 }
810 else
811 {
812 flagcode_recordSuppressed (FLG_UNRECOG);
813 }
814 }
815 else
816 {
817 voptgenerror
818 (FLG_UNRECOG, message ("Unrecognized identifier: %s", c),
819 e->loc);
820 }
821 }
822
823 e->edata = exprData_makeId (uentry_makeUnrecognized (c, fileloc_copy (loc)));
824
825 /* No alias errors for unrecognized identifiers */
826 sRef_setAliasKind (e->sref, AK_ERROR, loc);
827
828 return (e);
829}
830
831exprNode exprNode_createId (/*@observer@*/ uentry c)
832{
833 if (uentry_isValid (c))
834 {
835 exprNode e = exprNode_new ();
836
837 e->typ = uentry_getType (c);
838
839 if (uentry_isFunction (c)
840 && !sRef_isLocalVar (uentry_getSref (c)))
841 {
842 e->sref = sRef_undefined;
843 }
844 else
845 {
846 e->sref = uentry_getSref (c);
847 }
848
849 if (sRef_isStateUnknown (e->sref) && uentry_isNonLocal (c))
850 {
851 sRef_setDefined (e->sref, fileloc_undefined);
852 }
853
854 /*
855 ** yoikes! leaving this out was a heinous bug...that would have been
856 ** caught if i had lclint working first. gag!
857 */
858
859 e->etext = cstring_undefined;
860
861 if (uentry_isEitherConstant (c))
862 {
863 e->kind = XPR_CONST;
864 e->val = multiVal_copy (uentry_getConstantValue (c));
865 }
866 else
867 {
868 e->kind = XPR_VAR;
869 e->val = multiVal_unknown ();
870 }
871
872 e->edata = exprData_makeId (c);
873 e->loc = context_getSaveLocation ();
874
875 if (fileloc_isUndefined (e->loc))
876 {
877 fileloc_free (e->loc);
878 e->loc = fileloc_copy (g_currentloc);
879 }
880
881 e->guards = guardSet_new ();
882 e->sets = sRefSet_new ();
883 e->msets = sRefSet_new ();
884 e->uses = sRefSet_new ();
885
886 /*> missing fields, detected by lclint <*/
887 e->exitCode = XK_NEVERESCAPE;
888 e->isJumpPoint = FALSE;
889 e->canBreak = FALSE;
890 e->mustBreak = FALSE;
891
892 return e;
893 }
894 else
895 {
896 return exprNode_createUnknown ();
897 }
898}
899
900/*@notnull@*/ exprNode
901exprNode_fromIdentifier (/*@observer@*/ uentry c)
902{
903 exprNode ret;
904
905 if (context_justPopped ()) /* watch out! c could be dead */
906 {
907 uentry ce = usymtab_lookupSafe (LastIdentifier ());
908
909 if (uentry_isValid (ce))
910 {
911 c = ce;
912 }
913 else
914 {
915 llbuglit ("Looks like Aunt Millie forgot to walk to dog again.");
916 }
917 }
918
919 ret = exprNode_fromIdentifierAux (c);
920
921 return ret;
922}
923
924
925static /*@only@*/ /*@notnull@*/ exprNode
926exprNode_fromIdentifierAux (/*@observer@*/ uentry c)
927{
928 exprNode e = exprNode_createId (c);
929 sRef sr = e->sref;
930
931 uentry_setUsed (c, e->loc);
932
933 if (uentry_isVar (c) && sRef_isGlobal (sr))
934 {
935 checkGlobUse (c, FALSE, e);
936 }
937
938 return (e);
939}
940
941static bool
942exprNode_isZero (exprNode e)
943{
944 if (exprNode_isDefined (e))
945 {
946 multiVal m = exprNode_getValue (e);
947
948 if (multiVal_isInt (m))
949 {
950 return (multiVal_forceInt (m) == 0);
951 }
952 }
953
954 return FALSE;
955}
956
957static bool
958exprNode_isNonNegative (exprNode e)
959{
960 if (exprNode_isDefined (e))
961 {
962 multiVal m = exprNode_getValue (e);
963
964 if (multiVal_isInt (m))
965 {
966 return (multiVal_forceInt (m) >= 0);
967 }
968 }
969
970 return FALSE;
971}
972
973/*
974** a[x] - uses a but NOT a[]
975** result sref = a[] (set/use in assignment)
976**
977** The syntax x[a] is also legal in C, and has the same
978** semantics. If ind is an array, and arr is an int, flip
979** the arguments.
980*/
981
982/*@only@*/ exprNode
983exprNode_arrayFetch (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
984{
985 /*
986 ** error in arr, error propagates (no new messages)
987 ** error in ind, assume valid and continue
988 */
989
990 if (exprNode_isError (e1))
991 {
992 exprNode_free (e2);
993 return (exprNode_makeError ());
994 }
995 else
996 {
997 exprNode arr;
998 exprNode ind;
999 ctype carr = exprNode_getType (e1);
1000 ctype crarr = ctype_realType (carr);
1001
1002 /*
1003 ** this sets up funny aliasing, that leads to spurious
1004 ** lclint errors. Hence, the i2 comments.
1005 */
1006
1007 if (!ctype_isRealArray (crarr)
1008 && ctype_isRealNumeric (crarr)
1009 && !exprNode_isError (e2)
1010 && ctype_isRealAP (exprNode_getType (e2))) /* fetch like 3[a] */
1011 {
1012 arr = e2;
1013 ind = e1;
1014
1015 carr = exprNode_getType (arr);
1016 crarr = ctype_realType (carr);
1017 }
1018 else
1019 {
1020 arr = e1;
1021 ind = e2;
1022 }
1023
1024 if (sRef_possiblyNull (arr->sref))
1025 {
1026 if (!usymtab_isGuarded (arr->sref))
1027 {
1028 if (optgenerror (FLG_NULLDEREF,
1029 message ("Index of %s pointer %q: %s",
1030 sRef_nullMessage (arr->sref),
1031 sRef_unparse (arr->sref),
1032 exprNode_unparse (arr)),
1033 arr->loc))
1034 {
1035 sRef_showNullInfo (arr->sref);
1036
1037 /* suppress future messages */
1038 sRef_setNullError (arr->sref);
1039 }
1040 }
1041 }
1042
1043 if (exprNode_isError (ind))
1044 {
1045 if ((ctype_isArrayPtr (crarr)
1046 && !ctype_isFunction (crarr))
1047 || ctype_isUnknown (carr))
1048 {
1049 exprNode ret = exprNode_createPartialCopy (arr);
1050
1051 if (ctype_isKnown (carr))
1052 {
1053 ret->typ = ctype_baseArrayPtr (crarr);
1054 }
1055 else
1056 {
1057 ret->typ = ctype_unknown;
1058 }
1059
1060 ret->sref = sRef_makeArrayFetch (arr->sref);
1061
1062 ret->kind = XPR_FETCH;
1063
1064 /*
1065 ** Because of funny aliasing (when arr and ind are
1066 ** flipped) spurious errors would be reported here.
1067 */
1068
1069 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1070 checkSafeUse (ret, arr->sref);
1071 return (ret);
1072 }
1073 else
1074 {
1075 voptgenerror (FLG_TYPE,
1076 message ("Array fetch from non-array (%t): %s[%s]", carr,
1077 exprNode_unparse (e1), exprNode_unparse (e2)),
1078 arr->loc);
1079 exprNode_free (arr);
1080 return (exprNode_makeError ());
1081 }
1082 }
1083 else
1084 {
1085 if (!ctype_isForceRealInt (&(ind->typ)))
1086 {
1087 ctype rt = ctype_realType (ind->typ);
1088
1089 if (ctype_isChar (rt))
1090 {
1091 vnoptgenerror
1092 (FLG_CHARINDEX,
1093 message ("Array fetch using non-integer, %t: %s[%s]",
1094 ind->typ,
1095 exprNode_unparse (e1), exprNode_unparse (e2)),
1096 arr->loc);
1097 }
1098 else if (ctype_isEnum (rt))
1099 {
1100 vnoptgenerror
1101 (FLG_ENUMINDEX,
1102 message ("Array fetch using non-integer, %t: %s[%s]",
1103 ind->typ,
1104 exprNode_unparse (e1), exprNode_unparse (e2)),
1105 arr->loc);
1106 }
1107 else
1108 {
1109 voptgenerror
1110 (FLG_TYPE,
1111 message ("Array fetch using non-integer, %t: %s[%s]",
1112 ind->typ,
1113 exprNode_unparse (e1), exprNode_unparse (e2)),
1114 arr->loc);
1115 }
1116
1117 multiVal_free (ind->val);
1118 ind->val = multiVal_unknown ();
1119 }
1120
1121 if (ctype_isArrayPtr (crarr) && !ctype_isFunction (crarr))
1122 {
1123 exprNode ret = exprNode_createSemiCopy (arr);
1124 multiVal m = exprNode_getValue (ind);
1125
1126 ret->typ = ctype_baseArrayPtr (crarr);
1127 ret->kind = XPR_FETCH;
1128
1129 if (multiVal_isInt (m))
1130 {
1131 int i = (int) multiVal_forceInt (m);
1132
1133 if (sRef_isValid (arr->sref)) {
1134 ret->sref = sRef_makeArrayFetchKnown (arr->sref, i);
1135 } else {
1136 ret->sref = sRef_undefined;
1137 }
1138 }
1139 else
1140 {
1141 ret->sref = sRef_makeArrayFetch (arr->sref);
1142 }
1143
1144 ret->sets = sRefSet_realNewUnion (arr->sets, ind->sets);
1145 ret->msets = sRefSet_realNewUnion (arr->msets, ind->msets);
1146 ret->uses = sRefSet_realNewUnion (arr->uses, ind->uses);
1147
1148 /* (see comment on spurious errors above) */
1149 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1150
1151 exprNode_checkUse (ret, ind->sref, ind->loc);
1152 exprNode_checkUse (ret, arr->sref, arr->loc);
1153
1154 return (ret);
1155 }
1156 else
1157 {
1158 if (ctype_isUnknown (carr))
1159 {
1160 exprNode ret = exprNode_createPartialCopy (arr);
1161
1162 ret->kind = XPR_FETCH;
1163 ret->typ = ctype_unknown;
1164 ret->sets = sRefSet_union (ret->sets, ind->sets);
1165 ret->msets = sRefSet_union (ret->msets, ind->msets);
1166 ret->uses = sRefSet_union (ret->uses, ind->uses);
1167
1168 /* (see comment on spurious errors above) */
1169 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1170
1171 exprNode_checkUse (ret, ind->sref, ind->loc);
1172 exprNode_checkUse (ret, arr->sref, arr->loc);
1173 return (ret);
1174 }
1175 else
1176 {
1177 voptgenerror
1178 (FLG_TYPE,
1179 message ("Array fetch from non-array (%t): %s[%s]", carr,
1180 exprNode_unparse (e1), exprNode_unparse (e2)),
1181 arr->loc);
1182
1183 exprNode_free (arr);
1184 exprNode_free (ind);
1185
1186 return (exprNode_makeError ());
1187 }
1188 }
1189 }
1190 }
1191 BADEXIT;
1192}
1193
1194
1195static int
1196checkArgs (uentry fcn, /*@dependent@*/ exprNode f, ctype t,
1197 exprNodeList args, exprNode ret)
1198{
1199 return (checkArgsReal (fcn, f, ctype_argsFunction (t), args, FALSE, ret));
1200}
1201
1202/*
1203** checkPrintfArgs --- checks arguments for printf-like functions
1204** Arguments before ... have already been checked.
1205** The argument before the ... is a char *.
1206** argno is the format string argument.
1207*/
1208
1209static void
1210checkPrintfArgs (/*@notnull@*/ /*@dependent@*/ exprNode f, uentry fcn,
1211 exprNodeList args, exprNode ret, int argno)
1212{
1213 /*
1214 ** the last argument before the elips is the format string
1215 */
1216
1217 int i = argno;
1218 fileloc formatloc;
1219 int nargs = exprNodeList_size (args);
1220 uentryList params = uentry_getParams (fcn);
1221 exprNode a;
1222
1223 /*
1224 ** These should be ensured by checkSpecialFunction
1225 */
1226
1227 llassert (uentryList_size (params) == argno + 1);
1228 llassert (uentry_isElipsisMarker (uentryList_getN (params, argno)));
1229
1230 a = exprNodeList_getN (args, argno - 1);
1231 formatloc = fileloc_copy (exprNode_loc (a));
1232
1233 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
1234 && exprNode_knownStringValue (a))
1235 {
1236 char *format = cstring_toCharsSafe (multiVal_forceString (exprNode_getValue (a)));
1237 char *code = format;
1238 char *ocode = code;
1239
1240 nargs = exprNodeList_size (args);
1241
1242 while ((code = strchr (code, '%')) != NULL)
1243 {
1244 char *origcode = code;
1245 char key = *(++code);
1246 ctype modtype = ctype_int;
1247 bool modified = FALSE;
1248
1249 fileloc_addColumn (formatloc, code - ocode);
1250
1251 /* ignore flags */
1252 while (isFlagKey (key))
1253 {
1254 key = *(++code);
1255 fileloc_incColumn (formatloc);
1256 }
1257
1258 if (key == 'm') /* skipped in syslog */
1259 {
1260 continue;
1261 }
1262
1263 /* ignore field width */
1264 while (isdigit ((int) key) != 0)
1265 {
1266 key = *(++code);
1267 fileloc_incColumn (formatloc);
1268 }
1269
1270 /* ignore precision */
1271 if (key == '.')
1272 {
1273 key = *(++code);
1274 fileloc_incColumn (formatloc);
1275
1276 /*
1277 ** In printf, '*' means: read the next arg as an int for the
1278 ** field width. This seems to be missing from my copy of the
1279 ** standard x3.159-1989. Setion 4.9.6.1 refers to * (described
1280 ** later) but never does.
1281 */
1282
1283 if (key == '*')
1284 {
1285 ; /* don't do anything --- handle later */
1286 }
1287 else
1288 {
1289 while (isdigit ((int) key) != 0)
1290 {
1291 key = *(++code);
1292 fileloc_incColumn (formatloc);
1293 }
1294 }
1295 }
1296
1297 if (key == 'h')
1298 {
1299 modtype = ctype_sint; /* short */
1300 key = *(++code);
1301 fileloc_incColumn (formatloc);
1302 }
1303 else if (key == 'l' || key == 'L')
1304 {
1305 modtype = ctype_lint; /* long */
1306 key = *(++code);
1307 fileloc_incColumn (formatloc);
1308
1309 if (key == 'l' || key == 'L') {
1310 modtype = ctype_llint; /* long long */
1311 key = *(++code);
1312 fileloc_incColumn (formatloc);
1313 }
1314 }
1315 else
1316 {
1317 ; /* no modifier */
1318 }
1319
1320 /* now, key = type of conversion to apply */
1321 ++code;
1322 fileloc_incColumn (formatloc);
1323
1324 if (key != '%')
1325 {
1326 if (i >= nargs)
1327 {
1328 if (optgenerror
1329 (FLG_TYPE,
1330 message ("No argument corresponding to %q format "
1331 "code %d (%%%h): \"%s\"",
1332 uentry_getName (fcn),
1333 i, key,
1334 cstring_fromChars (format)),
1335 f->loc))
1336 {
1337 if (fileloc_isDefined (formatloc)
1338 && context_getFlag (FLG_SHOWCOL))
1339 {
1340 llgenindentmsg (cstring_makeLiteral ("Corresponding format code"),
1341 formatloc);
1342 }
1343 }
1344 i++;
1345 }
1346 else
1347 {
1348 a = exprNodeList_getN (args, i);
1349 i++;
1350
1351 if (!exprNode_isError (a))
1352 {
1353 ctype expecttype;
1354
1355 switch (key)
1356 {
1357 case '*': /* int argument for fieldwidth */
1358 expecttype = ctype_int;
1359 *(--code) = '%'; /* convert it for next code */
1360 fileloc_subColumn (formatloc, 1);
1361 /*@switchbreak@*/ break;
1362 case 'u':
1363 case 'o':
1364 expecttype = ctype_combine (ctype_uint, modtype);
1365 /*@switchbreak@*/ break;
1366
1367 case 'i': /* int argument */
1368 case 'd':
1369 expecttype = ctype_combine (ctype_int, modtype);
1370 /*@switchbreak@*/ break;
1371
1372 case 'x': /* unsigned int */
1373 case 'X':
1374 expecttype = ctype_combine (ctype_uint, modtype);
1375 /*@switchbreak@*/ break;
1376
1377 case 'e':
1378 case 'E':
1379 case 'g':
1380 case 'G':
1381 case 'f': /* double */
1382 expecttype = ctype_combine (ctype_double, modtype);
1383 /*@switchbreak@*/ break;
1384
1385 case 'c': /* int converted to char (check its a char?) */
1386 expecttype = ctype_makeConj (ctype_char, ctype_uchar);
1387 /*@switchbreak@*/ break;
1388
1389 case 's': /* string */
1390 expecttype = ctype_string;
1391 /*@switchbreak@*/ break;
1392 case '[':
1393 /* skip to ']' */
1394 while (((key = *(++code)) != ']')
1395 && (key != '\0'))
1396 {
1397 fileloc_incColumn (formatloc);
1398 }
1399
1400 if (key == '\0')
1401 {
1402 llfatalerrorLoc
1403 (message ("Bad character set format: %s",
1404 cstring_fromChars (origcode)));
1405 }
1406
1407 expecttype = ctype_string;
1408 /*@switchbreak@*/ break;
1409
1410 case 'p': /* pointer */
1411 expecttype = ctype_makePointer (ctype_void);
1412 /* really! */
1413 /*@switchbreak@*/ break;
1414
1415 case 'n': /* pointer to int, modified by call! */
1416 expecttype = ctype_combine (ctype_makePointer (ctype_int), modtype);
1417 modified = TRUE;
1418 uentry_setDefState (regArg, SS_ALLOCATED); /* corresponds to out */
1419 /*@switchbreak@*/ break;
1420
1421 case 'm': /* in a syslog, it doesn't consume an argument */
1422 /* should check we're really doing syslog */
1423
1424 /*@switchbreak@*/ break;
1425
1426
1427 default:
1428 expecttype = ctype_unknown;
1429
1430 voptgenerror
1431 (FLG_FORMATCODE,
1432 message ("Unrecognized format code: %s",
1433 cstring_fromChars (origcode)),
1434 fileloc_isDefined (formatloc)
1435 ? formatloc : g_currentloc);
1436
1437 /*@switchbreak@*/ break;
1438 }
1439
1440 if (!(exprNode_matchArgType (expecttype, a)))
1441 {
1442 if (ctype_isVoidPointer (expecttype)
1443 && ctype_isRealAbstract (a->typ)
1444 && (context_getFlag (FLG_ABSTVOIDP)))
1445 {
1446 ;
1447 }
1448 else
1449 {
1450 if (llgenformattypeerror
1451 (expecttype, exprNode_undefined,
1452 a->typ, a,
1453 message ("Format argument %d to %q (%%%h) expects "
1454 "%t gets %t: %s",
1455 i - argno,
1456 uentry_getName (fcn),
1457 key, expecttype,
1458 a->typ, exprNode_unparse (a)),
1459 a->loc))
1460 {
1461 if (fileloc_isDefined (formatloc)
1462 && context_getFlag (FLG_SHOWCOL))
1463 {
1464 llgenindentmsg
1465 (cstring_makeLiteral
1466 ("Corresponding format code"),
1467 formatloc);
1468 }
1469 }
1470 }
1471 }
1472
1473 uentry_setType (regArg, expecttype);
1474 checkOneArg (regArg, a, f, FALSE, i+1, nargs);
1475
1476 if (ctype_equal (expecttype, ctype_string))
1477 {
1478 exprNode_checkUse (a, sRef_makePointer (a->sref), a->loc);
1479 }
1480
1481 uentry_setType (regArg, ctype_unknown);
1482 uentry_fixupSref (regArg);
1483
1484 if (modified)
1485 {
1486 exprNode_checkCallModifyVal (a->sref, args, f, ret);
1487 }
1488 }
1489 else
1490 {
1491 ;
1492 }
1493 }
1494 }
1495 ocode = code;
1496 }
1497
1498 if (i < nargs)
1499 {
1500 voptgenerror (FLG_TYPE,
1501 message ("Format string for %q has %d arg%p, given %d",
1502 uentry_getName (fcn), i - argno, nargs - argno),
1503 f->loc);
1504 }
1505 }
1506 else
1507 {
1508 /* no checking possible for compile-time unknown format strings */
1509 }
1510
1511 fileloc_free (formatloc);
1512}
1513
1514static void
1515checkScanfArgs (/*@notnull@*/ /*@dependent@*/ exprNode f, uentry fcn,
1516 exprNodeList args, exprNode ret, int argno)
1517{
1518 int i = argno;
1519 fileloc formatloc;
1520 int nargs = exprNodeList_size (args);
1521 uentryList params = uentry_getParams (fcn);
1522 exprNode a;
1523
1524 /*
1525 ** These should be ensured by checkSpecialFunction
1526 */
1527
1528 llassert (uentryList_size (params) == argno + 1);
1529 llassert (uentry_isElipsisMarker (uentryList_getN (params, argno)));
1530
1531 a = exprNodeList_getN (args, argno - 1);
1532 formatloc = fileloc_copy (exprNode_loc (a));
1533
1534 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
1535 && exprNode_knownStringValue (a))
1536 {
1537 char *format = cstring_toCharsSafe (multiVal_forceString (exprNode_getValue (a)));
1538 char *code = format;
1539 char *ocode = code;
1540
1541 nargs = exprNodeList_size (args);
1542
1543 while ((code = strchr (code, '%')) != NULL)
1544 {
1545 char *origcode = code;
1546 char key = *(++code);
1547 ctype modtype = ctype_int;
1548 char modifier = '\0';
1549 bool modified = TRUE;
1550 bool ignore = FALSE;
1551
1552 fileloc_addColumn (formatloc, code - ocode);
1553
1554 /*
1555 ** this is based on ANSI standard library description of fscanf
1556 ** (from ANSI standard X3.159-1989, 4.9.6.1)
1557 */
1558
1559 /* '*' suppresses assignment (does not need match argument) */
1560
1561 if (key == '*')
1562 {
1563 key = *(++code);
1564 modified = FALSE;
1565 ignore = TRUE;
1566 fileloc_incColumn (formatloc);
1567 }
1568
1569 /* ignore field width */
1570 while (isdigit ((int) key) != 0)
1571 {
1572 key = *(++code);
1573 fileloc_incColumn (formatloc);
1574 }
1575
1576 if (key == 'h')
1577 {
1578 modtype = ctype_sint; /* short */
1579 key = *(++code);
1580 fileloc_incColumn (formatloc);
1581 }
1582 else if (key == 'l' || key == 'L')
1583 {
1584 modtype = ctype_lint; /* long */
1585 modifier = key;
1586
1587 key = *(++code);
1588 fileloc_incColumn (formatloc);
1589
1590 if (key == 'l' || key == 'L') {
1591 modtype = ctype_llint; /* long long */
1592 key = *(++code);
1593 fileloc_incColumn (formatloc);
1594 }
1595 }
1596 else
1597 {
1598 ; /* no modifier */
1599 }
1600
1601 /* now, key = type of conversion to apply */
1602 ++code;
1603 fileloc_incColumn (formatloc);
1604
1605 if (key != '%')
1606 {
1607 if (ignore)
1608 {
1609 ;
1610 }
1611 else
1612 {
1613 if (i >= nargs)
1614 {
1615 if (optgenerror
1616 (FLG_TYPE,
1617 message ("No argument corresponding to %q format "
1618 "code %d (%%%h): \"%s\"",
1619 uentry_getName (fcn),
1620 i, key,
1621 cstring_fromChars (format)),
1622 f->loc))
1623 {
1624 if (fileloc_isDefined (formatloc)
1625 && context_getFlag (FLG_SHOWCOL))
1626 {
1627 llgenindentmsg
1628 (cstring_makeLiteral ("Corresponding format code"),
1629 formatloc);
1630 }
1631 }
1632 i++;
1633 }
1634 else
1635 {
1636 a = exprNodeList_getN (args, i);
1637 i++;
1638
1639 if (!exprNode_isError (a))
1640 {
1641 ctype expecttype;
1642
1643 switch (key)
1644 {
1645 case '*': /* int argument for fieldwidth */
1646 expecttype = ctype_makePointer (ctype_int);
1647 *(--code) = '%'; /* convert it for next code */
1648 fileloc_subColumn (formatloc, 1);
1649 /*@switchbreak@*/ break;
1650 case 'u':
1651 case 'o':
1652 expecttype = ctype_makePointer (ctype_combine (ctype_uint, modtype));
1653 /*@switchbreak@*/ break;
1654
1655 case 'i':
1656 case 'd':
1657 case 'x':
1658 case 'X': /* unsigned int */
1659 expecttype = ctype_makePointer (ctype_combine (ctype_int, modtype));
1660 /*@switchbreak@*/ break;
1661
1662 case 'e':
1663 case 'E':
1664 case 'g':
1665 case 'G':
1666 case 'f':
1667 /* printf is double, scanf is float! */
1668
1669 if (modifier == 'l')
1670 {
1671 expecttype = ctype_makePointer (ctype_double);
1672 }
1673 else if (modifier == 'L')
1674 {
1675 expecttype = ctype_makePointer (ctype_ldouble);
1676 }
1677 else
1678 {
1679 llassert (modifier == '\0');
1680 expecttype = ctype_makePointer (ctype_float);
1681 }
1682 /*@switchbreak@*/ break;
1683
1684 case 'c': /* int converted to char (check its a char?) */
1685 expecttype = ctype_makePointer (ctype_makeConj (ctype_char, ctype_uchar));
1686 /*@switchbreak@*/ break;
1687
1688 case 's': /* string */
1689 expecttype = ctype_string;
1690 /*@switchbreak@*/ break;
1691
1692 case '[':
1693 /* skip to ']' */
1694 while (((key = *(++code)) != ']')
1695 && (key != '\0'))
1696 {
1697 fileloc_incColumn (formatloc);
1698 }
1699
1700 if (key == '\0')
1701 {
1702 llfatalerrorLoc
1703 (message ("Bad character set format: %s",
1704 cstring_fromChars (origcode)));
1705 }
1706
1707 expecttype = ctype_string;
1708 /*@switchbreak@*/ break;
1709
1710 case 'p': /* pointer */
1711 expecttype = ctype_unknown;
1712 /* really! */
1713 /*@switchbreak@*/ break;
1714
1715 case 'n': /* pointer to int, modified by call! */
1716 expecttype = ctype_makePointer (ctype_int);
1717 /*@switchbreak@*/ break;
1718
1719 default:
1720 expecttype = ctype_unknown;
1721
1722 voptgenerror
1723 (FLG_FORMATCODE,
1724 message ("Unrecognized format code: %s",
1725 cstring_fromChars (origcode)),
1726 fileloc_isDefined (formatloc)
1727 ? formatloc : g_currentloc);
1728
1729 /*@switchbreak@*/ break;
1730 }
1731
1732 if (!(exprNode_matchArgType (expecttype, a)))
1733 {
1734 if (ctype_isVoidPointer (expecttype)
1735 && ctype_isRealAbstract (a->typ)
1736 && (context_getFlag (FLG_ABSTVOIDP)))
1737 {
1738 ;
1739 }
1740 else
1741 {
1742 if (modifier != '\0')
1743 {
1744 if (llgenformattypeerror
1745 (expecttype, exprNode_undefined,
1746 a->typ, a,
1747 message ("Format argument %d to %q (%%%h%h) expects "
1748 "%t gets %t: %s",
1749 i - argno,
1750 uentry_getName (fcn),
1751 modifier,
1752 key, expecttype,
1753 a->typ, exprNode_unparse (a)),
1754 a->loc))
1755 {
1756 if (fileloc_isDefined (formatloc)
1757 && context_getFlag (FLG_SHOWCOL))
1758 {
1759 llgenindentmsg
1760 (cstring_makeLiteral
1761 ("Corresponding format code"),
1762 formatloc);
1763 }
1764 }
1765
1766 }
1767 else
1768 {
1769 if (llgenformattypeerror
1770 (expecttype, exprNode_undefined,
1771 a->typ, a,
1772 message ("Format argument %d to %q (%%%h) expects "
1773 "%t gets %t: %s",
1774 i - argno,
1775 uentry_getName (fcn),
1776 key, expecttype,
1777 a->typ, exprNode_unparse (a)),
1778 a->loc))
1779 {
1780 if (fileloc_isDefined (formatloc)
1781 && context_getFlag (FLG_SHOWCOL))
1782 {
1783 llgenindentmsg
1784 (cstring_makeLiteral
1785 ("Corresponding format code"),
1786 formatloc);
1787 }
1788 }
1789 }
1790 }
1791 }
1792
1793 uentry_setType (outArg, expecttype);
1794 checkOneArg (outArg, a, f, FALSE, i+1, nargs);
1795 uentry_setType (outArg, ctype_unknown);
1796 uentry_fixupSref (outArg);
1797
1798 if (modified)
1799 {
1800 exprNode_checkCallModifyVal (a->sref, args, f, ret);
1801 }
1802 }
1803 else
1804 {
1805 /* a->sref = defref; */
1806 }
1807 }
1808 }
1809 }
1810 ocode = code;
1811 }
1812
1813 if (i < nargs)
1814 {
1815 voptgenerror (FLG_TYPE,
1816 message ("Format string for %q has %d arg%p, given %d",
1817 uentry_getName (fcn), i - argno, nargs - argno),
1818 f->loc);
1819 }
1820 }
1821 else
1822 {
1823 /* no checking possible for compile-time unknown format strings */
1824 }
1825
1826 fileloc_free (formatloc);
1827}
1828
1829static void
1830checkMessageArgs (/*@notnull@*/ /*@dependent@*/ exprNode f,
1831 uentry fcn,
1832 exprNodeList args,
1833 /*@unused@*/ int argno)
1834{
1835 /*
1836 ** the last argument before the elips is the format string
1837 */
1838
1839 int nargs = exprNodeList_size (args);
1840 int i = argno;
1841 fileloc formatloc;
1842 exprNode a;
1843
1844 a = exprNodeList_getN (args, argno - 1);
1845 formatloc = fileloc_copy (exprNode_loc (a));
1846
1847 if (ctype_isUnknown (cstringType)) {
1848 if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
1849 {
1850 cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
1851 }
1852 }
1853
1854 if (ctype_isUnknown (ctypeType)) {
1855 if (usymtab_existsType (cstring_makeLiteralTemp ("ctype")))
1856 {
1857 ctypeType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("ctype"));
1858 }
1859 }
1860
1861 if (ctype_isUnknown (filelocType)) {
1862 if (usymtab_existsType (cstring_makeLiteralTemp ("fileloc")))
1863 {
1864 filelocType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("fileloc"));
1865 }
1866 }
1867
1868 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
1869 && exprNode_knownStringValue (a))
1870 {
1871 cstring format = multiVal_forceString (exprNode_getValue (a));
1872 char *code = cstring_toCharsSafe (format);
1873 char *ocode = code;
1874
1875 nargs = exprNodeList_size (args);
1876
1877 while ((code = strchr (code, '%')) != NULL)
1878 {
1879 char *origcode = code;
1880 char key = *(++code);
1881 bool isOnly = FALSE;
1882
1883 fileloc_addColumn (formatloc, code - ocode);
1884
1885 while (key >= '0' && key <= '9')
1886 {
1887 key = *(++code);
1888 fileloc_incColumn (formatloc);
1889 }
1890
1891 ++code;
1892 fileloc_incColumn (formatloc);
1893
1894 if (key != '%')
1895 {
1896 if (key == 'p')
1897 {
1898 goto nextKey;
1899 }
1900
1901 if (i >= nargs)
1902 {
1903 voptgenerror
1904 (FLG_TYPE,
1905 message ("Message missing format arg %d (%%%h): \"%s\"",
1906 i + 1, key, format),
1907 f->loc);
1908 i++;
1909 }
1910 else
1911 {
1912 a = exprNodeList_getN (args, i);
1913 i++;
1914
1915 nextKey:
1916 if (!exprNode_isError (a))
1917 {
1918 ctype expecttype;
1919
1920 /*@-loopswitchbreak@*/
1921
1922 switch (key)
1923 {
1924 case 'c':
1925 case 'h':
1926 expecttype = ctype_char; break;
1927 case 's':
1928 expecttype = cstringType; break;
1929 case 'q':
1930 expecttype = cstringType; isOnly = TRUE; break;
1931 case 'x':
1932 expecttype = cstringType; isOnly = TRUE; break;
1933 case 'd': expecttype = ctype_int; break;
1934 case 'u': expecttype = ctype_uint; break;
1935 case 'w': expecttype = ctype_ulint; break;
1936 case 'f': expecttype = ctype_float; break;
1937 case 'b': expecttype = ctype_bool; break;
1938 case 't': expecttype = ctypeType; break;
1939 case 'l': expecttype = filelocType; break;
1940 case 'p': /* a wee bit of a hack methinks */
1941 expecttype = ctype_int;
1942 break;
1943 case 'r': expecttype = ctype_bool; break;
1944 default:
1945 expecttype = ctype_unknown;
1946 voptgenerror
1947 (FLG_FORMATCODE,
1948 message ("Unrecognized format code: %s",
1949 cstring_fromChars (origcode)),
1950 fileloc_isDefined (formatloc)
1951 ? formatloc : g_currentloc);
1952 break;
1953 }
1954 /*@=loopswitchbreak@*/
1955
1956 if (!(exprNode_matchArgType (expecttype, a)))
1957 {
1958 if (ctype_isVoidPointer (expecttype)
1959 && ctype_isRealAbstract (a->typ)
1960 && (context_getFlag (FLG_ABSTVOIDP)))
1961 {
1962 ;
1963 }
1964 else
1965 {
1966 if (llgenformattypeerror
1967 (expecttype, exprNode_undefined,
1968 a->typ, a,
1969 message ("Format argument %d to %q (%%%h) expects "
1970 "%t gets %t: %s",
1971 i - argno,
1972 uentry_getName (fcn),
1973 key, expecttype,
1974 a->typ, exprNode_unparse (a)),
1975 a->loc))
1976 {
1977 if (fileloc_isDefined (formatloc)
1978 && context_getFlag (FLG_SHOWCOL))
1979 {
1980 llgenindentmsg
1981 (cstring_makeLiteral
1982 ("Corresponding format code"),
1983 formatloc);
1984 }
1985 }
1986 }
1987 }
1988
1989 if (ctype_equal (expecttype, cstringType))
1990 {
1991 if (isOnly)
1992 {
1993 checkOneArg (csOnlyArg, a, f, FALSE, i+1, nargs);
1994 uentry_fixupSref (csOnlyArg);
1995 }
1996 else
1997 {
1998 checkOneArg (csArg, a, f, FALSE, i+1, nargs);
1999 uentry_fixupSref (csArg);
2000 }
2001 }
2002 else
2003 {
2004 checkOneArg (regArg, a, f, FALSE, i+1, nargs);
2005 uentry_fixupSref (regArg);
2006 }
2007 }
2008 }
2009 }
2010 }
2011
2012 if (i < nargs)
2013 {
2014 voptgenerror (FLG_TYPE,
2015 message ("Format string for %q has %d arg%p, given %d",
2016 uentry_getName (fcn), i - argno, nargs -argno),
2017 f->loc);
2018 }
2019 }
2020 else
2021 {
2022 /* no checking possible for compile-time unknown format strings */
2023 }
2024
2025 fileloc_free (formatloc);
2026}
2027
2028static void
2029 checkExpressionDefinedAux (/*@notnull@*/ exprNode e1,
2030 /*@notnull@*/ exprNode e2,
2031 sRefSet sets1,
2032 sRefSet sets2,
2033 lltok op,
2034 flagcode flag)
2035{
2036 bool hadUncon = FALSE;
2037
2038 if (sRef_isGlobal (sRef_getRootBase (e1->sref)) &&
2039 sRefSet_hasUnconstrained (sets2))
2040 {
2041 voptgenerror
2042 (FLG_EVALORDERUNCON,
2043 message
2044 ("Expression may have undefined behavior (%q used in right operand "
2045 "may set global variable %q used in left operand): %s %s %s",
2046 sRefSet_unparseUnconstrained (sets2),
2047 sRef_unparse (sRef_getRootBase (e1->sref)),
2048 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2049 e2->loc);
2050 }
2051
2052 if (sRef_isGlobal (sRef_getRootBase (e2->sref)) &&
2053 sRefSet_hasUnconstrained (sets1))
2054 {
2055 voptgenerror
2056 (FLG_EVALORDERUNCON,
2057 message
2058 ("Expression has undefined behavior (%q used in left operand "
2059 "may set global variable %q used in right operand): %s %s %s",
2060 sRefSet_unparseUnconstrained (sets1),
2061 sRef_unparse (e2->sref),
2062 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2063 e2->loc);
2064 }
2065
2066 sRefSet_realElements (e1->uses, sr)
2067 {
2068 if (sRef_isMeaningful (sr) && sRefSet_member (sets2, sr))
2069 {
2070 voptgenerror
2071 (FLG_EVALORDER,
2072 message
2073 ("Expression has undefined behavior (left operand uses %q, "
2074 "modified by right operand): %s %s %s",
2075 sRef_unparse (sr),
2076 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2077 e2->loc);
2078 }
2079 } end_sRefSet_realElements;
2080
2081 sRefSet_realElements (sets1, sr)
2082 {
2083 if (sRef_isMeaningful (sr))
2084 {
2085 if (sRef_same (sr, e2->sref))
2086 {
2087 voptgenerror
2088 (flag,
2089 message
2090 ("Expression has undefined behavior (value of right operand "
2091 "modified by left operand): %s %s %s",
2092 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2093 e2->loc);
2094 }
2095 else if (sRefSet_member (e2->uses, sr))
2096 {
2097 voptgenerror
2098 (flag,
2099 message
2100 ("Expression has undefined behavior (left operand modifies %q, "
2101 "used by right operand): %s %s %s",
2102 sRef_unparse (sr),
2103 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2104 e2->loc);
2105 }
2106 else
2107 {
2108 if (sRefSet_member (sets2, sr))
2109 {
2110 if (sRef_isUnconstrained (sr))
2111 {
2112 if (hadUncon)
2113 {
2114 ;
2115 }
2116 else
2117 {
2118 hadUncon = optgenerror
2119 (FLG_EVALORDERUNCON,
2120 message
2121 ("Expression may have undefined behavior. Left operand "
2122 "calls %q; right operand calls %q. The unconstrained "
2123 "functions may modify global state used by "
2124 "the other operand): %s %s %s",
2125 sRefSet_unparseUnconstrained (sets1),
2126 sRefSet_unparseUnconstrained (sets2),
2127 exprNode_unparse (e1), lltok_unparse (op),
2128 exprNode_unparse (e2)),
2129 e2->loc);
2130 }
2131 }
2132 else
2133 {
2134 voptgenerror
2135 (flag,
2136 message
2137 ("Expression has undefined behavior (both "
2138 "operands modify %q): %s %s %s",
2139 sRef_unparse (sr),
2140 exprNode_unparse (e1),
2141 lltok_unparse (op), exprNode_unparse (e2)),
2142 e2->loc);
2143 }
2144 }
2145 }
2146 }
2147 } end_sRefSet_realElements;
2148}
2149
2150static void checkExpressionDefined (exprNode e1, exprNode e2, lltok op)
2151{
2152 bool hasError = FALSE;
2153
2154 if (exprNode_isError (e1) || exprNode_isError (e2))
2155 {
2156 return;
2157 }
2158
2159 if (sRefSet_member (e2->sets, e1->sref))
2160 {
2161 if (e2->kind == XPR_CALL)
2162 {
2163 ;
2164 }
2165 else
2166 {
2167 hasError = optgenerror
2168 (FLG_EVALORDER,
2169 message ("Expression has undefined behavior "
2170 "(value of left operand is modified "
2171 "by right operand): %s %s %s",
2172 exprNode_unparse (e1), lltok_unparse (op),
2173 exprNode_unparse (e2)),
2174 e2->loc);
2175 }
2176 }
2177
2178 if (context_getFlag (FLG_EVALORDERUNCON))
2179 {
2180 if (sRefSet_member (e2->msets, e1->sref))
2181 {
2182 if (e2->kind == XPR_CALL)
2183 {
2184 ;
2185 }
2186 else
2187 {
2188 hasError = optgenerror
2189 (FLG_EVALORDER,
2190 message
2191 ("Expression has undefined behavior (value of left "
2192 "operand may be modified by right operand): %s %s %s",
2193 exprNode_unparse (e1), lltok_unparse (op),
2194 exprNode_unparse (e2)),
2195 e2->loc);
2196 }
2197 }
2198 }
2199
2200 if (!hasError)
2201 {
2202 checkExpressionDefinedAux (e1, e2, e1->sets, e2->sets, op, FLG_EVALORDER);
2203
2204 if (context_maybeSet (FLG_EVALORDERUNCON))
2205 {
2206 checkExpressionDefinedAux (e1, e2, e1->msets,
2207 e2->msets, op, FLG_EVALORDERUNCON);
2208 }
2209 }
2210}
2211
2212static void checkSequencing (exprNode p_f, exprNodeList p_args);
2213
2214static int
2215 checkArgsReal (uentry fcn, /*@dependent@*/ exprNode f, uentryList cl,
2216 exprNodeList args, bool isIter, exprNode ret)
2217{
2218 int special = 0;
2219
2220 if (!exprNode_isError (f))
2221 {
2222 if (!uentryList_isMissingParams (cl))
2223 {
2224 int nargs = exprNodeList_size (args);
2225 int expectargs = uentryList_size (cl);
2226 ctype last;
2227 int i = 0;
2228
2229 if (expectargs == 0)
2230 {
2231 if (nargs != 0)
2232 {
2233 if (isIter)
2234 {
2235 voptgenerror
2236 (FLG_TYPE,
2237 message ("Iter %q invoked with %d args, "
2238 "declared void",
2239 uentry_getName (fcn),
2240 nargs),
2241 f->loc);
2242 }
2243 else
2244 {
2245 voptgenerror
2246 (FLG_TYPE,
2247 message ("Function %s called with %d args, "
2248 "declared void",
2249 exprNode_unparse (f), nargs),
2250 f->loc);
2251 }
2252 }
2253 return special;
2254 }
2255
2256 last = uentry_getType (uentryList_getN (cl, expectargs - 1));
2257
2258 exprNodeList_reset (args);
2259
2260 uentryList_elements (cl, current)
2261 {
2262 ctype ct = uentry_getType (current);
2263 exprNode a;
2264
2265 if (ctype_isElips (ct))
2266 {
2267 /*
2268 ** do special checking for printf/scanf library functions
2269 **
2270 ** this is kludgey code, just for handling the special case
2271 **
2272 */
2273
2274 if (uentry_isPrintfLike (fcn))
2275 {
2276 checkPrintfArgs (f, fcn, args, ret, i);
2277 special = i;
2278 }
2279 else if (uentry_isScanfLike (fcn))
2280 {
2281 checkScanfArgs (f, fcn, args, ret, i);
2282 special = i;
2283 }
2284 else if (uentry_isMessageLike (fcn))
2285 {
2286 checkMessageArgs (f, fcn, args, i);
2287 special = i;
2288 }
2289 else
2290 {
2291 llassert (!uentry_isSpecialFunction (fcn));
2292 }
2293
2294 nargs = expectargs; /* avoid errors */
2295 break;
2296 }
2297 else
2298 {
2299 if (i >= nargs) break;
2300
2301 a = exprNodeList_current (args);
2302 exprNodeList_advance (args);
2303
2304 i++;
2305
2306 if (exprNode_isError (a))
2307 {
2308 ;
2309 }
2310 else
2311 {
2312 /*
2313 probably necessary? I'm not sure about this one
2314 checkMacroParen (a);
2315 */
2316
2317 f->guards = guardSet_union (f->guards, a->guards);
2318
2319 DPRINTF (("match arg: %s / %s", ctype_unparse (ct), ctype_unparse (a->typ)));
2320
2321 if (!(exprNode_matchArgType (ct, a)))
2322 {
2323 DPRINTF (("Args mismatch!"));
2324
2325 if (ctype_isVoidPointer (ct)
2326 && (ctype_isPointer (a->typ)
2327 && (ctype_isRealAbstract (ctype_baseArrayPtr (a->typ)))))
2328 {
2329 vnoptgenerror
2330 (FLG_ABSTVOIDP,
2331 message
2332 ("Pointer to abstract type (%t) used "
2333 "as void pointer "
2334 "(arg %d to %q): %s",
2335 a->typ, i,
2336 uentry_getName (fcn),
2337 exprNode_unparse (a)),
2338 a->loc);
2339 }
2340 else
2341 {
2342 if (isIter)
2343 {
2344 (void) gentypeerror
2345 (ct, exprNode_undefined,
2346 a->typ, a,
2347 message
2348 ("Iter %q expects arg %d to "
2349 "be %t gets %t: %s",
2350 uentry_getName (fcn),
2351 i, ct, a->typ, exprNode_unparse (a)),
2352 a->loc);
2353 }
2354 else
2355 {
2356 if (gentypeerror
2357 (ct,
2358 exprNode_undefined,
2359 a->typ,
2360 a,
2361 message
2362 ("Function %q expects arg %d to be %t gets %t: %s",
2363 uentry_getName (fcn),
2364 i, ct, a->typ, exprNode_unparse (a)),
2365 a->loc))
2366 {
2367 DPRINTF (("Types: %s / %s",
2368 ctype_unparse (ct),
2369 ctype_unparse (a->typ)));
2370 }
2371
2372 /*
2373 ** Clear null marker for abstract types.
2374 ** (It is not revealed, so suppress future messages.)
2375 */
2376
2377 if (ctype_isAbstract (a->typ))
2378 {
2379 sRef_setNullUnknown (exprNode_getSref (a), a->loc);
2380 }
2381 }
2382 }
2383 }
2384 }
2385 }
2386 } end_uentryList_elements ;
2387
2388
2389 if (expectargs != nargs) /* note: not != since we may have ... */
2390 {
2391 if (ctype_isElips (last))
2392 {
2393 voptgenerror
2394 (FLG_TYPE,
2395 message ("Function %s called with %d args, expects at least %d",
2396 exprNode_unparse (f),
2397 nargs, expectargs - 1),
2398 f->loc);
2399 }
2400 else
2401 {
2402 if (isIter)
2403 {
2404 voptgenerror
2405 (FLG_TYPE,
2406 message ("Iter %q invoked with %d args, expects %d",
2407 uentry_getName (fcn), nargs, expectargs),
2408 f->loc);
2409 }
2410 else
2411 {
2412 voptgenerror
2413 (FLG_TYPE,
2414 message ("Function %s called with %d args, expects %d",
2415 exprNode_unparse (f),
2416 nargs, expectargs),
2417 f->loc);
2418 }
2419 }
2420 }
2421 }
2422 }
2423
2424 return special;
2425}
2426
2427/*
2428** Check for undefined code sequences in function arguments:
2429**
2430** one parameter sets something used by another parameter
2431** one parameter sets something set by another parameter
2432*/
2433
2434static void
2435checkSequencingOne (exprNode f, exprNodeList args,
2436 /*@notnull@*/ exprNode el, int argno)
2437{
2438 /*
2439 ** Do second loop, iff +undefunspec
2440 */
2441
2442 int checkloop;
2443 int numloops = context_maybeSet (FLG_EVALORDERUNCON) ? 2 : 1;
2444
2445 for (checkloop = 0; checkloop < numloops; checkloop++)
2446 {
2447 sRefSet thissets;
2448
2449 if (checkloop == 0)
2450 {
2451 thissets = el->sets;
2452 }
2453 else
2454 {
2455 llassert (checkloop == 1);
2456 thissets = el->msets;
2457 }
2458
2459 sRefSet_realElements (thissets, thisset)
2460 {
2461 int j;
2462
2463 /*@access exprNodeList@*/
2464 for (j = 0; j < args->nelements; j++)
2465 {
2466 exprNode jl = args->elements[j];
2467 int thisargno = j + 1;
2468
2469 if (thisargno != argno && exprNode_isDefined (jl))
2470 {
2471 sRefSet otheruses = jl->uses;
2472
2473 if (sRef_isGlobal (sRef_getRootBase (jl->sref)) &&
2474 sRefSet_hasUnconstrained (thissets))
2475 {
2476 voptgenerror
2477 (FLG_EVALORDERUNCON,
2478 /*@-sefparams@*/
2479 message
2480 ("%q used in argument %d may set "
2481 "global variable %q used by argument %d: %s(%q)",
2482 cstring_capitalizeFree (sRefSet_unparseUnconstrained (thissets)),
2483 /*@=sefparams@*/
2484 argno,
2485 sRef_unparse (sRef_getRootBase (jl->sref)),
2486 thisargno,
2487 exprNode_unparse (f), exprNodeList_unparse (args)),
2488 el->loc);
2489 }
2490
2491 if (sRefSet_member (otheruses, thisset))
2492 {
2493 if (sRef_isUnconstrained (thisset))
2494 {
2495 voptgenerror
2496 (FLG_EVALORDERUNCON,
2497 message
2498 ("Unconstrained functions used in arguments %d (%q) "
2499 "and %d (%s) may modify "
2500 "or use global state in undefined way: %s(%q)",
2501 argno,
2502 sRefSet_unparseUnconstrainedPlain (otheruses),
2503 thisargno,
2504 sRef_unconstrainedName (thisset),
2505 exprNode_unparse (f),
2506 exprNodeList_unparse (args)),
2507 el->loc);
2508 }
2509 else
2510 {
2511 voptgenerror
2512 (FLG_EVALORDER,
2513 message
2514 ("Argument %d modifies %q, used by argument %d "
2515 "(order of evaluation of actual parameters is "
2516 "undefined): %s(%q)",
2517 argno, sRef_unparse (thisset), thisargno,
2518 exprNode_unparse (f), exprNodeList_unparse (args)),
2519 el->loc);
2520 }
2521 }
2522 else
2523 {
2524 sRefSet othersets = jl->sets;
2525
2526 if (sRefSet_member (othersets, thisset))
2527 {
2528 if (sRef_isUnconstrained (thisset))
2529 {
2530 voptgenerror
2531 (FLG_EVALORDERUNCON,
2532 message
2533 ("Unconstrained functions used in "
2534 "arguments %d (%q) and %d (%s) may modify "
2535 "or use global state in undefined way: %s(%q)",
2536 argno,
2537 sRefSet_unparseUnconstrainedPlain (othersets),
2538 thisargno,
2539 sRef_unconstrainedName (thisset),
2540 exprNode_unparse (f), exprNodeList_unparse (args)),
2541 el->loc);
2542 }
2543 else
2544 {
2545 voptgenerror
2546 (FLG_EVALORDER,
2547 message
2548 ("Argument %d modifies %q, set by argument %d (order of"
2549 " evaluation of actual parameters is undefined): %s(%q)",
2550 argno, sRef_unparse (thisset), thisargno,
2551 exprNode_unparse (f), exprNodeList_unparse (args)),
2552 el->loc);
2553 }
2554 }
2555 }
2556 }
2557 }
2558 /*@noaccess exprNodeList@*/
2559 } end_sRefSet_realElements;
2560 }
2561}
2562
2563static void
2564checkSequencing (exprNode f, exprNodeList args)
2565{
2566 if (exprNodeList_size (args) > 1)
2567 {
2568 int i;
2569 exprNode el;
2570
2571 /*@access exprNodeList*/
2572
2573 for (i = 0; i < args->nelements; i++)
2574 {
2575 el = args->elements[i];
2576
2577 if (!exprNode_isError (el))
2578 {
2579 checkSequencingOne (f, args, el, i + 1);
2580 }
2581 }
2582 /*@noaccess exprNodeList*/
2583 }
2584}
2585
2586/*
2587** requires le = exprNode_getUentry (f)
2588*/
2589
2590static void
2591checkGlobMods (/*@notnull@*/ /*@dependent@*/ exprNode f,
2592 uentry le, exprNodeList args,
2593 /*@notnull@*/ exprNode ret, int specialArgs)
2594{
2595 bool isSpec = FALSE;
2596 bool hasMods = FALSE;
2597 cstring fname;
2598 globSet usesGlobs = globSet_undefined;
2599 sRefSet mods = sRefSet_undefined;
2600 bool freshMods = FALSE;
2601 uentryList params = uentryList_undefined;
2602
2603 /*
2604 ** check globals and modifies
2605 */
2606
2607 setCodePoint ();
2608
2609 if (!uentry_isValid (le))
2610 {
2611 ctype fr = ctype_realType (f->typ);
2612
2613 if (ctype_isFunction (fr))
2614 {
2615 params = ctype_argsFunction (fr);
2616 }
2617 else
2618 {
2619 params = uentryList_missingParams;
2620 }
2621
2622 if (!context_getFlag (FLG_MODNOMODS)
2623 && !context_getFlag (FLG_GLOBUNSPEC))
2624 {
2625 checkUnspecCall (f, params, args);
2626 }
2627
2628 return;
2629 }
2630
2631 fname = uentry_rawName (le);
2632
2633 setCodePoint ();
2634
2635 if (uentry_isFunction (le))
2636 {
2637 params = uentry_getParams (le);
2638 mods = uentry_getMods (le);
2639 hasMods = uentry_hasMods (le);
2640 usesGlobs = uentry_getGlobs (le);
2641 isSpec = uentry_isSpecified (le);
2642 }
2643 else /* not a function */
2644 {
2645 ctype ct = ctype_realType (uentry_getType (le));
2646
2647 llassertprint (uentry_isVar (le) && ctype_isFunction (ct),
2648 ("checkModGlobs: uentry not a function: %s",
2649 uentry_unparse (le)));
2650
2651 params = ctype_argsFunction (ct);
2652 }
2653
2654 /*
2655 ** check globals
2656 */
2657
2658 setCodePoint ();
2659
2660
2661 globSet_allElements (usesGlobs, el)
2662 {
2663 if (sRef_isValid (el))
2664 {
2665 if (sRef_isInternalState (el) || sRef_isSystemState (el))
2666 {
2667 context_usedGlobal (el);
2668 exprNode_checkUse (f, el, f->loc);
2669
2670 if (context_checkInternalUse ())
2671 {
2672 if (!context_globAccess (el))
2673 {
2674 if (sRef_isSystemState (el)
2675 && !context_getFlag (FLG_MODFILESYSTEM))
2676 {
2677 ;
2678 }
2679 else
2680 {
2681 voptgenerror
2682 (FLG_INTERNALGLOBS,
2683 message
2684 ("Called procedure %s may access %q, but "
2685 "globals list does not include globals %s",
2686 exprNode_unparse (f),
2687 sRef_unparse (el),
2688 cstring_makeLiteralTemp (sRef_isInternalState (el)
2689 ? "internalState"
2690 : "fileSystem")),
2691 f->loc);
2692 }
2693 }
2694 }
2695 }
2696 else if (sRef_isNothing (el) || sRef_isSpecState (el))
2697 {
2698 ;
2699 }
2700 else
2701 {
2702 uentry gle = sRef_getUentry (el);
2703 sRef sr = sRef_updateSref (el);
2704
2705 if (sRef_isUndefGlob (el))
2706 {
2707 sRef_setDefined (sr, f->loc);
2708 exprNode_checkSet (f, sr);
2709 }
2710 else
2711 {
2712 /*
2713 ** check definition
2714 */
2715
2716 if (sRef_isAllocated (el))
2717 {
2718 exprNode_checkSet (f, sr);
2719 }
2720 else
2721 {
2722 if (sRef_isStateUndefined (sr))
2723 {
2724 voptgenerror
2725 (FLG_GLOBSTATE,
2726 message
2727 ("%s %q used by function undefined before call: %s",
2728 sRef_getScopeName (sr),
2729 sRef_unparse (sr),
2730 exprNode_unparse (f)),
2731 f->loc);
2732 sRef_setDefined (sr, f->loc);
2733 }
2734 exprNode_checkUse (f, sr, f->loc);
2735 }
2736
2737 checkGlobUse (gle, TRUE, f);
2738 }
2739
2740 if (sRef_isKilledGlob (el))
2741 {
2742 sRef_kill (sr, f->loc);
2743 context_usedGlobal (sr);
2744 }
2745 }
2746 }
2747 } end_globSet_allElements;
2748
2749 /*
2750 ** check modifies
2751 */
2752
2753 if (context_hasMods () || context_getFlag (FLG_MODNOMODS))
2754 {
2755 sRefSet smods = sRefSet_undefined;
2756
2757 /*
2758 ** NEED to check for modifies anything
2759 */
2760
2761 /*
2762 ** check each sRef that called function modifies (ml), is
2763 ** modifiable by tl
2764 */
2765
2766 setCodePoint ();
2767
2768 sRefSet_allElements (mods, s) /* s is something which may be modified */
2769 {
2770 if (sRef_isKindSpecial (s))
2771 {
2772 if (sRef_isSpecInternalState (s))
2773 {
2774 if (context_getFlag (FLG_MODINTERNALSTRICT))
2775 {
2776 exprNode_checkCallModifyVal (s, args, f, ret);
2777 }
2778 else
2779 {
2780 sRefSet mmods = context_modList ();
2781
2782 sRefSet_allElements (mmods, el)
2783 {
2784 if (sRef_isInternalState (el))
2785 {
2786 sRef_setModified (el);
2787 }
2788 } end_sRefSet_allElements ;
2789 }
2790 }
2791 else
2792 {
2793 exprNode_checkCallModifyVal (s, args, f, ret);
2794 }
2795 }
2796 else
2797 {
2798 sRef rb = sRef_getRootBase (s);
2799
2800 if (sRef_isGlobal (rb))
2801 {
2802 context_usedGlobal (rb);
2803 }
2804
2805 if (sRef_isFileStatic (s)
2806 && !fileId_equal (fileloc_fileId (f->loc),
2807 fileloc_fileId (uentry_whereDefined (le))))
2808 {
2809 smods = sRefSet_insert (smods, s);
2810 }
2811 else
2812 {
2813 exprNode_checkCallModifyVal (s, args, f, ret);
2814 }
2815 }
2816 } end_sRefSet_allElements;
2817
2818 setCodePoint ();
2819
2820 /*
2821 ** Static elements in modifies set can have nasty consequences.
2822 ** (I think...have not been able to reproduce a possible bug.)
2823 */
2824
2825 if (!sRefSet_isDefined (smods))
2826 {
2827 mods = sRefSet_newCopy (mods);
2828 freshMods = TRUE;
2829
2830 sRefSet_allElements (smods, el)
2831 {
2832 bool res = sRefSet_delete (mods, el);
2833
2834 llassert (res);
2835 } end_sRefSet_allElements;
2836
2837 sRefSet_free (smods);
2838 /*@-branchstate@*/
2839 }
2840 /*@=branchstate@*/
2841 }
2842 else if (sRefSet_isDefined (mods))
2843 { /* just check observers */
2844 setCodePoint ();
2845
2846 sRefSet_allElements (mods, s) /* s is something which may be modified */
2847 {
2848 sRef rb = sRef_getRootBase (s);
2849
2850 setCodePoint ();
2851
2852 if (sRef_isParam (rb))
2853 {
2854 sRef b = sRef_fixBaseParam (s, args);
2855
2856 if (sRef_isObserver (b))
2857 {
2858 exprNode e = exprNodeList_nth (args, sRef_getParam (rb));
2859
2860 if (optgenerror
2861 (FLG_MODOBSERVER,
2862 message ("Function call may modify observer%q: %s",
2863 sRef_unparsePreOpt (b), exprNode_unparse (e)),
2864 exprNode_loc (e)))
2865 {
2866 sRef_showExpInfo (b);
2867 }
2868 }
2869 }
2870 } end_sRefSet_allElements;
2871 }
2872 else
2873 {
2874 if (!hasMods) /* no specified modifications */
2875 {
2876 if (context_getFlag (FLG_MODOBSERVERUNCON))
2877 {
2878 exprNodeList_elements (args, e)
2879 {
2880 if (exprNode_isDefined (e))
2881 {
2882 sRef s = exprNode_getSref (e);
2883
2884 if (sRef_isObserver (s)
2885 && ctype_isMutable (sRef_getType (s)))
2886 {
2887 if (optgenerror
2888 (FLG_MODOBSERVERUNCON,
2889 message
2890 ("Call to unconstrained function %s may modify observer%q: %s",
2891 exprNode_unparse (f),
2892 sRef_unparsePreOpt (s), exprNode_unparse (e)),
2893 exprNode_loc (e)))
2894 {
2895 sRef_showExpInfo (s);
2896 }
2897 }
2898 }
2899 } end_exprNodeList_elements;
2900 }
2901 }
2902 }
2903
2904 checkAnyCall (f, fname, params, args, hasMods, mods, isSpec, specialArgs);
2905
2906 ret->uses = sRefSet_union (ret->uses, f->uses);
2907 ret->sets = sRefSet_union (ret->sets, f->sets);
2908 ret->msets = sRefSet_union (ret->msets, f->msets);
2909
2910 if (freshMods)
2911 {
2912 /*
2913 ** Spurious errors reported, because lclint can't tell
2914 ** mods must be fresh if freshMods is true.
2915 */
2916
2917 /*@i@*/ sRefSet_free (mods);
2918 }
2919
2920 setCodePoint ();
2921}
2922
2923void checkGlobUse (uentry glob, bool isCall, /*@notnull@*/ exprNode e)
2924{
2925 if (uentry_isVar (glob))
2926 {
2927 if (context_inFunctionLike ())
2928 {
2929 sRef sr = uentry_getSref (glob);
2930
2931 context_usedGlobal (sr);
2932
2933 if (context_checkGlobUse (glob))
2934 {
2935 if (!context_globAccess (sr))
2936 {
2937 if (isCall)
2938 {
2939 voptgenerror
2940 (FLG_GLOBALS,
2941 message ("Called procedure %s may access %s %q",
2942 exprNode_unparse (e),
2943 sRef_unparseScope (sr),
2944 uentry_getName (glob)),
2945 e->loc);
2946 }
2947 else
2948 {
2949 voptgenerror
2950 (FLG_GLOBALS,
2951 message ("Undocumented use of %s %s",
2952 sRef_unparseScope (sr),
2953 exprNode_unparse (e)),
2954 e->loc);
2955 }
2956 }
2957 }
2958 }
2959 }
2960 else
2961 {
2962 llbug (message ("Global not variable: %q", uentry_unparse (glob)));
2963 }
2964}
2965
2966static /*@only@*/ exprNode
2967functionCallSafe (/*@only@*/ /*@notnull@*/ exprNode f,
2968 ctype t, /*@keep@*/ exprNodeList args)
2969{
2970 /* requires f is a non-error exprNode, with type function */
2971 cstring fname = exprNode_unparse (f);
2972 uentry le = exprNode_getUentry (f);
2973 exprNode ret = exprNode_createPartialCopy (f);
2974 int special;
2975
2976 setCodePoint ();
2977
2978 ret->typ = ctype_returnValue (t);
2979 ret->kind = XPR_CALL;
2980
2981 ret->edata = exprData_makeCall (f, args);
2982
2983 /*
2984 ** Order of these steps is very important!
2985 **
2986 ** Must check for argument dependencies before messing up uses and sets.
2987 */
2988
2989 if (context_getFlag (FLG_EVALORDER))
2990 {
2991 exprNodeList_elements (args, current)
2992 {
2993 if (exprNode_isDefined (current))
2994 {
2995 exprNode_addUse (current, current->sref);
2996 }
2997 } end_exprNodeList_elements;
2998
2999 if (context_maybeSet (FLG_EVALORDER) || context_maybeSet (FLG_EVALORDERUNCON))
3000 {
3001 checkSequencing (f, args);
3002 }
3003
3004 exprNodeList_elements (args, current)
3005 {
3006 if (exprNode_isDefined (current) && sRef_isMeaningful (current->sref))
3007 {
3008 exprNode_addUse (ret, sRef_makeDerived (current->sref));
3009 }
3010 } end_exprNodeList_elements ;
3011 }
3012
3013 special = checkArgs (le, f, t, args, ret);
3014 checkGlobMods (f, le, args, ret, special);
3015
3016 setCodePoint ();
3017
3018 if (uentry_isValid (le)
3019 && (uentry_isFunction (le)
3020 || (uentry_isVariable (le)
3021 && ctype_isFunction (uentry_getType (le)))))
3022 {
3023 exitkind exk = uentry_getExitCode (le);
3024
3025 /* f->typ is already set to the return type */
3026
3027 ret->sref = uentry_returnedRef (le, args);
3028
3029 if (uentry_isFunction (le) && exprNodeList_size (args) >= 1)
3030 {
3031 qual nullPred = uentry_nullPred (le);
3032
3033 if (qual_isTrueNull (nullPred))
3034 {
3035 exprNode arg = exprNodeList_head (args);
3036
3037 if (exprNode_isDefined (arg))
3038 {
3039 ret->guards = guardSet_addFalseGuard (ret->guards, arg->sref);
3040 }
3041 }
3042 else if (qual_isFalseNull (nullPred))
3043 {
3044 exprNode arg = exprNodeList_head (args);
3045
3046 if (exprNode_isDefined (arg))
3047 {
3048 ret->guards = guardSet_addTrueGuard (ret->guards, arg->sref);
3049 }
3050 }
3051 else
3052 {
3053 llassert (qual_isUnknown (nullPred));
3054 }
3055 }
3056
3057 if (exitkind_isConditionalExit (exk))
3058 {
3059 /*
3060 ** True exit is:
3061 ** if (arg0) then { exit! } else { ; }
3062 ** False exit is:
3063 ** if (arg0) then { ; } else { exit! }
3064 */
3065
3066 exprNode firstArg;
3067
3068 llassert (!exprNodeList_isEmpty (args));
3069 firstArg = exprNodeList_head (args);
3070
3071 if (exprNode_isDefined (firstArg)
3072 && !guardSet_isEmpty (firstArg->guards))
3073 {
3074 usymtab_trueBranch (guardSet_undefined);
3075 usymtab_altBranch (guardSet_undefined);
3076
3077 if (exitkind_isTrueExit (exk))
3078 {
3079 usymtab_popBranches (firstArg,
3080 exprNode_makeMustExit (),
3081 exprNode_undefined,
3082 TRUE, TRUEEXITCLAUSE);
3083 }
3084 else
3085 {
3086 usymtab_popBranches (firstArg,
3087 exprNode_undefined,
3088 exprNode_makeMustExit (),
3089 TRUE, FALSEEXITCLAUSE);
3090 }
3091 }
3092
3093 ret->exitCode = XK_MAYEXIT;
3094 }
3095 else if (exitkind_mustExit (exk))
3096 {
3097 ret->exitCode = XK_MUSTEXIT;
3098 }
3099 else if (exitkind_couldExit (exk))
3100 {
3101 ret->exitCode = XK_MAYEXIT;
3102 }
3103 else
3104 {
3105 ;
3106 }
3107
3108 if (cstring_equalLit (fname, "exit"))
3109 {
3110 if (exprNodeList_size (args) == 1)
3111 {
3112 exprNode arg = exprNodeList_head (args);
3113
3114 if (exprNode_isDefined (arg) && exprNode_knownIntValue (arg))
3115 {
3116 long int val = multiVal_forceInt (exprNode_getValue (arg));
3117
3118 if (val != 0)
3119 {
3120 voptgenerror
3121 (FLG_EXITARG,
3122 message
3123 ("Argument to exit has implementation defined behavior: %s",
3124 exprNode_unparse (arg)),
3125 exprNode_loc (arg));
3126 }
3127 }
3128 }
3129 }
3130 }
3131 else
3132 {
3133 ret->sref = defref;
3134 exprNode_checkSetAny (ret, uentry_rawName (le));
3135 }
3136
3137 return (ret);
3138}
3139
3140/*
3141** this is yucky! should keep the uentry as part of exprNode!
3142*/
3143
3144/*@observer@*/ uentry
3145exprNode_getUentry (exprNode e)
3146{
3147 if (exprNode_isError (e))
3148 {
3149 return uentry_undefined;
3150 }
3151 else
3152 {
3153 cstring s = exprNode_rootVarName (e);
3154 uentry ue = usymtab_lookupSafe (s);
3155
3156 return ue;
3157 }
3158}
3159
3160exprNode
3161exprNode_makeInitBlock (lltok brace, /*@only@*/ exprNodeList inits)
3162{
3163 exprNode ret = exprNode_createPlain (ctype_unknown);
3164
3165 ret->kind = XPR_INITBLOCK;
3166 ret->edata = exprData_makeCall (exprNode_undefined, inits);
3167 ret->loc = fileloc_update (ret->loc, lltok_getLoc (brace));
3168
3169 return (ret);
3170}
3171
3172exprNode
3173exprNode_functionCall (/*@only@*/ exprNode f, /*@only@*/ exprNodeList args)
3174{
3175 ctype t;
3176
3177 setCodePoint ();
3178
3179 if (exprNode_isUndefined (f))
3180 {
3181 exprNode_free (f);
3182 exprNodeList_free (args);
3183 return exprNode_undefined;
3184 }
3185
3186 t = exprNode_getType (f);
3187
3188 if (sRef_isLocalVar (f->sref))
3189 {
3190 exprNode_checkUse (f, f->sref, f->loc);
3191
3192 if (sRef_possiblyNull (f->sref))
3193 {
3194 if (!usymtab_isGuarded (f->sref))
3195 {
3196 if (optgenerror (FLG_NULLDEREF,
3197 message ("Function call using %s pointer %q",
3198 sRef_nullMessage (f->sref),
3199 sRef_unparse (f->sref)),
3200 f->loc))
3201 {
3202 sRef_showNullInfo (f->sref);
3203 sRef_setNullError (f->sref);
3204 }
3205 }
3206 }
3207 }
3208
3209 setCodePoint ();
3210
3211 if (ctype_isRealFunction (t))
3212 {
3213 exprNode ret = functionCallSafe (f, t, args);
3214 setCodePoint ();
3215 return ret;
3216 }
3217 else if (ctype_isUnknown (t))
3218 {
3219 exprNode ret = exprNode_createPartialCopy (f);
3220 cstring tstring;
3221
3222 setCodePoint ();
3223
3224 ret->typ = t;
3225 exprNodeList_elements (args, current)
3226 {
3227 if (exprNode_isDefined (current))
3228 {
3229 exprNode_checkUse (ret, current->sref, ret->loc);
3230
3231 /*
3232 ** also, anything derivable from current->sref may be used
3233 */
3234
3235 exprNode_addUse (ret, sRef_makeDerived (current->sref));
3236 exprNode_mergeUSs (ret, current);
3237 }
3238 } end_exprNodeList_elements;
3239
3240 ret->edata = exprData_makeCall (f, args);
3241 ret->kind = XPR_CALL;
3242
3243 tstring = cstring_copy (exprNode_unparse (f));
3244
3245 cstring_markOwned (tstring);
3246 exprNode_checkSetAny (ret, tstring);
3247
3248 return (ret);
3249 }
3250 else
3251 {
3252 voptgenerror (FLG_TYPE,
3253 message ("Call to non-function (type %t): %s", t,
3254 exprNode_unparse (f)),
3255 f->loc);
3256 exprNode_free (f);
3257 exprNodeList_free (args);
3258
3259 return (exprNode_makeError ());
3260 }
3261}
3262
3263exprNode
3264exprNode_fieldAccess (/*@only@*/ exprNode s, /*@only@*/ cstring f)
3265{
3266 exprNode ret = exprNode_createPartialCopy (s);
3267
3268 ret->kind = XPR_FACCESS;
3269
3270 if (exprNode_isError (s))
3271 {
3272 ret->edata = exprData_makeField (s, f);
3273 return ret;
3274 }
3275 else
3276 {
3277 ctype t = exprNode_getType (s);
3278 ctype tr = ctype_realType (t);
3279
3280 checkMacroParen (s);
3281
3282 ret->edata = exprData_makeField (s, f);
3283
3284 if (ctype_isStructorUnion (tr))
3285 {
3286 uentry tf = uentryList_lookupField (ctype_getFields (tr), f);
3287
3288 if (uentry_isUndefined (tf))
3289 {
3290 voptgenerror (FLG_TYPE,
3291 message ("Access non-existent field %s of %t: %s", f, t,
3292 exprNode_unparse (ret)),
3293 s->loc);
3294
3295 return (ret);
3296 }
3297 else
3298 {
3299 uentry_setUsed (tf, exprNode_loc (ret));
3300
3301 ret->typ = uentry_getType (tf);
3302 checkSafeUse (ret, s->sref);
3303
3304 ret->sref = sRef_makeField (s->sref, uentry_rawName (tf));
3305 return (ret);
3306 }
3307 }
3308 else /* isStructorUnion */
3309 {
3310 if (ctype_isRealAbstract (tr))
3311 {
3312 voptgenerror
3313 (FLG_ABSTRACT,
3314 message ("Access field of abstract type (%t): %s.%s",
3315 t, exprNode_unparse (s), f),
3316 s->loc);
3317 ret->typ = ctype_unknown;
3318 }
3319 else
3320 {
3321 if (ctype_isKnown (tr))
3322 {
3323 voptgenerror
3324 (FLG_TYPE,
3325 message
3326 ("Access field of non-struct or union (%t): %s.%s",
3327 t, exprNode_unparse (s), f),
3328 s->loc);
3329
3330 ret->typ = ctype_unknown;
3331 }
3332 else
3333 {
3334 cstring sn = cstring_copy (f);
3335
3336 checkSafeUse (ret, s->sref);
3337 cstring_markOwned (sn);
3338 ret->sref = sRef_makeField (s->sref, sn);
3339
3340 return (ret);
3341 }
3342 }
3343 return (ret);
3344 }
3345 }
3346 BADEXIT;
3347}
3348
3349exprNode
3350exprNode_addParens (/*@only@*/ lltok lpar, /*@only@*/ exprNode e)
3351{
3352 exprNode ret = exprNode_createPartialCopy (e);
3353
3354 ret->loc = fileloc_update (ret->loc, lltok_getLoc (lpar));
3355 ret->kind = XPR_PARENS;
3356 ret->edata = exprData_makeUop (e, lpar);
3357
3358 if (!exprNode_isError (e))
3359 {
3360 ret->exitCode = e->exitCode;
3361 ret->canBreak = e->canBreak;
3362 ret->mustBreak = e->mustBreak;
3363 ret->isJumpPoint = e->isJumpPoint;
3364 ret->sref = e->sref;
3365 }
3366
3367 return ret;
3368}
3369
3370exprNode
3371exprNode_arrowAccess (/*@only@*/ exprNode s, /*@only@*/ cstring f)
3372{
3373 exprNode ret = exprNode_createPartialCopy (s);
3374
3375 ret->edata = exprData_makeField (s, f);
3376 ret->kind = XPR_ARROW;
3377
3378 if (exprNode_isError (s))
3379 {
3380 return (ret);
3381 }
3382 else
3383 {
3384 ctype t = exprNode_getType (s);
3385 ctype tr = ctype_realType (t);
3386
3387 checkMacroParen (s);
3388
3389 (void) ctype_fixArrayPtr (tr); /* REWRITE THIS */
3390
3391 if (ctype_isRealPointer (tr))
3392 {
3393 ctype b = ctype_realType (ctype_baseArrayPtr (tr));
3394
3395 if (ctype_isStructorUnion (b))
3396 {
3397 uentry fentry = uentryList_lookupField (ctype_getFields (b), f);
3398
3399 if (sRef_isKnown (s->sref) && sRef_possiblyNull (s->sref))
3400 {
3401 if (!usymtab_isGuarded (s->sref) && !context_inProtectVars ())
3402 {
3403 if (optgenerror
3404 (FLG_NULLDEREF,
3405 message ("Arrow access from %s pointer%q: %s",
3406 sRef_nullMessage (s->sref),
3407 sRef_unparsePreOpt (s->sref),
3408 exprNode_unparse (ret)),
3409 s->loc))
3410 {
3411 sRef_showNullInfo (s->sref);
3412 sRef_setNullError (s->sref);
3413 }
3414 }
3415 }
3416
3417 if (uentry_isUndefined (fentry))
3418 {
3419 voptgenerror
3420 (FLG_TYPE,
3421 message ("Access non-existent field %s of %t: %s",
3422 f, t, exprNode_unparse (ret)),
3423 s->loc);
3424 ret->typ = ctype_unknown;
3425
3426 return (ret);
3427 }
3428 else
3429 {
3430 /*
3431 ** was safeUse: shouldn't be safe!
3432 **
3433 ** to do rec->field
3434 ** rec must be defined,
3435 ** *rec must be allocated
3436 ** rec->field need only be defined it if is an rvalue
3437 */
3438
3439 uentry_setUsed (fentry, exprNode_loc (ret));
3440 ret->typ = uentry_getType (fentry);
3441
3442 exprNode_checkUse (ret, s->sref, s->loc);
3443
3444 /* exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc); */
3445 ret->sref = sRef_makeArrow (s->sref, uentry_rawName (fentry));
3446 return (ret);
3447 }
3448 }
3449 else /* Pointer to something that is not a struct or union*/
3450 {
3451 if (ctype_isRealAbstract (tr))
3452 {
3453 ctype xrt = ctype_forceRealType (tr);
3454
3455 voptgenerror
3456 (FLG_ABSTRACT,
3457 message ("Arrow access field of abstract type (%t): %s->%s",
3458 t, exprNode_unparse (s), f),
3459 s->loc);
3460
3461 /*
3462 ** Set the state correctly, as if the abstraction is broken.
3463 */
3464
3465 if (ctype_isRealPointer (xrt) &&
3466 (b = ctype_realType (ctype_baseArrayPtr (xrt)),
3467 ctype_isStructorUnion (b)))
3468 {
3469 uentry fentry = uentryList_lookupField (ctype_getFields (b), f);
3470 ret->typ = uentry_getType (fentry);
3471 ret->sref = sRef_makeArrow (s->sref, uentry_rawName (fentry));
3472 }
3473 else
3474 {
3475 ret->typ = ctype_unknown;
3476 ret->sref = sRef_undefined;
3477 }
3478 }
3479 else /* not a struct, union or abstract */
3480 {
3481 if (ctype_isUnknown (tr)) {
3482 cstring sn = cstring_copy (f);
3483
3484 DPRINTF (("Here: %s", exprNode_unparse (s)));
3485
3486 exprNode_checkUse (ret, s->sref, s->loc);
3487 exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc);
3488
3489 cstring_markOwned (sn);
3490 ret->sref = sRef_makeArrow (s->sref, sn);
3491
3492 ret->kind = XPR_ARROW;
3493 return (ret);
3494 } else {
3495 voptgenerror
3496 (FLG_TYPE,
3497 message ("Arrow access field of non-struct or union "
3498 "pointer (%t): %s->%s",
3499 t, exprNode_unparse (s), f),
3500 s->loc);
3501
3502 ret->typ = ctype_unknown;
3503 ret->sref = sRef_undefined;
3504 }
3505 }
3506 }
3507 }
3508 else /* its not a pointer */
3509 {
3510 if (!ctype_isUnknown (tr))
3511 {
3512 voptgenerror
3513 (FLG_TYPE,
3514 message ("Arrow access of non-pointer (%t): %s->%s",
3515 t, exprNode_unparse (s), f),
3516 s->loc);
3517
3518 ret->typ = ctype_unknown;
3519 ret->sref = sRef_undefined;
3520 }
3521 else
3522 {
3523 cstring sn = cstring_copy (f);
3524
3525 DPRINTF (("Here: %s", exprNode_unparse (s)));
3526
3527 exprNode_checkUse (ret, s->sref, s->loc);
3528 exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc);
3529
3530 cstring_markOwned (sn);
3531 ret->sref = sRef_makeArrow (s->sref, sn);
3532
3533 ret->kind = XPR_ARROW;
3534 return (ret);
3535 }
3536 }
3537
3538 return (ret);
3539 }
3540 BADEXIT;
3541}
3542
3543/*
3544** only postOp's in C: i++ and i--
3545*/
3546
3547exprNode
3548exprNode_postOp (/*@only@*/ exprNode e, /*@only@*/ lltok op)
3549{
3550 /* check modification also */
3551 /* cstring opname = lltok_unparse (op);*/
3552 ctype t;
3553 exprNode ret = exprNode_createPartialCopy (e);
3554
3555 ret->loc = fileloc_update (ret->loc, lltok_getLoc (op));
3556 ret->kind = XPR_POSTOP;
3557 ret->edata = exprData_makeUop (e, op);
3558
3559 if (!exprNode_isDefined (e))
3560 {
3561 return ret;
3562 }
3563
3564 checkMacroParen (e);
3565
3566 exprNode_checkUse (ret, e->sref, e->loc);
3567 exprNode_checkSet (ret, e->sref);
3568
3569 t = exprNode_getType (e);
3570
3571 if (sRef_isUnsafe (e->sref))
3572 {
3573 voptgenerror (FLG_MACROPARAMS,
3574 message ("Operand of %s is macro parameter (non-functional): %s%s",
3575 lltok_unparse (op), exprNode_unparse (e), lltok_unparse (op)),
3576 e->loc);
3577 sRef_makeSafe (e->sref);
3578 sRef_makeSafe (ret->sref);
3579 }
3580
3581 if (ctype_isForceRealNumeric (&t) || ctype_isRealAP (t))
3582 {
3583 ret->typ = e->typ;
3584 }
3585 else
3586 {
3587 if (ctype_isRealAbstract (t))
3588 {
3589 voptgenerror
3590 (FLG_ABSTRACT,
3591 message ("Operand of %s is abstract type (%t): %s",
3592 lltok_unparse (op), t, exprNode_unparse (e)),
3593 e->loc);
3594 }
3595 else
3596 {
3597 voptgenerror
3598 (FLG_TYPE,
3599 message ("Operand of %s is non-numeric (%t): %s",
3600 lltok_unparse (op), t, exprNode_unparse (e)),
3601 e->loc);
3602 }
3603 ret->typ = ctype_unknown;
3604 }
3605
3606 /* if (ctype_isZero (t)) e->typ = ctype_int; */
3607
3608 exprNode_checkModify (e, ret);
3609
3610 /* added 7/11/2000 D.L */
3611
dc92450f 3612 // updateEnvironmentForPostOp (e);
616915dd 3613
3614 /* start modifications */
3615 /* added by Seejo on 4/16/2000 */
3616
3617 /* Arithmetic operations on pointers wil modify the size/len/null terminated
3618 status */
3619 if ((sRef_isPossiblyNullTerminated (e->sref)) || (sRef_isNullTerminated(e->sref))) {
3620
3621 ret->sref = sRef_copy (e->sref);
3622
3623 /* Operator : ++ */
3624 if (lltok_getTok (op) == INC_OP) {
3625 if (sRef_getSize(e->sref) > 0) {
3626
3627 sRef_setSize (ret->sref, sRef_getSize(e->sref) - 1);
3628
3629 if (sRef_getLen(e->sref) == 1) { /* i.e. the first character is \0 */
3630 /* Assumption: there is only 1 \0 in the buffer */
3631 /* This will not be correct if there are 2 \0's in the buffer */
3632 sRef_setNotNullTerminatedState(ret->sref);
3633 sRef_resetLen(ret->sref);
3634 } else {
3635 sRef_setNullTerminatedState(ret->sref);
3636 sRef_setLen (ret->sref, sRef_getLen(e->sref) - 1);
3637 }
3638 if (sRef_isNullTerminated (ret->sref))
3639 printf ("ret->sref is Null Terminated\n");
3640 else if (sRef_isPossiblyNullTerminated (ret->sref))
3641 printf ("ret->sref is Possibly Null Terminated\n");
3642 else if (sRef_isNotNullTerminated (ret->sref))
3643 printf ("ret->sref is Not Null Terminated\n");
3644 }
3645 }
3646
3647 /* Operator : -- */
3648 if (lltok_getTok (op) == DEC_OP) {
3649 if (sRef_getSize(e->sref) >= 0) {
3650 sRef_setSize (ret->sref, sRef_getSize(e->sref) + 1);
3651 sRef_setLen (ret->sref, sRef_getLen(e->sref) + 1);
3652 }
3653 }
3654 }
3655
3656 /* end modifications */
3657
3658 return ret;
3659}
3660
3661exprNode
3662exprNode_preOp (/*@only@*/ exprNode e, /*@only@*/ lltok op)
3663{
3664 bool checkMod = FALSE;
3665 ctype te, tr;
3666 int opid = lltok_getTok (op);
3667 exprNode ret = exprNode_createSemiCopy (e);
3668
3669 exprNode_copySets (ret, e);
3670
3671 multiVal_free (ret->val);
3672 ret->val = multiVal_undefined;
3673 ret->loc = fileloc_update (ret->loc, lltok_getLoc (op));
3674 ret->kind = XPR_PREOP;
3675 ret->edata = exprData_makeUop (e, op);
3676
3677 if (exprNode_isError (e))
3678 {
3679 return ret;
3680 }
3681
3682 checkMacroParen (e);
3683
3684 te = exprNode_getType (e);
3685 tr = ctype_realType (te);
3686
3687 if (opid != TAMPERSAND)
3688 {
3689 exprNode_checkUse (ret, e->sref, e->loc);
3690
3691 if (ctype_isRealAbstract (tr)
3692 && (!(ctype_isRealBool (te) && (opid == TEXCL))))
3693 {
3694 if (optgenerror (FLG_ABSTRACT,
3695 message ("Operand of %s is abstract type (%t): %s",
3696 lltok_unparse (op), tr,
3697 exprNode_unparse (ret)),
3698 e->loc))
3699 {
3700 tr = te = ctype_unknown;
3701 ret->typ = ctype_unknown;
3702 sRef_setNullError (e->sref);
3703 }
3704 }
3705 }
3706
3707 switch (opid)
3708 {
3709 case INC_OP:
3710 case DEC_OP: /* should also check modification! */
3711
3712 if (sRef_isMacroParamRef (e->sref))
3713 {
3714 voptgenerror
3715 (FLG_MACROPARAMS,
3716 message ("Operand of %s is macro parameter (non-functional): %s",
3717 lltok_unparse (op), exprNode_unparse (ret)),
3718 e->loc);
3719 }
3720 else
3721 {
3722 exprNode_checkSet (ret, e->sref);
3723 }
3724
3725 if (ctype_isForceRealNumeric (&tr) || ctype_isRealAP (tr))
3726 {
3727 }
3728 else
3729 {
3730 if (context_msgStrictOps ())
3731 {
3732 voptgenerror
3733 (FLG_STRICTOPS,
3734 message ("Operand of %s is non-numeric (%t): %s",
3735 lltok_unparse (op), te, exprNode_unparse (ret)),
3736 e->loc);
3737 }
3738 ret->typ = ctype_int;
3739 }
3740
3741 /* start modifications */
3742 /* added by Seejo on 4/16/2000 */
3743
3744 /* Arithmetic operations on pointers wil modify the size/len/null terminated
3745 status */
3746 if ((sRef_isPossiblyNullTerminated (e->sref)) || (sRef_isNullTerminated(e->sref))) {
3747
3748 ret->sref = sRef_copy (e->sref);
3749
3750 /* Operator : ++ */
3751 if (lltok_getTok (op) == INC_OP) {
3752 if (sRef_getSize(e->sref) > 0) {
3753
3754 sRef_setSize (ret->sref, sRef_getSize(e->sref) - 1);
3755
3756 if (sRef_getLen(e->sref) == 1) { /* i.e. the first character is \0 */
3757 /* Assumption: there is only 1 \0 in the buffer */
3758 /* This will not be correct if there are 2 \0's in the buffer */
3759 sRef_setNotNullTerminatedState(ret->sref);
3760 sRef_resetLen (ret->sref);
3761 } else {
3762 sRef_setNullTerminatedState(ret->sref);
3763 sRef_setLen (ret->sref, sRef_getLen(e->sref) - 1);
3764 }
3765 }
3766 }
3767
3768 /* Operator : -- */
3769 if (lltok_getTok (op) == DEC_OP) {
3770 if (sRef_getSize(e->sref) >= 0) {
3771 sRef_setSize (ret->sref, sRef_getSize(e->sref) + 1);
3772 sRef_setLen (ret->sref, sRef_getLen(e->sref) + 1);
3773 }
3774 }
3775 }
3776
3777 /* end modifications */
3778
3779 checkMod = TRUE;
3780 break;
3781
3782 case TMINUS:
3783 case TPLUS:
3784 if (ctype_isForceRealNumeric (&tr))
3785 {
3786 if (opid == TMINUS)
3787 {
3788 ret->val = multiVal_invert (exprNode_getValue (e));
3789 }
3790 else
3791 {
3792 ret->val = multiVal_copy (exprNode_getValue (e));
3793 }
3794 }
3795 else
3796 {
3797 if (context_msgStrictOps ())
3798 {
3799 voptgenerror
3800 (FLG_STRICTOPS,
3801 message ("Operand of %s is non-numeric (%t): %s",
3802 lltok_unparse (op), te, exprNode_unparse (ret)),
3803 e->loc);
3804 }
3805
3806 ret->typ = ctype_int;
3807 }
3808 break;
3809
3810 case TEXCL: /* maybe this should be restricted */
3811 guardSet_flip (ret->guards);
3812
3813 if (ctype_isRealBool (te))
3814 {
3815 ;
3816 }
3817 else
3818 {
3819 if (ctype_isRealPointer (tr))
3820 {
3821 if (sRef_isKnown (e->sref))
3822 {
3823 ret->guards = guardSet_addFalseGuard (ret->guards, e->sref);
3824 }
3825
3826 voptgenerror2n
3827 (FLG_BOOLOPS, FLG_PTRNEGATE,
3828 message ("Operand of %s is non-boolean (%t): %s",
3829 lltok_unparse (op), te, exprNode_unparse (ret)),
3830 e->loc);
3831 }
3832 else
3833 {
3834 voptgenerror
3835 (FLG_BOOLOPS,
3836 message ("Operand of %s is non-boolean (%t): %s",
3837 lltok_unparse (op), te, exprNode_unparse (ret)),
3838 e->loc);
3839 }
3840
3841 ret->typ = ctype_bool;
3842 }
3843 break;
3844
3845 case TTILDE:
3846 if (ctype_isForceRealInt (&tr))
3847 {
3848 }
3849 else
3850 {
3851 if (context_msgStrictOps ())
3852 {
3853 voptgenerror
3854 (FLG_STRICTOPS,
3855 message ("Operand of %s is non-integer (%t): %s",
3856 lltok_unparse (op), te, exprNode_unparse (ret)),
3857 e->loc);
3858 }
3859
3860 if (ctype_isInt (e->typ))
3861 {
3862 ret->typ = e->typ;
3863 }
3864 else
3865 {
3866 ret->typ = ctype_int;
3867 }
3868 }
3869 break;
3870
3871 case TAMPERSAND:
3872 ret->typ = ctype_makePointer (e->typ);
3873
3874 if (sRef_isKnown (e->sref))
3875 {
3876 ret->sref = sRef_makeAddress (e->sref);
3877 }
3878
3879 break;
3880
3881 case TMULT:
3882
3883 if (ctype_isAP (tr))
3884 {
3885 ret->typ = ctype_baseArrayPtr (e->typ);
3886 }
3887 else
3888 {
3889 if (ctype_isKnown (te))
3890 {
3891 if (ctype_isFunction (te))
3892 {
3893 ret->typ = e->typ;
3894
3895 voptgenerror
3896 (FLG_FCNDEREF,
3897 message ("Dereference of function type (%t): %s",
3898 te, exprNode_unparse (ret)),
3899 e->loc);
3900 }
3901 else
3902 {
3903 voptgenerror (FLG_TYPE,
3904 message ("Dereference of non-pointer (%t): %s",
3905 te, exprNode_unparse (ret)),
3906 e->loc);
3907 ret->typ = ctype_unknown;
3908 }
3909 }
3910 else
3911 {
3912 ret->typ = ctype_unknown;
3913 }
3914
3915 }
3916
3917 if (sRef_isKnown (e->sref))
3918 {
3919 if (sRef_possiblyNull (e->sref))
3920 {
3921 if (!usymtab_isGuarded (e->sref) && !context_inProtectVars ())
3922 {
3923 if (optgenerror
3924 (FLG_NULLDEREF,
3925 message ("Dereference of %s pointer %q: %s",
3926 sRef_nullMessage (e->sref),
3927 sRef_unparse (e->sref),
3928 exprNode_unparse (ret)),
3929 e->loc))
3930 {
3931 sRef_showNullInfo (e->sref);
3932 sRef_setNotNull (e->sref, e->loc); /* suppress future messages */
3933 }
3934 }
3935 }
3936
3937 ret->sref = sRef_makePointer (e->sref);
3938 }
3939 break;
3940
3941 default:
3942 llbug (message ("exprNode_preOp: unhandled op: %s", lltok_unparse (op)));
3943 }
3944
3945 if (checkMod)
3946 {
3947 exprNode_checkModify (e, ret);
3948 }
3949
3950 return ret;
3951}
3952
3953/*
3954** any reason to disallow sizeof (abstract type) ?
3955*/
3956
3957/*
3958** used by both sizeof
3959*/
3960
3961static
3962ctype sizeof_resultType (void)
3963{
3964 static ctype sizet = ctype_unknown;
3965
3966 if (ctype_isUnknown (sizet))
3967 {
3968 if (usymtab_existsType (cstring_makeLiteralTemp ("size_t")))
3969 {
3970 sizet = uentry_getAbstractType (usymtab_lookup (cstring_makeLiteralTemp ("size_t")));
3971 }
3972 else
3973 {
3974 sizet = ctype_ulint;
3975 }
3976 }
3977 return sizet;
3978}
3979
3980exprNode
3981exprNode_sizeofType (/*@only@*/ qtype qt)
3982{
3983 exprNode ret = exprNode_create (sizeof_resultType ());
3984 ctype ct = qtype_getType (qt);
3985
3986 ret->kind = XPR_SIZEOFT;
3987 ret->edata = exprData_makeSizeofType (qt);
3988
3989 voptgenerror (FLG_SIZEOFTYPE,
3990 message ("Parameter to sizeof is type %s: %s",
3991 ctype_unparse (ct),
3992 exprNode_unparse (ret)),
3993 ret->loc);
3994
3995 return (ret);
3996}
3997
3998exprNode
3999exprNode_alignofType (/*@only@*/ qtype qt)
4000{
4001 exprNode ret = exprNode_create (sizeof_resultType ());
4002 ctype ct = qtype_getType (qt);
4003
4004 ret->kind = XPR_ALIGNOFT;
4005 ret->edata = exprData_makeSizeofType (qt);
4006
4007 voptgenerror (FLG_SIZEOFTYPE,
4008 message ("Parameter to alignof is type %s: %s",
4009 ctype_unparse (ct),
4010 exprNode_unparse (ret)),
4011 ret->loc);
4012
4013 return (ret);
4014}
4015
4016exprNode exprNode_offsetof (qtype qt, cstringList s)
4017{
4018 exprNode ret = exprNode_create (sizeof_resultType ());
4019 ctype ct = qtype_getType (qt);
4020
4021 ret->kind = XPR_OFFSETOF;
4022 ret->edata = exprData_makeOffsetof (qt, s);
4023
4024 if (!ctype_isRealSU (ct))
4025 {
4026 voptgenerror (FLG_TYPE,
4027 message ("First parameter to offsetof is not a "
4028 "struct or union type (type %s): %s",
4029 ctype_unparse (ct),
4030 exprNode_unparse (ret)),
4031 ret->loc);
4032 }
4033 else
4034 {
4035 ctype lt = ct;
4036
4037 cstringList_elements (s, el) {
4038 uentryList fields;
4039 uentry fld;
4040
4041 if (ctype_isUndefined (lt))
4042 {
4043 break;
4044 }
4045 else if (!ctype_isRealSU (lt))
4046 {
4047 voptgenerror (FLG_TYPE,
4048 message ("Inner offsetof type is not a "
4049 "struct or union type (type %s before field %s): %s",
4050 ctype_unparse (lt), el,
4051 exprNode_unparse (ret)),
4052 ret->loc);
4053 break;
4054 }
4055 else
4056 {
4057 fields = ctype_getFields (ctype_realType (lt));
4058 fld = uentryList_lookupField (fields, el);
4059 DPRINTF (("Try: %s / %s", ctype_unparse (lt), el));
4060
4061 if (uentry_isUndefined (fld))
4062 {
4063 if (ctype_equal (lt, ct)) {
4064 voptgenerror (FLG_TYPE,
4065 message ("Field %s in offsetof is not the "
4066 "name of a field of %s: %s",
4067 el,
4068 ctype_unparse (ct),
4069 exprNode_unparse (ret)),
4070 ret->loc);
4071 } else {
4072 voptgenerror (FLG_TYPE,
4073 message ("Deep field %s in offsetof is not the "
4074 "name of a field of %s: %s",
4075 el,
4076 ctype_unparse (lt),
4077 exprNode_unparse (ret)),
4078 ret->loc);
4079 }
4080 }
4081 else
4082 {
4083 lt = uentry_getType (fld);
4084 }
4085 }
4086 } end_cstringList_elements;
4087
4088 /* Should report error if its a bit field - behavior is undefined! */
4089 }
4090
4091 return (ret);
4092}
4093
4094/*@only@*/ exprNode
4095exprNode_sizeofExpr (/*@only@*/ exprNode e)
4096{
4097 exprNode ret;
4098
4099 if (exprNode_isUndefined (e))
4100 {
4101 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
4102 ret->edata = exprData_makeSingle (e);
4103 ret->typ = sizeof_resultType ();
4104 ret->kind = XPR_SIZEOF;
4105 }
4106 else
4107 {
4108 uentry u = exprNode_getUentry (e);
4109
4110 ret = exprNode_createPartialCopy (e);
4111 ret->edata = exprData_makeSingle (e);
4112
4113 ret->typ = sizeof_resultType ();
4114 ret->kind = XPR_SIZEOF;
4115
4116 if (uentry_isValid (u)
4117 && uentry_isRefParam (u)
4118 && ctype_isRealArray (uentry_getType (u)))
4119 {
4120 voptgenerror
4121 (FLG_SIZEOFFORMALARRAY,
4122 message ("Parameter to sizeof is an array-type function parameter: %s",
4123 exprNode_unparse (ret)),
4124 ret->loc);
4125 }
4126 }
4127
4128 /*
4129 ** sizeof (x) doesn't "really" use x
4130 */
4131
4132 return (ret);
4133}
4134
4135/*@only@*/ exprNode
4136exprNode_alignofExpr (/*@only@*/ exprNode e)
4137{
4138 exprNode ret;
4139
4140 if (exprNode_isUndefined (e))
4141 {
4142 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
4143 }
4144 else
4145 {
4146 ret = exprNode_createPartialCopy (e);
4147 }
4148
4149 ret->edata = exprData_makeSingle (e);
4150 ret->typ = sizeof_resultType ();
4151 ret->kind = XPR_ALIGNOF;
4152
4153 /*
4154 ** sizeof (x) doesn't "really" use x
4155 */
4156
4157 return (ret);
4158}
4159
4160/*@only@*/ exprNode
4161exprNode_cast (/*@only@*/ lltok tok, /*@only@*/ exprNode e, /*@only@*/ qtype q)
4162{
4163 ctype c;
4164 ctype t;
4165 exprNode ret;
4166
4167 if (exprNode_isError (e))
4168 {
4169 qtype_free (q);
4170 lltok_release (tok);
4171 return exprNode_undefined;
4172 }
4173
4174 checkMacroParen (e);
4175
4176 c = qtype_getType (q);
4177 t = exprNode_getType (e);
4178
4179 ret = exprNode_createPartialCopy (e);
4180
4181 ret->loc = fileloc_update (ret->loc, lltok_getLoc (tok));
4182 ret->typ = c;
4183 ret->kind = XPR_CAST;
4184 ret->edata = exprData_makeCast (tok, e, q);
4185
4186 if (ctype_isRealSU (ctype_getBaseType (sRef_getType (e->sref))))
4187 {
4188 /*
4189 ** This is a bit of a hack to avoid a problem
4190 ** when the code does,
4191 ** (some other struct) x
4192 ** ...
4193 ** x->field
4194 */
4195
4196 ret->sref = sRef_copy (e->sref);
4197 usymtab_addForceMustAlias (ret->sref, e->sref);
4198 sRef_setTypeFull (ret->sref, c);
4199 DPRINTF (("Cast: %s -> %s", sRef_unparseFull (e->sref),
4200 sRef_unparseFull (ret->sref)));
4201 }
4202 else
4203 {
4204 ret->sref = e->sref;
4205 sRef_setTypeFull (ret->sref, c);
4206 DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
4207 }
4208
4209 /*
4210 ** we allow
4211 ** abstract -> void
4212 ** 0 <-> abstract *
4213 ** void * <-> abstract * (if FLG_ABSTVOIDP)
4214 ** abstract * <-> void * (if FLG_ABSTVOIDP)
4215 */
4216
4217 if (ctype_isVoid (c)) /* cast to void is always okay --- discard value */
4218 {
4219 ;
4220 }
4221 else if (ctype_isRealAP (c)) /* casting to array or pointer */
4222 {
4223 ctype bc = ctype_getBaseType (c);
4224 ctype bt = ctype_getBaseType (t);
4225 ctype rt = ctype_realType (t);
4226
4227 if (ctype_isFunction (ctype_baseArrayPtr (ctype_realType (c)))
4228 && (ctype_isArrayPtr (rt)
4229 && !ctype_isFunction (ctype_realType (ctype_baseArrayPtr (rt)))))
4230 {
4231 voptgenerror
4232 (FLG_CASTFCNPTR,
4233 message ("Cast from function pointer type (%t) to "
4234 "non-function pointer (%t): %s",
4235 c, t, exprNode_unparse (ret)),
4236 e->loc);
4237 }
4238
4239 if (!ctype_isFunction (ctype_baseArrayPtr (c))
4240 && (ctype_isArrayPtr (rt)
4241 && ctype_isFunction (ctype_realType (ctype_baseArrayPtr (rt)))))
4242 {
4243 voptgenerror
4244 (FLG_CASTFCNPTR,
4245 message ("Cast from non-function pointer type (%t) to "
4246 "function pointer (%t): %s",
4247 c, t, exprNode_unparse (ret)),
4248 e->loc);
4249 }
4250
4251 if (exprNode_isZero (e) && context_getFlag (FLG_ZEROPTR) &&
4252 !(ctype_isRealAbstract (bc)
4253 && context_hasAccess (ctype_typeId (bc))))
4254 {
4255 ; /* okay to cast zero */
4256 }
4257 else
4258 {
4259 if (ctype_isRealAbstract (bc)
4260 && !context_hasAccess (ctype_typeId (bc)))
4261 {
4262 if (ctype_isVoidPointer (t) || ctype_isUnknown (t))
4263 {
4264 vnoptgenerror
4265 (FLG_ABSTVOIDP,
4266 message ("Cast to underlying abstract type %t: %s",
4267 c, exprNode_unparse (ret)),
4268 e->loc);
4269 }
4270 else
4271 {
4272 voptgenerror
4273 (FLG_ABSTRACT,
4274 message ("Cast to underlying abstract type %t: %s",
4275 c, exprNode_unparse (ret)),
4276 e->loc);
4277 }
4278 }
4279
4280 if (ctype_isRealAbstract (bt)
4281 && !context_hasAccess (ctype_typeId (bt)))
4282 {
4283 if (ctype_isUnknown (c) || ctype_isVoidPointer (c))
4284 {
4285 vnoptgenerror
4286 (FLG_ABSTVOIDP,
4287 message ("Cast from underlying abstract type %t: %s",
4288 t, exprNode_unparse (ret)),
4289 e->loc);
4290 }
4291 else
4292 {
4293 voptgenerror
4294 (FLG_ABSTRACT,
4295 message ("Cast from underlying abstract type %t: %s",
4296 t, exprNode_unparse (ret)),
4297 e->loc);
4298 }
4299 }
4300 }
4301 }
4302 else
4303 {
4304 ctype bt = ctype_realType (ctype_getBaseType (t));
4305 ctype bc = ctype_realType (ctype_getBaseType (c));
4306
4307 if (ctype_isAbstract (bt) && !context_hasAccess (ctype_typeId (bt)))
4308 {
4309 if (ctype_match (c, t))
4310 {
4311 if (ctype_equal (c, t))
4312 {
4313 voptgenerror
4314 (FLG_TYPE,
4315 message ("Redundant cast involving abstract type %t: %s",
4316 bt, exprNode_unparse (ret)),
4317 e->loc);
4318 }
4319 }
4320 else
4321 {
4322 voptgenerror
4323 (FLG_ABSTRACT,
4324 message ("Cast from abstract type %t: %s",
4325 bt, exprNode_unparse (ret)),
4326 e->loc);
4327 }
4328 }
4329
4330 if (ctype_isAbstract (bc)
4331 && !context_hasAccess (ctype_typeId (bc)))
4332 {
4333 if (ctype_match (c, t))
4334 {
4335 ;
4336 }
4337 else
4338 {
4339 voptgenerror
4340 (FLG_ABSTRACT,
4341 message ("Cast to abstract type %t: %s", bc,
4342 exprNode_unparse (ret)),
4343 e->loc);
4344 }
4345 }
4346 }
4347
4348 if (ctype_isAbstract (c))
4349 {
4350 if (sRef_isExposed (e->sref) || sRef_isOnly (e->sref))
4351 {
4352 /* okay, cast exposed to abstract */
4353 sRef_clearExKindComplete (ret->sref, fileloc_undefined);
4354 }
4355 else
4356 {
4357 if (ctype_isVisiblySharable (t)
4358 && sRef_isExternallyVisible (e->sref)
4359 && !(ctype_isAbstract (t)
4360 && context_hasAccess (ctype_typeId (t))))
4361 {
4362 voptgenerror
4363 (FLG_CASTEXPOSE,
4364 message ("Cast to abstract type from externally visible "
4365 "mutable storage exposes rep of %s: %s",
4366 ctype_unparse (c),
4367 exprNode_unparse (e)),
4368 e->loc);
4369 }
4370 }
4371 }
4372
4373 return (ret);
4374}
4375
4376static bool
4377evaluationOrderUndefined (lltok op)
4378{
4379 int opid = lltok_getTok (op);
4380
4381 return (opid != AND_OP && opid != OR_OP);
4382}
4383
4384static bool checkIntegral (/*@notnull@*/ exprNode e1,
4385 /*@notnull@*/ exprNode e2,
4386 /*@notnull@*/ exprNode ret,
4387 lltok op)
4388{
4389 bool error = FALSE;
4390
4391 ctype te1 = exprNode_getType (e1);
4392 ctype te2 = exprNode_getType (e2);
4393
4394 ctype tr1 = ctype_realishType (te1);
4395 ctype tr2 = ctype_realishType (te2);
4396
4397 if (ctype_isForceRealInt (&tr1) && ctype_isForceRealInt (&tr2))
4398 {
4399 ;
4400 }
4401 else
4402 {
4403 if (context_msgStrictOps ())
4404 {
4405 if (!ctype_isInt (tr1) && !ctype_isInt (tr2))
4406 {
4407 if (ctype_sameName (te1, te2))
4408 {
4409 error = optgenerror
4410 (FLG_STRICTOPS,
4411 message ("Operands of %s are non-integer (%t): %s",
4412 lltok_unparse (op), te1,
4413 exprNode_unparse (ret)),
4414 e1->loc);
4415 }
4416 else
4417 {
4418 error = optgenerror
4419 (FLG_STRICTOPS,
4420 message ("Operands of %s are non-integers (%t, %t): %s",
4421 lltok_unparse (op), te1, te2,
4422 exprNode_unparse (ret)),
4423 e1->loc);
4424 }
4425 }
4426 else if (!ctype_isInt (tr1))
4427 {
4428 error = optgenerror
4429 (FLG_STRICTOPS,
4430 message ("Left operand of %s is non-integer (%t): %s",
4431 lltok_unparse (op), te1, exprNode_unparse (ret)),
4432 e1->loc);
4433 }
4434 else
4435 /* !ctype_isInt (te2) */
4436 {
4437 error = optgenerror
4438 (FLG_STRICTOPS,
4439 message ("Right operand of %s is non-integer (%t): %s",
4440 lltok_unparse (op), te2, exprNode_unparse (ret)),
4441 e2->loc);
4442 }
4443 }
4444 }
4445
4446 return !error;
4447}
4448
4449/*
4450** returns exprNode representing e1 op e2
4451**
4452** uses msg if there are errors
4453** can be used for both assignment ops and regular ops
4454**
4455** modifies e1
4456*/
4457
4458static /*@only@*/ /*@notnull@*/ exprNode
4459exprNode_makeOp (/*@keep@*/ exprNode e1, /*@keep@*/ exprNode e2,
4460 /*@keep@*/ lltok op)
4461{
4462 ctype te1, te2, tr1, tr2, tret;
4463 int opid = lltok_getTok (op);
4464 bool hasError = FALSE;
4465 exprNode ret;
4466
4467 if (exprNode_isError (e1))
4468 {
4469 ret = exprNode_createPartialNVCopy (e2);
4470 }
4471 else
4472 {
4473 ret = exprNode_createPartialNVCopy (e1);
4474 }
4475
4476 ret->val = multiVal_undefined;
4477 ret->kind = XPR_OP;
4478 ret->edata = exprData_makeOp (e1, e2, op);
4479
4480 if (exprNode_isError (e1) || exprNode_isError (e2))
4481 {
4482 if (opid == TLT || opid == TGT || opid == LE_OP || opid == GE_OP
4483 || opid == EQ_OP || opid == NE_OP
4484 || opid == AND_OP || opid == OR_OP)
4485 {
4486 ret->typ = ctype_bool;
4487 }
4488
4489 if (exprNode_isDefined (e1))
4490 {
4491 exprNode_checkUse (ret, e1->sref, e1->loc);
4492 }
4493
4494 if (exprNode_isDefined (e2))
4495 {
4496 exprNode_mergeUSs (ret, e2);
4497 exprNode_checkUse (ret, e2->sref, e2->loc);
4498 }
4499
4500 return ret;
4501 }
4502
4503 tret = ctype_unknown;
4504 te1 = exprNode_getType (e1);
4505 DPRINTF (("te1 = %s / %s", exprNode_unparse (e1), ctype_unparse (te1)));
4506
4507 te2 = exprNode_getType (e2);
4508
4509 tr1 = ctype_realishType (te1);
4510 tr2 = ctype_realishType (te2);
4511
4512 if (opid == OR_OP)
4513 {
4514 ret->guards = guardSet_or (ret->guards, e2->guards);
4515 }
4516 else if (opid == AND_OP)
4517 {
4518 ret->guards = guardSet_and (ret->guards, e2->guards);
4519 }
4520 else
4521 {
4522 /* no guards */
4523 }
4524
4525 if (opid == EQ_OP || opid == NE_OP)
4526 {
4527 exprNode temp1 = e1, temp2 = e2;
4528
4529 /* could do NULL == x */
4530
4531 if (exprNode_isNullValue (e1) || exprNode_isUnknownConstant (e1))
4532 {
4533 temp1 = e2; temp2 = e1;
4534 }
4535
4536 if (exprNode_isNullValue (temp2) || exprNode_isUnknownConstant (temp2))
4537 {
4538 reflectNullTest (temp1, (opid == NE_OP));
4539 guardSet_free (ret->guards);
4540 ret->guards = guardSet_copy (temp1->guards);
4541 }
4542 }
4543
4544 if (opid == TLT || opid == TGT || opid == LE_OP || opid == GE_OP
4545 || opid == EQ_OP || opid == NE_OP || opid == AND_OP || opid == OR_OP)
4546 {
4547 tret = ctype_bool;
4548 }
4549
4550 if (anyAbstract (tr1, tr2) &&
4551 (!((ctype_isRealBool (te1) || ctype_isRealBool (te2)) &&
4552 (opid == AND_OP || opid == OR_OP
4553 || opid == EQ_OP || opid == NE_OP))))
4554 {
4555 abstractOpError (tr1, tr2, op, e1, e2, e1->loc, e2->loc);
4556 }
4557 else if (ctype_isUnknown (te1) || ctype_isUnknown (te2))
4558 {
4559 /* unknown types, no comparisons possible */
4560 }
4561 else
4562 {
4563 switch (opid)
4564 {
4565 case TMULT: /* multiplication and division: */
4566 case TDIV: /* */
4567 case MUL_ASSIGN: /* numeric, numeric -> numeric */
4568 case DIV_ASSIGN: /* */
4569
4570 tret = checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
4571 break;
4572
4573 case TPLUS: /* addition and subtraction: */
4574 case TMINUS: /* pointer, int -> pointer */
4575 case SUB_ASSIGN: /* int, pointer -> pointer */
4576 case ADD_ASSIGN: /* numeric, numeric -> numeric */
4577
4578 tr1 = ctype_fixArrayPtr (tr1);
4579
4580 if ((ctype_isRealPointer (tr1) && !exprNode_isNullValue (e1))
4581 && (!ctype_isRealPointer (tr2) && ctype_isRealInt (tr2)))
4582 {
4583 /* pointer + int */
4584
4585 if (context_msgPointerArith ())
4586 {
4587 voptgenerror
4588 (FLG_POINTERARITH,
4589 message ("Pointer arithmetic (%t, %t): %s",
4590 te1, te2, exprNode_unparse (ret)),
4591 e1->loc);
4592 }
4593
4594 if (sRef_possiblyNull (e1->sref)
4595 && !usymtab_isGuarded (e1->sref))
4596 {
4597 voptgenerror
4598 (FLG_NULLPOINTERARITH,
4599 message ("Pointer arithmetic involving possibly "
4600 "null pointer %s: %s",
4601 exprNode_unparse (e1),
4602 exprNode_unparse (ret)),
4603 e1->loc);
4604 }
4605
4606 ret->sref = sRef_copy (e1->sref);
4607
4608 /* start modifications */
4609 /* added by Seejo on 4/16/2000 */
4610
4611 /* Arithmetic operations on pointers wil modify the size/len/null terminated
4612 status */
4613 if ((sRef_isPossiblyNullTerminated (e1->sref)) || (sRef_isNullTerminated(e1->sref))) {
4614 //if (sRef_isKnown (e->sref)) {
4615 //ret->sref = sRef_makeAddress (e->sref);
4616 //}
4617
4618 int val;
4619 /*drl 1-4-2001
4620 added ugly fixed to stop
4621 program from crashing on point + int +int
4622 one day I'll fix this or ask Seejo wtf the codes supposed to do. */
4623
4624 if (!multiVal_isInt (e2->val) )
4625 break;
4626 /*end drl*/
4627
4628 val = (int) multiVal_forceInt (e2->val);
4629
4630 /* Operator : + or += */
4631 if ((lltok_getTok (op) == TPLUS) || (lltok_getTok(op) == ADD_ASSIGN)) {
4632 if (sRef_getSize(e1->sref) >= val) {/* Incrementing the pointer by
4633 val should not result in a
4634 size < 0 (size = 0 is ok !) */
4635
4636 sRef_setSize (ret->sref, sRef_getSize(e1->sref) - val);
4637
4638 if (sRef_getLen(e1->sref) == val) { /* i.e. the character at posn val is \0 */
4639 sRef_setNotNullTerminatedState(ret->sref);
4640 sRef_resetLen (ret->sref);
4641 } else {
4642 sRef_setNullTerminatedState(ret->sref);
4643 sRef_setLen (ret->sref, sRef_getLen(e1->sref) - val);
4644 }
4645 }
4646 }
4647
4648 /* Operator : - or -= */
4649 if ((lltok_getTok (op) == TMINUS) || (lltok_getTok (op) == SUB_ASSIGN)) {
4650 if (sRef_getSize(e1->sref) >= 0) {
4651 sRef_setSize (ret->sref, sRef_getSize(e1->sref) + val);
4652 sRef_setLen (ret->sref, sRef_getLen(e1->sref) + val);
4653 }
4654 }
4655 }
4656
4657 /* end modifications */
4658
4659 sRef_setNullError (ret->sref);
4660
4661 /*
4662 ** Fixed for 2.2c: the alias state of ptr + int is dependent,
4663 ** since is points to storage that should not be deallocated
4664 ** through this pointer.
4665 */
4666
4667 if (sRef_isOnly (ret->sref)
4668 || sRef_isFresh (ret->sref))
4669 {
4670 sRef_setAliasKind (ret->sref, AK_DEPENDENT, exprNode_loc (ret));
4671 }
4672
4673 tret = e1->typ;
4674 }
4675 else if ((!ctype_isRealPointer(tr1) && ctype_isRealInt (tr1))
4676 && (ctype_isRealPointer (tr2) && !exprNode_isNullValue (e2)))
4677 {
4678 if (context_msgPointerArith ())
4679 {
4680 voptgenerror
4681 (FLG_POINTERARITH,
4682 message ("Pointer arithmetic (%t, %t): %s",
4683 te1, te2, exprNode_unparse (ret)),
4684 e1->loc);
4685 }
4686
4687 if (sRef_possiblyNull (e1->sref)
4688 && !usymtab_isGuarded (e1->sref))
4689 {
4690 voptgenerror
4691 (FLG_NULLPOINTERARITH,
4692 message ("Pointer arithmetic involving possibly "
4693 "null pointer %s: %s",
4694 exprNode_unparse (e2),
4695 exprNode_unparse (ret)),
4696 e2->loc);
4697 }
4698
4699 ret->sref = sRef_copy (e2->sref);
4700
4701 /* start modifications */
4702 /* added by Seejo on 4/16/2000 */
4703
4704 /* Arithmetic operations on pointers wil modify the size/len/null terminated
4705 status */
4706
4707 if ((sRef_isPossiblyNullTerminated (e2->sref)) || (sRef_isNullTerminated(e2->sref))) {
4708 //if (sRef_isKnown (e->sref)) {
4709 //ret->sref = sRef_makeAddress (e->sref);
4710 //}
4711
4712 int val = (int) multiVal_forceInt (e1->val);
4713
4714 /* Operator : + or += */
4715 if ((lltok_getTok (op) == TPLUS) || (lltok_getTok(op) == ADD_ASSIGN)) {
4716 if (sRef_getSize(e2->sref) >= val) {/* Incrementing the pointer by
4717 val should not result in a
4718 size < 0 (size = 0 is ok !) */
4719
4720 sRef_setSize (ret->sref, sRef_getSize(e2->sref) - val);
4721
4722 if (sRef_getLen(e2->sref) == val) { /* i.e. the character at posn val is \0 */
4723 sRef_setNotNullTerminatedState(ret->sref);
4724 sRef_resetLen (ret->sref);
4725 } else {
4726 sRef_setNullTerminatedState(ret->sref);
4727 sRef_setLen (ret->sref, sRef_getLen(e2->sref) - val);
4728 }
4729 }
4730 }
4731
4732 /* Operator : - or -= */
4733 if ((lltok_getTok (op) == TMINUS) || (lltok_getTok (op) == SUB_ASSIGN)) {
4734 if (sRef_getSize(e2->sref) >= 0) {
4735 sRef_setSize (ret->sref, sRef_getSize(e2->sref) + val);
4736 sRef_setLen (ret->sref, sRef_getLen(e2->sref) + val);
4737 }
4738 }
4739 }
4740
4741 /* end modifications */
4742
4743 sRef_setNullError (ret->sref);
4744
4745 /*
4746 ** Fixed for 2.2c: the alias state of ptr + int is dependent,
4747 ** since is points to storage that should not be deallocated
4748 ** through this pointer.
4749 */
4750
4751 if (sRef_isOnly (ret->sref)
4752 || sRef_isFresh (ret->sref)) {
4753 sRef_setAliasKind (ret->sref, AK_DEPENDENT, exprNode_loc (ret));
4754 }
4755
4756 tret = e2->typ;
4757 ret->sref = e2->sref;
4758 }
4759 else
4760 {
4761 tret = checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
4762 }
4763
4764 break;
4765
4766 case LEFT_ASSIGN: /* Shifts: should be unsigned values */
4767 case RIGHT_ASSIGN:
4768 case LEFT_OP:
4769 case RIGHT_OP:
4770 case TAMPERSAND: /* bitwise & */
4771 case AND_ASSIGN:
4772 case TCIRC: /* ^ (XOR) */
4773 case TBAR:
4774 case XOR_ASSIGN:
4775 case OR_ASSIGN:
4776 {
4777 bool reported = FALSE;
4778 flagcode code = FLG_BITWISEOPS;
4779
4780 if (opid == LEFT_OP || opid == LEFT_ASSIGN
4781 || opid == RIGHT_OP || opid == RIGHT_ASSIGN) {
4782 code = FLG_SHIFTSIGNED;
4783 }
4784
4785 if (!ctype_isUnsigned (tr1))
4786 {
4787 if (exprNode_isNonNegative (e1)) {
4788 ;
4789 } else {
4790 reported = optgenerror
4791 (code,
4792 message ("Left operand of %s is not unsigned value (%t): %s",
4793 lltok_unparse (op), te1,
4794 exprNode_unparse (ret)),
4795 e1->loc);
4796
4797 if (reported) {
4798 te1 = ctype_uint;
4799 }
4800 }
4801 }
4802 else
4803 {
4804 /* right need not be signed for shifts */
4805 if (code != FLG_SHIFTSIGNED
4806 && !ctype_isUnsigned (tr2))
4807 {
4808 if (!exprNode_isNonNegative (e2)) {
4809 reported = optgenerror
4810 (code,
4811 message ("Right operand of %s is not unsigned value (%t): %s",
4812 lltok_unparse (op), te2,
4813 exprNode_unparse (ret)),
4814 e2->loc);
4815 }
4816 }
4817 }
4818
4819 if (!reported)
4820 {
4821 if (!checkIntegral (e1, e2, ret, op)) {
4822 te1 = ctype_unknown;
4823 }
4824 }
4825
4826 DPRINTF (("Set: %s", ctype_unparse (te1)));
4827
4828 /*
4829 ** tret is the widest type of te1 and te2
4830 */
4831
4832 tret = ctype_widest (te1, te2);
4833 break;
4834 }
4835 case MOD_ASSIGN:
4836 case TPERCENT:
4837 if (checkIntegral (e1, e2, ret, op)) {
4838 tret = te1;
4839 } else {
4840 tret = ctype_unknown;
4841 }
4842 break;
4843 case EQ_OP:
4844 case NE_OP:
4845 case TLT: /* comparisons */
4846 case TGT: /* numeric, numeric -> bool */
4847 if ((ctype_isReal (tr1) && !ctype_isInt (tr1))
4848 || (ctype_isReal (tr2) && !ctype_isInt (tr2)))
4849 {
4850 ctype rtype = tr1;
4851 bool fepsilon = FALSE;
4852
4853 if (!ctype_isReal (rtype) || ctype_isInt (rtype))
4854 {
4855 rtype = tr2;
4856 }
4857
4858 if (opid == TLT || opid == TGT)
4859 {
4860 uentry ue1 = exprNode_getUentry (e1);
4861 uentry ue2 = exprNode_getUentry (e2);
4862
4863 /*
4864 ** FLT_EPSILON, etc. really is a variable, not
4865 ** a constant.
4866 */
4867
4868 if (uentry_isVariable (ue1))
4869 {
4870 cstring uname = uentry_rawName (ue1);
4871
4872 if (cstring_equalLit (uname, "FLT_EPSILON")
4873 || cstring_equalLit (uname, "DBL_EPSILON")
4874 || cstring_equalLit (uname, "LDBL_EPSILON"))
4875 {
4876 fepsilon = TRUE;
4877 }
4878 }
4879
4880 if (uentry_isVariable (ue2))
4881 {
4882 cstring uname = uentry_rawName (ue2);
4883
4884 if (cstring_equalLit (uname, "FLT_EPSILON")
4885 || cstring_equalLit (uname, "DBL_EPSILON")
4886 || cstring_equalLit (uname, "LDBL_EPSILON"))
4887 {
4888 fepsilon = TRUE;
4889 }
4890 }
4891 }
4892
4893 if (fepsilon)
4894 {
4895 ; /* Don't complain. */
4896 }
4897 else
4898 {
4899 voptgenerror
4900 (FLG_REALCOMPARE,
4901 message ("Dangerous comparison involving %s types: %s",
4902 ctype_unparse (rtype),
4903 exprNode_unparse (ret)),
4904 ret->loc);
4905 }
4906 }
4907 /*@fallthrough@*/
4908 case LE_OP:
4909 case GE_OP:
4910
4911 /*
4912 ** Types should match.
4913 */
4914
4915 if (!exprNode_matchTypes (e1, e2))
4916 {
4917 hasError = gentypeerror
4918 (te1, e1, te2, e2,
4919 message ("Operands of %s have incompatible types (%t, %t): %s",
4920 lltok_unparse (op), te1, te2, exprNode_unparse (ret)),
4921 e1->loc);
4922
4923 }
4924
4925 if (hasError
4926 || (ctype_isForceRealNumeric (&tr1)
4927 && ctype_isForceRealNumeric (&tr2)) ||
4928 (ctype_isRealPointer (tr1) && ctype_isRealPointer (tr2)))
4929 {
4930 ; /* okay */
4931 }
4932 else
4933 {
4934 if ((ctype_isRealNumeric (tr1) && ctype_isRealPointer (tr2)) ||
4935 (ctype_isRealPointer (tr1) && ctype_isRealNumeric (tr2)))
4936 {
4937 voptgenerror
4938 (FLG_PTRNUMCOMPARE,
4939 message ("Comparison of pointer and numeric (%t, %t): %s",
4940 te1, te2, exprNode_unparse (ret)),
4941 e1->loc);
4942 }
4943 else
4944 {
4945 (void) checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
4946 }
4947 tret = ctype_bool;
4948 }
4949
4950 /* EQ_OP should NOT be used with booleans (unless one is FALSE) */
4951
4952 if ((opid == EQ_OP || opid == NE_OP) &&
4953 ctype_isDirectBool (tr1) && ctype_isDirectBool (tr2))
4954 {
4955 /*
4956 ** is one a variable?
4957 */
4958
4959 if (uentry_isVariable (exprNode_getUentry (e1))
4960 || uentry_isVariable (exprNode_getUentry (e2)))
4961 {
4962 /*
4963 ** comparisons with FALSE are okay
4964 */
4965
4966 if (exprNode_isFalseConstant (e1)
4967 || exprNode_isFalseConstant (e2))
4968 {
4969 ;
4970 }
4971 else
4972 {
4973 voptgenerror
4974 (FLG_BOOLCOMPARE,
4975 message
4976 ("Use of %q with %s variables (risks inconsistency because "
4977 "of multiple true values): %s",
4978 cstring_makeLiteral ((opid == EQ_OP) ? "==" : "!="),
4979 context_printBoolName (), exprNode_unparse (ret)),
4980 e1->loc);
4981 }
4982 }
4983 }
4984 break;
4985
4986 case AND_OP: /* bool, bool -> bool */
4987 case OR_OP:
4988
4989 if (ctype_isForceRealBool (&tr1) && ctype_isForceRealBool (&tr2))
4990 {
4991 ;
4992 }
4993 else
4994 {
4995 if (context_maybeSet (FLG_BOOLOPS))
4996 {
4997 if (!ctype_isRealBool (te1) && !ctype_isRealBool (te2))
4998 {
4999 if (ctype_sameName (te1, te2))
5000 {
5001 voptgenerror
5002 (FLG_BOOLOPS,
5003 message ("Operands of %s are non-boolean (%t): %s",
5004 lltok_unparse (op), te1,
5005 exprNode_unparse (ret)),
5006 e1->loc);
5007 }
5008 else
5009 {
5010 voptgenerror
5011 (FLG_BOOLOPS,
5012 message
5013 ("Operands of %s are non-booleans (%t, %t): %s",
5014 lltok_unparse (op), te1, te2, exprNode_unparse (ret)),
5015 e1->loc);
5016 }
5017 }
5018 else if (!ctype_isRealBool (te1))
5019 {
5020 voptgenerror
5021 (FLG_BOOLOPS,
5022 message ("Left operand of %s is non-boolean (%t): %s",
5023 lltok_unparse (op), te1, exprNode_unparse (ret)),
5024 e1->loc);
5025 }
5026 else if (!ctype_isRealBool (te2))
5027 {
5028 voptgenerror
5029 (FLG_BOOLOPS,
5030 message ("Right operand of %s is non-boolean (%t): %s",
5031 lltok_unparse (op), te2, exprNode_unparse (ret)),
5032 e2->loc);
5033 }
5034 else
5035 {
5036 ;
5037 }
5038 }
5039 tret = ctype_bool;
5040 }
5041 break;
5042 default: {
5043 llfatalbug
5044 (cstring_makeLiteral
5045 ("There has been a problem in the parser. This is due to a bug "
5046 "in either lclint, bison or gcc version 2.95 optimizations, "
5047 "but it has not been confirmed. Please try rebuidling LCLint "
5048 "without the -O<n> option."));
5049 }
5050 }
5051 }
5052
5053 DPRINTF (("Return type: %s", ctype_unparse (tret)));
5054 ret->typ = tret;
5055
5056 exprNode_checkUse (ret, e1->sref, e1->loc);
5057 exprNode_mergeUSs (ret, e2);
5058 exprNode_checkUse (ret, e2->sref, e2->loc);
5059
5060 return ret;
5061}
5062
5063/*@only@*/ exprNode
5064exprNode_op (/*@only@*/ exprNode e1, /*@keep@*/ exprNode e2,
5065 /*@only@*/ lltok op)
5066{
5067 exprNode ret;
5068
5069 checkMacroParen (e1);
5070 checkMacroParen (e2);
5071
5072 if (evaluationOrderUndefined (op) && context_maybeSet (FLG_EVALORDER))
5073 {
5074 checkExpressionDefined (e1, e2, op);
5075 }
5076
5077 ret = exprNode_makeOp (e1, e2, op);
5078 return (ret);
5079}
5080
5081static
5082void exprNode_checkAssignMod (exprNode e1, exprNode ret)
5083{
5084 /*
5085 ** This is somewhat bogus!
5086 **
5087 ** Assigning to a nested observer in a non-observer datatype
5088 ** should not produce an error.
5089 */
5090
5091 sRef ref = exprNode_getSref (e1);
5092
5093 DPRINTF (("Check assign mod: %s",
5094 sRef_unparseFull (ref)));
5095
5096 if (sRef_isObserver (ref)
5097 || ((sRef_isFileStatic (ref) || sRef_isGlobal (ref))
5098 && ctype_isArray (ctype_realType (sRef_getType (ref)))))
5099 {
5100 sRef base = sRef_getBase (ref);
5101
5102 if (sRef_isValid (base) && sRef_isObserver (base))
5103 {
5104 exprNode_checkModify (e1, ret);
5105 }
5106 else
5107 {
5108 exprNode_checkModifyVal (e1, ret);
5109 }
5110 }
5111 else
5112 {
5113 exprNode_checkModify (e1, ret);
5114 }
5115}
5116
5117exprNode
5118exprNode_assign (/*@only@*/ exprNode e1,
5119 /*@only@*/ exprNode e2, /*@only@*/ lltok op)
5120{
5121 bool isalloc = FALSE;
5122 bool isjustalloc = FALSE;
5123 exprNode ret;
5124
5125 DPRINTF (("%s [%s] <- %s [%s]",
5126 exprNode_unparse (e1),
5127 ctype_unparse (e1->typ),
5128 exprNode_unparse (e2),
5129 ctype_unparse (e2->typ)));
5130
5131 if (lltok_getTok (op) != TASSIGN)
5132 {
5133 ret = exprNode_makeOp (e1, e2, op);
5134 }
5135 else
5136 {
5137 ret = exprNode_createPartialCopy (e1);
5138 ret->kind = XPR_ASSIGN;
5139 ret->edata = exprData_makeOp (e1, e2, op);
5140
5141 if (!exprNode_isError (e2))
5142 {
5143 ret->sets = sRefSet_union (ret->sets, e2->sets);
5144 ret->msets = sRefSet_union (ret->msets, e2->msets);
5145 ret->uses = sRefSet_union (ret->uses, e2->uses);
5146 }
5147 }
5148
5149 checkExpressionDefined (e1, e2, op);
5150
5151 if (exprNode_isError (e1))
5152 {
5153 if (!exprNode_isError (e2))
5154 {
5155 ret->loc = fileloc_update (ret->loc, e2->loc);
5156 }
5157 else
5158 {
5159 ret->loc = fileloc_update (ret->loc, g_currentloc);
5160 }
5161 }
5162
5163 if (!exprNode_isError (e2))
5164 {
5165 checkMacroParen (e2);
5166 }
5167
5168 if (exprNode_isDefined (e1))
5169 {
5170 if (sRef_isMacroParamRef (e1->sref))
5171 {
5172 if (context_inIterDef ())
5173 {
5174 uentry ue = sRef_getUentry (e1->sref);
5175
5176 if (uentry_isYield (ue))
5177 {
5178 ;
5179 }
5180 else
5181 {
5182 if (fileloc_isDefined (e1->loc))
5183 {
5184 voptgenerror
5185 (FLG_MACROPARAMS,
5186 message ("Assignment to non-yield iter parameter: %q",
5187 sRef_unparse (e1->sref)),
5188 e1->loc);
5189 }
5190 else
5191 {
5192 voptgenerror
5193 (FLG_MACROPARAMS,
5194 message ("Assignment to non-yield iter parameter: %q",
5195 sRef_unparse (e1->sref)),
5196 g_currentloc);
5197 }
5198 }
5199 }
5200 else
5201 {
5202 if (fileloc_isDefined (e1->loc))
5203 {
5204 voptgenerror
5205 (FLG_MACROASSIGN,
5206 message ("Assignment to macro parameter: %q",
5207 sRef_unparse (e1->sref)),
5208 e1->loc);
5209 }
5210 else
5211 {
5212 voptgenerror
5213 (FLG_MACROASSIGN,
5214 message ("Assignment to macro parameter: %q",
5215 sRef_unparse (e1->sref)),
5216 g_currentloc);
5217 }
5218 }
5219 }
5220 else
5221 {
5222 exprNode_checkAssignMod (e1, ret);
5223 }
5224
5225 if (exprNode_isDefined (e2))
5226 {
5227 if (lltok_getTok (op) == TASSIGN)
5228 {
5229 ctype te1 = exprNode_getType (e1);
5230 ctype te2 = exprNode_getType (e2);
5231
5232 if (!ctype_forceMatch (te1, te2))
5233 {
5234 if (exprNode_matchLiteral (te1, e2))
5235 {
5236 ;
5237 }
5238 else
5239 {
5240 (void) gentypeerror
5241 (te2, e2, te1, e1,
5242 message ("Assignment of %t to %t: %s %s %s",
5243 te2, te1, exprNode_unparse (e1),
5244 lltok_unparse (op),
5245 exprNode_unparse (e2)),
5246 e1->loc);
5247 }
5248 }
5249 }
5250
5251 exprNode_mergeUSs (ret, e2);
5252 exprNode_checkUse (ret, e2->sref, e2->loc);
5253
5254 doAssign (e1, e2, FALSE);
5255 ret->sref = e1->sref;
5256 }
5257 else
5258 {
5259 if (exprNode_isDefined (e2))
5260 {
5261 exprNode_mergeUSs (ret, e2);
5262 exprNode_checkUse (ret, e2->sref, e2->loc);
5263 }
5264 }
5265
5266 if (sRef_isPointer (e1->sref) && !sRef_isMacroParamRef (e1->sref))
5267 {
5268 exprNode_checkUse (ret, sRef_getBase (e1->sref), e1->loc);
5269 }
5270
5271 isjustalloc = sRef_isJustAllocated (e1->sref);
5272 isalloc = sRef_isAllocated (e1->sref);
5273
5274 if (sRef_isField (e1->sref))
5275 {
5276 sRef root = sRef_getRootBase (sRef_getBase (e1->sref));
5277
5278 if (!sRef_isAllocated (root) && !sRef_isMacroParamRef (root))
5279 {
5280 exprNode_checkUse (ret, root, e1->loc);
5281 }
5282
5283 }
5284
5285 /*
5286 ** be careful! this defines e1->sref.
5287 */
5288
5289 if (!sRef_isMacroParamRef (e1->sref))
5290 {
5291 exprNode_checkSet (ret, e1->sref);
5292 }
5293
5294 if (isjustalloc)
5295 {
5296 sRef_setAllocatedComplete (e1->sref, exprNode_isDefined (e2)
5297 ? e2->loc : e1->loc);
5298 }
5299 else
5300 {
5301 if (isalloc)
5302 {
5303 sRef_setAllocatedShallowComplete (e1->sref, exprNode_loc (e2));
5304 }
5305 }
5306 }
5307
5308 return ret;
5309}
5310
5311exprNode
5312exprNode_cond (/*@keep@*/ exprNode pred, /*@keep@*/ exprNode ifclause,
5313 /*@keep@*/ exprNode elseclause)
5314{
5315 exprNode ret;
5316
5317 if (!exprNode_isError (pred))
5318 {
5319 ret = exprNode_createPartialCopy (pred);
5320 checkMacroParen (pred);
5321 exprNode_checkPred (cstring_makeLiteralTemp ("conditional"), pred);
5322
5323 if (!exprNode_isError (ifclause))
5324 {
5325 checkMacroParen (ifclause); /* update macro counts! */
5326
5327 if (!exprNode_isError (elseclause))
5328 {
5329 checkMacroParen (elseclause);
5330
5331 if (!exprNode_matchTypes (ifclause, elseclause))
5332 {
5333 if (gentypeerror
5334 (exprNode_getType (ifclause),
5335 ifclause,
5336 exprNode_getType (elseclause),
5337 elseclause,
5338 message ("Conditional clauses are not of same type: "
5339 "%s (%t), %s (%t)",
5340 exprNode_unparse (ifclause),
5341 exprNode_getType (ifclause),
5342 exprNode_unparse (elseclause),
5343 exprNode_getType (elseclause)),
5344 ifclause->loc))
5345 {
5346 ret->sref = sRef_undefined;
5347 ret->typ = ctype_unknown;
5348 }
5349 }
5350 else
5351 {
5352 /* for now...should merge the states */
5353 ret->sref = ifclause->sref;
5354 ret->typ = ifclause->typ;
5355
5356 if (exprNode_isNullValue (ifclause))
5357 {
5358 ret->typ = elseclause->typ;
5359 }
5360 }
5361
5362 exprNode_checkUse (ret, pred->sref, pred->loc);
5363 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
5364 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
5365
5366 exprNode_mergeCondUSs (ret, ifclause, elseclause);
5367
5368 }
5369 else
5370 {
5371 ret->typ = ifclause->typ;
5372
5373 exprNode_checkUse (pred, pred->sref, pred->loc);
5374 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
5375
5376 exprNode_mergeCondUSs (ret, ifclause, exprNode_undefined);
5377 }
5378 }
5379 else
5380 {
5381 if (!exprNode_isError (elseclause))
5382 {
5383 ret->typ = elseclause->typ;
5384
5385 exprNode_checkUse (pred, pred->sref, pred->loc);
5386 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
5387
5388 exprNode_mergeCondUSs (ret, exprNode_undefined, elseclause);
5389 }
5390 }
5391 }
5392 else /* pred is error */
5393 {
5394 if (!exprNode_isError (ifclause))
5395 {
5396 ret = exprNode_createSemiCopy (ifclause);
5397
5398 checkMacroParen (ifclause); /* update macro counts! */
5399
5400 if (!exprNode_isError (elseclause))
5401 {
5402 checkMacroParen (elseclause);
5403
5404 ret->typ = ifclause->typ;
5405
5406 if (!ctype_forceMatch (ifclause->typ, elseclause->typ))
5407 {
5408 if (gentypeerror
5409 (exprNode_getType (ifclause),
5410 ifclause,
5411 exprNode_getType (elseclause),
5412 elseclause,
5413 message ("Conditional clauses are not of same type: "
5414 "%s (%t), %s (%t)",
5415 exprNode_unparse (ifclause),
5416 exprNode_getType (ifclause),
5417 exprNode_unparse (elseclause),
5418 exprNode_getType (elseclause)),
5419 ifclause->loc))
5420 {
5421 ret->typ = ctype_unknown;
5422 }
5423 }
5424
5425 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
5426 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
5427
5428 exprNode_mergeCondUSs (ret, ifclause, elseclause);
5429 }
5430 }
5431 else if (!exprNode_isError (elseclause)) /* pred, if errors */
5432 {
5433 ret = exprNode_createSemiCopy (ifclause);
5434
5435 ret->typ = elseclause->typ;
5436 checkMacroParen (elseclause);
5437
5438 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
5439 exprNode_mergeCondUSs (ret, exprNode_undefined, elseclause);
5440 }
5441 else /* all errors! */
5442 {
5443 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
5444 }
5445 }
5446
5447 ret->kind = XPR_COND;
5448 ret->edata = exprData_makeCond (pred, ifclause, elseclause);
5449
5450 if (exprNode_isDefined (ifclause) && exprNode_isDefined (elseclause))
5451 {
5452 exprNode_combineControl (ret, ifclause, elseclause);
5453 }
5454
5455 return (ret);
5456}
5457
5458exprNode
5459exprNode_vaArg (/*@only@*/ lltok tok, /*@only@*/ exprNode arg, /*@only@*/ qtype qt)
5460{
5461 ctype totype = qtype_getType (qt);
5462 exprNode ret =
5463 exprNode_createPartialLocCopy (arg, fileloc_copy (lltok_getLoc (tok)));
5464 ctype targ;
5465
5466 /*
5467 ** check use of va_arg : <valist>, type -> type
5468 */
5469
5470 if (exprNode_isError (arg))
5471 {
5472 }
5473 else
5474 {
5475 targ = exprNode_getType (arg);
5476
5477 /*
5478 ** arg should have be a pointer
5479 */
5480
5481 if (!ctype_isUA (targ) ||
5482 (!usymId_equal (ctype_typeId (targ),
5483 usymtab_getTypeId (cstring_makeLiteralTemp ("va_list")))))
5484 {
5485 voptgenerror
5486 (FLG_TYPE,
5487 message ("First argument to va_arg is not a va_list (type %t): %s",
5488 targ, exprNode_unparse (arg)),
5489 arg->loc);
5490 }
5491
5492 exprNode_checkSet (ret, arg->sref);
5493 }
5494
5495 /*
5496 ** return type is totype
5497 */
5498
5499 ret->typ = totype;
5500 ret->kind = XPR_VAARG;
5501 ret->edata = exprData_makeCast (tok, arg, qt);
5502
5503 return (ret);
5504}
5505
5506exprNode exprNode_labelMarker (/*@only@*/ cstring label)
5507{
5508 exprNode ret = exprNode_createPlain (ctype_undefined);
5509 ret->kind = XPR_LABEL;
5510 ret->edata = exprData_makeLiteral (label);
5511 ret->isJumpPoint = TRUE;
5512
5513 return (ret); /* for now, ignore label */
5514}
5515
5516exprNode exprNode_notReached (/*@returned@*/ exprNode stmt)
5517{
5518 if (exprNode_isDefined (stmt))
5519 {
5520 stmt->isJumpPoint = TRUE;
5521
5522 /* This prevent stray no return path errors, etc. */
5523 stmt->exitCode = XK_MUSTEXIT;
5524 }
5525
5526 return (stmt);
5527}
5528
5529bool exprNode_isDefaultMarker (exprNode e)
5530{
5531 if (exprNode_isDefined (e))
5532 {
5533 return (e->kind == XPR_DEFAULT || e->kind == XPR_FTDEFAULT);
5534 }
5535
5536 return FALSE;
5537}
5538
5539bool exprNode_isCaseMarker (exprNode e)
5540{
5541 if (exprNode_isDefined (e))
5542 {
5543 return (e->kind == XPR_FTCASE || e->kind == XPR_CASE);
5544 }
5545
5546 return FALSE;
5547}
5548
5549bool exprNode_isLabelMarker (exprNode e)
5550{
5551 if (exprNode_isDefined (e))
5552 {
5553 return (e->kind == XPR_LABEL);
5554 }
5555
5556 return FALSE;
5557}
5558
5559exprNode exprNode_caseMarker (/*@only@*/ exprNode test, bool fallThrough)
5560{
5561 exprNode ret = exprNode_createPartialCopy (test);
5562
5563 ret->kind = fallThrough ? XPR_FTCASE : XPR_CASE;
5564
5565 if (exprNode_isError (test)) {
5566 return ret;
5567 }
5568
5569 exprNode_checkUse (ret, test->sref, test->loc);
5570
5571 usymtab_setExitCode (ret->exitCode);
5572
5573 if (ret->mustBreak)
5574 {
5575 usymtab_setMustBreak ();
5576 }
5577
5578 ret->edata = exprData_makeSingle (test);
5579 ret->isJumpPoint = TRUE;
5580
5581 return ret;
5582}
5583
5584# if 0
5585exprNode exprNode_caseStatement (/*@only@*/ exprNode test, /*@only@*/ exprNode stmt, bool fallThrough)
5586{
5587 exprNode ret = exprNode_createPartialCopy (test);
5588
5589 ret->kind = fallThrough ? XPR_FTCASE : XPR_CASE;
5590 ret->edata = exprData_makePair (test, stmt);
5591 ret->isJumpPoint = TRUE;
5592
5593 if (exprNode_isError (test))
5594 {
5595 return ret;
5596 }
5597
5598 exprNode_checkUse (ret, test->sref, test->loc);
5599
5600 if (exprNode_isError (stmt))
5601 {
5602 return ret;
5603 }
5604
5605 exprNode_mergeUSs (ret, stmt);
5606
5607 ret->exitCode = stmt->exitCode;
5608 ret->mustBreak = stmt->mustBreak;
5609 ret->canBreak = stmt->canBreak;
5610
5611 usymtab_setExitCode (ret->exitCode);
5612
5613 if (ret->mustBreak)
5614 {
5615 usymtab_setMustBreak ();
5616 }
5617
5618 return ret;
5619}
5620# endif
5621
5622/*@notnull@*/ /*@only@*/ exprNode
5623exprNode_defaultMarker (/*@only@*/ lltok def, bool fallThrough)
5624{
5625 exprNode ret = exprNode_createTok (def);
5626
5627 ret->isJumpPoint = TRUE;
5628 ret->kind = fallThrough ? XPR_FTDEFAULT : XPR_DEFAULT;
5629 return (ret);
5630}
5631
5632bool
5633exprNode_mayEscape (exprNode e)
5634{
5635 if (exprNode_isDefined (e))
5636 {
5637 return exitkind_couldEscape (e->exitCode);
5638 }
5639 return FALSE;
5640}
5641
5642static bool
5643exprNode_mustBreak (exprNode e)
5644{
5645 if (exprNode_isDefined (e))
5646 {
5647 return e->mustBreak;
5648 }
5649 return FALSE;
5650}
5651
5652bool
5653exprNode_mustEscape (exprNode e)
5654{
5655 if (exprNode_isDefined (e))
5656 {
5657 return exitkind_mustEscape (e->exitCode) || exprNode_mustBreak (e);
5658 }
5659
5660 return FALSE;
5661}
5662
5663bool
5664exprNode_errorEscape (exprNode e)
5665{
5666 if (exprNode_isDefined (e))
5667 {
5668 return exitkind_isError (e->exitCode);
5669 }
5670
5671 return FALSE;
5672}
5673
5674exprNode exprNode_concat (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
5675{
5676 exprNode ret = exprNode_createPartialCopy (e1);
5677
5678 ret->edata = exprData_makePair (e1, e2);
5679 ret->kind = XPR_STMTLIST;
5680
5681 if (exprNode_isDefined (e1))
5682 {
5683 ret->isJumpPoint = e1->isJumpPoint;
5684 ret->canBreak = e1->canBreak;
5685 }
5686 else
5687 {
5688 if (exprNode_isDefined (e2))
5689 {
5690 ret->loc = fileloc_update (ret->loc, e2->loc);
5691 }
5692 }
5693
5694 if (exprNode_isDefined (e2))
5695 {
5696 ret->exitCode = e2->exitCode;
5697 ret->mustBreak = e2->mustBreak;
5698 if (e2->canBreak) ret->canBreak = TRUE;
5699 }
5700
5701 /*
5702 ** if e1 must return, then e2 is unreachable!
5703 */
5704
5705 if (exprNode_isDefined (e1) && exprNode_isDefined (e2))
5706 {
5707 if ((exprNode_mustEscape (e1) || exprNode_mustBreak (e1))
5708 && !(e2->isJumpPoint))
5709 {
5710 if (context_getFlag (FLG_UNREACHABLE))
5711 {
5712 exprNode nr = e2;
5713
5714 if (e2->kind == XPR_STMT)
5715 {
5716 nr = exprData_getUopNode (e2->edata);
5717 }
5718
5719 if ((nr->kind == XPR_TOK
5720 && lltok_isSemi (exprData_getTok (nr->edata))))
5721 {
5722 /* okay to have unreachable ";" */
5723 ret->exitCode = XK_MUSTEXIT;
5724 ret->canBreak = TRUE;
5725 }
5726 else
5727 {
5728 if (optgenerror (FLG_UNREACHABLE,
5729 message ("Unreachable code: %s",
5730 exprNode_unparseFirst (nr)),
5731 exprNode_loc (nr)))
5732 {
5733 ret->isJumpPoint = TRUE;
5734 ret->mustBreak = FALSE;
5735 ret->exitCode = XK_ERROR;
5736 DPRINTF (("Jump point: %s", exprNode_unparse (ret)));
5737 }
5738 else
5739 {
5740 ret->exitCode = XK_MUSTEXIT;
5741 ret->canBreak = TRUE;
5742 }
5743
5744 }
5745 }
5746 }
5747 else
5748 {
5749 if ((e2->kind == XPR_CASE || e2->kind == XPR_DEFAULT))
5750 {
5751 /*
5752 ** We want a warning anytime we have:
5753 ** case xxx: ...
5754 ** yyy; <<<- no break or return
5755 ** case zzz: ...
5756 */
5757
5758 exprNode lastStmt = exprNode_lastStatement (e1);
5759
5760 if (exprNode_isDefined (lastStmt)
5761 && !exprNode_mustEscape (lastStmt)
5762 && !exprNode_mustBreak (lastStmt)
5763 && !exprNode_isCaseMarker (lastStmt)
5764 && !exprNode_isDefaultMarker (lastStmt)
5765 && !exprNode_isLabelMarker (lastStmt))
5766 {
5767 voptgenerror (FLG_CASEBREAK,
5768 cstring_makeLiteral
5769 ("Fall through case (no preceeding break)"),
5770 e2->loc);
5771 }
5772 }
5773 }
5774 }
5775
5776 exprNode_mergeUSs (ret, e2);
dc92450f 5777 // ret = exprNode_mergeEnvironments (ret, e1, e2);
616915dd 5778 usymtab_setExitCode (ret->exitCode);
5779
5780 if (ret->mustBreak)
5781 {
5782 usymtab_setMustBreak ();
5783 }
5784
5785 return ret;
5786}
5787
5788exprNode exprNode_createTok (/*@only@*/ lltok t)
5789{
5790 exprNode ret = exprNode_create (ctype_unknown);
5791 ret->kind = XPR_TOK;
5792 ret->edata = exprData_makeTok (t);
5793 return ret;
5794}
5795
5796exprNode exprNode_statement (/*@only@*/ exprNode e, /*@only@*/ lltok t)
5797{
5798 if (!exprNode_isError (e))
5799 {
5800 exprNode_checkStatement(e);
5801 }
5802
5803 return (exprNode_statementError (e, t));
5804}
5805
5806static exprNode exprNode_statementError (/*@only@*/ exprNode e, /*@only@*/ lltok t)
5807{
5808 exprNode ret = exprNode_createPartialCopy (e);
5809
5810 if (!exprNode_isError (e))
5811 {
5812 if (e->kind != XPR_ASSIGN)
5813 {
5814 exprNode_checkUse (ret, e->sref, e->loc);
5815 }
5816
5817 ret->exitCode = e->exitCode;
5818 ret->canBreak = e->canBreak;
5819 ret->mustBreak = e->mustBreak;
5820 }
5821
5822 ret->edata = exprData_makeUop (e, t);
5823 ret->kind = XPR_STMT;
5824
5825 return ret;
5826}
5827
5828exprNode exprNode_checkExpr (/*@returned@*/ exprNode e)
5829{
5830 if (!exprNode_isError (e))
5831 {
5832 if (e->kind != XPR_ASSIGN)
5833 {
5834 exprNode_checkUse (e, e->sref, e->loc);
5835 }
5836 }
5837
5838 return e;
5839}
5840
5841void exprNode_produceGuards (exprNode pred)
5842{
5843 if (!exprNode_isError (pred))
5844 {
5845 if (ctype_isRealPointer (pred->typ))
5846 {
5847 pred->guards = guardSet_addTrueGuard (pred->guards, pred->sref);
5848 }
5849
5850 exprNode_checkUse (pred, pred->sref, pred->loc);
5851 exprNode_resetSref (pred);
5852 }
5853}
5854
5855exprNode exprNode_makeBlock (/*@only@*/ exprNode e)
5856{
5857 exprNode ret = exprNode_createPartialCopy (e);
5858
5859 if (!exprNode_isError (e))
5860 {
5861 ret->exitCode = e->exitCode;
5862 ret->canBreak = e->canBreak;
5863 ret->mustBreak = e->mustBreak;
5864 }
5865
5866 ret->edata = exprData_makeSingle (e);
5867 ret->kind = XPR_BLOCK;
5868 return ret;
5869}
5870
5871bool exprNode_isBlock (exprNode e)
5872{
5873 return (exprNode_isDefined (e)
5874 && ((e)->kind == XPR_BLOCK));
5875}
5876
5877bool exprNode_isAssign (exprNode e)
5878{
5879 if (exprNode_isDefined (e))
5880 {
5881 return (e->kind == XPR_ASSIGN);
5882 }
5883
5884 return FALSE;
5885}
5886
5887bool exprNode_isEmptyStatement (exprNode e)
5888{
5889 return (exprNode_isDefined (e)
5890 && (e->kind == XPR_TOK)
5891 && (lltok_isSemi (exprData_getTok (e->edata))));
5892}
5893
5894exprNode exprNode_if (/*@only@*/ exprNode pred, /*@only@*/ exprNode tclause)
5895{
5896 exprNode ret;
5897 bool emptyErr = FALSE;
5898
5899 if (context_maybeSet (FLG_IFEMPTY))
5900 {
5901 if (exprNode_isEmptyStatement (tclause))
5902 {
5903 emptyErr = optgenerror (FLG_IFEMPTY,
5904 cstring_makeLiteral
5905 ("Body of if statement is empty"),
5906 exprNode_loc (tclause));
5907 }
5908 }
5909
5910 if (!emptyErr && context_maybeSet (FLG_IFBLOCK))
5911 {
5912 if (exprNode_isDefined (tclause)
5913 && !exprNode_isBlock (tclause))
5914 {
5915 voptgenerror (FLG_IFBLOCK,
5916 message
5917 ("Body of if statement is not a block: %s",
5918 exprNode_unparse (tclause)),
5919 exprNode_loc (tclause));
5920 }
5921 }
5922
5923 if (exprNode_isError (pred))
5924 {
5925 if (exprNode_isError (tclause))
5926 {
5927 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
5928 }
5929 else
5930 {
5931 ret = exprNode_createPartialCopy (tclause);
5932 }
5933 }
5934 else
5935 {
5936 if (exprNode_mustEscape (pred))
5937 {
5938 voptgenerror
5939 (FLG_UNREACHABLE,
5940 message ("Predicate always exits: %s", exprNode_unparse (pred)),
5941 exprNode_loc (pred));
5942 }
5943
5944 exprNode_checkPred (cstring_makeLiteralTemp ("if"), pred);
5945 exprNode_checkUse (pred, pred->sref, pred->loc);
5946
5947 if (!exprNode_isError (tclause))
5948 {
5949 exprNode_mergeCondUSs (pred, tclause, exprNode_undefined);
5950 }
5951
5952 ret = exprNode_createPartialCopy (pred);
5953 }
5954
5955 ret->kind = XPR_IF;
5956 ret->edata = exprData_makePair (pred, tclause);
5957
5958 ret->exitCode = XK_UNKNOWN;
5959
5960 if (exprNode_isDefined (tclause))
5961 {
5962 ret->exitCode = exitkind_makeConditional (tclause->exitCode);
5963 ret->canBreak = tclause->canBreak;
5964 ret->sets = sRefSet_union (ret->sets, tclause->sets);
5965 ret->msets = sRefSet_union (ret->msets, tclause->msets);
5966 ret->uses = sRefSet_union (ret->uses, tclause->uses);
5967 }
5968
5969 ret->mustBreak = FALSE;
5970
5971 return ret;
5972}
5973
5974exprNode exprNode_ifelse (/*@only@*/ exprNode pred,
5975 /*@only@*/ exprNode tclause,
5976 /*@only@*/ exprNode eclause)
5977{
5978 exprNode ret;
5979 bool tEmptyErr = FALSE;
5980 bool eEmptyErr = FALSE;
5981
5982 if (context_maybeSet (FLG_IFEMPTY))
5983 {
5984 if (exprNode_isEmptyStatement (tclause))
5985 {
5986 tEmptyErr = optgenerror
5987 (FLG_IFEMPTY,
5988 cstring_makeLiteral
5989 ("Body of if clause of if statement is empty"),
5990 exprNode_loc (tclause));
5991 }
5992
5993 if (exprNode_isEmptyStatement (eclause))
5994 {
5995 eEmptyErr = optgenerror
5996 (FLG_IFEMPTY,
5997 cstring_makeLiteral
5998 ("Body of else clause of if statement is empty"),
5999 exprNode_loc (eclause));
6000 }
6001 }
6002
6003 if (context_maybeSet (FLG_IFBLOCK))
6004 {
6005 if (!tEmptyErr
6006 && exprNode_isDefined (tclause)
6007 && !exprNode_isBlock (tclause))
6008 {
6009 voptgenerror (FLG_IFBLOCK,
6010 message
6011 ("Body of if clause of if statement is not a block: %s",
6012 exprNode_unparse (tclause)),
6013 exprNode_loc (tclause));
6014 }
6015
6016 if (!eEmptyErr
6017 && exprNode_isDefined (eclause)
6018 && !exprNode_isBlock (eclause)
6019 && !(eclause->kind == XPR_IF)
6020 && !(eclause->kind == XPR_IFELSE))
6021 {
6022 voptgenerror
6023 (FLG_IFBLOCK,
6024 message
6025 ("Body of else clause of if statement is not a block: %s",
6026 exprNode_unparse (eclause)),
6027 exprNode_loc (eclause));
6028 }
6029 }
6030
6031 if (context_maybeSet (FLG_ELSEIFCOMPLETE))
6032 {
6033 if (exprNode_isDefined (eclause)
6034 && (eclause->kind == XPR_IF))
6035 {
6036 voptgenerror (FLG_ELSEIFCOMPLETE,
6037 message ("Incomplete else if logic (no final else): %s",
6038 exprNode_unparse (eclause)),
6039 exprNode_loc (eclause));
6040 }
6041 }
6042
6043 if (exprNode_isError (pred))
6044 {
6045 if (exprNode_isError (tclause))
6046 {
6047 if (exprNode_isError (eclause))
6048 {
6049 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
6050 }
6051 else
6052 {
6053 ret = exprNode_createPartialCopy (eclause);
6054 }
6055 }
6056 else
6057 {
6058 ret = exprNode_createPartialCopy (tclause);
6059 }
6060 }
6061 else /* pred is okay */
6062 {
6063 ret = exprNode_createPartialCopy (pred);
6064
6065 if (exprNode_mustEscape (pred))
6066 {
6067 voptgenerror
6068 (FLG_UNREACHABLE,
6069 message ("Predicate always exits: %s", exprNode_unparse (pred)),
6070 exprNode_loc (pred));
6071 }
6072
6073 exprNode_checkPred (cstring_makeLiteralTemp ("if"), pred);
6074 exprNode_checkUse (ret, pred->sref, pred->loc);
6075
6076 exprNode_mergeCondUSs (ret, tclause, eclause);
6077 }
6078
6079 ret->kind = XPR_IFELSE;
6080 ret->edata = exprData_makeCond (pred, tclause, eclause);
6081
6082 if (exprNode_isDefined (tclause) && exprNode_isDefined (eclause))
6083 {
6084 exprNode_combineControl (ret, tclause, eclause);
6085 ret->loc = fileloc_update (ret->loc, eclause->loc);
6086 }
6087
6088 return ret;
6089}
6090
6091/*
6092** *allpaths <- TRUE iff all executions paths must go through the switch
6093*/
6094
6095static bool
6096checkSwitchExpr (exprNode test, /*@dependent@*/ exprNode e, /*@out@*/ bool *allpaths)
6097{
6098 exprNodeSList el = exprNode_flatten (e);
6099 bool mustReturn = TRUE; /* find a branch that doesn't */
6100 bool thisReturn = FALSE;
6101 bool hasDefault = FALSE;
6102 bool hasAllMembers = FALSE;
6103 bool inSwitch = FALSE;
6104 bool isEnumSwitch = FALSE;
6105 bool canBreak = FALSE;
6106 bool fallThrough = FALSE;
6107 ctype ct = ctype_unknown;
6108 enumNameSList usedEnums;
6109 enumNameList enums;
6110
6111 if (exprNode_isDefined (test))
6112 {
6113 ctype ttype;
6114
6115 ct = test->typ;
6116 ttype = ctype_realType (ct);
6117
6118 if (ctype_isEnum (ttype))
6119 {
6120 isEnumSwitch = TRUE;
6121 enums = ctype_elist (ttype);
6122 usedEnums = enumNameSList_new ();
6123 }
6124 }
6125
6126 exprNodeSList_elements (el, current)
6127 {
6128 if (exprNode_isDefined (current))
6129 {
6130 switch (current->kind)
6131 {
6132 case XPR_FTDEFAULT:
6133 case XPR_DEFAULT:
6134 if (hasDefault)
6135 {
6136 voptgenerror
6137 (FLG_CONTROL,
6138 message ("Duplicate default cases in switch"),
6139 exprNode_loc (current));
6140 }
6141 /*@fallthrough@*/
6142 case XPR_FTCASE:
6143 case XPR_CASE:
6144 if (current->kind == XPR_DEFAULT || current->kind == XPR_FTDEFAULT)
6145 {
6146 hasDefault = TRUE;
6147 }
6148 else
6149 {
6150 if (isEnumSwitch)
6151 {
6152 exprNode st = exprData_getSingle (current->edata);
6153 uentry ue = exprNode_getUentry (st);
6154
6155 if (uentry_isValid (ue))
6156 {
6157 cstring cname = uentry_rawName (ue);
6158
6159 if (enumNameList_member (/*@-usedef@*/enums/*@=usedef@*/, cname))
6160 {
6161 if (enumNameSList_member
6162 (/*@-usedef@*/usedEnums/*@=usedef@*/, cname))
6163 {
6164 voptgenerror
6165 (FLG_CONTROL,
6166 message ("Duplicate case in switch: %s",
6167 cname),
6168 current->loc);
6169 }
6170 else
6171 {
6172 enumNameSList_addh (usedEnums, cname);
6173 }
6174 }
6175 else
6176 {
6177 voptgenerror
6178 (FLG_TYPE,
6179 message ("Case in switch not %s member: %s",
6180 ctype_unparse (ct), cname),
6181 current->loc);
6182 }
6183 }
6184 }
6185 }
6186
6187 if (inSwitch && !fallThrough)
6188 {
6189 if (!thisReturn || canBreak)
6190 {
6191 mustReturn = FALSE;
6192 }
6193 }
6194
6195 fallThrough = TRUE;
6196 inSwitch = TRUE;
6197 thisReturn = FALSE;
6198 canBreak = FALSE;
6199 /*@switchbreak@*/ break;
6200 default:
6201 thisReturn = thisReturn || exprNode_mustEscape (current);
6202 canBreak = canBreak || current->canBreak;
6203 if (canBreak) fallThrough = FALSE;
6204 }
6205 }
6206 } end_exprNodeSList_elements;
6207
6208 if (inSwitch) /* check the last one! */
6209 {
6210 if (!thisReturn || canBreak)
6211 {
6212 mustReturn = FALSE;
6213 }
6214 }
6215
6216 if (isEnumSwitch)
6217 {
6218 if (!hasDefault
6219 && (enumNameSList_size (/*@-usedef@*/usedEnums/*@=usedef@*/) !=
6220 enumNameList_size (/*@-usedef@*/enums/*@=usedef@*/)))
6221 {
6222 enumNameSList unused = enumNameSList_subtract (enums, usedEnums);
6223
6224 voptgenerror (FLG_MISSCASE,
6225 message ("Missing case%s in switch: %q",
6226 cstring_makeLiteralTemp
6227 ((enumNameSList_size (unused) > 1) ? "s" : ""),
6228 enumNameSList_unparse (unused)),
6229 g_currentloc);
6230
6231 enumNameSList_free (unused);
6232 }
6233 else
6234 {
6235 hasAllMembers = TRUE;
6236 *allpaths = TRUE;
6237 }
6238
6239 enumNameSList_free (usedEnums);
6240 }
6241 else
6242 {
6243 *allpaths = hasDefault;
6244 }
6245
6246 exprNodeSList_free (el);
6247 return ((hasDefault || hasAllMembers) && mustReturn);
6248}
6249
6250exprNode exprNode_switch (/*@only@*/ exprNode e, /*@only@*/ exprNode s)
6251{
6252 exprNode ret = exprNode_createPartialCopy (e);
6253 bool allpaths;
6254
6255 DPRINTF (("Switch: %s", exprNode_unparse (s)));
6256
6257 ret->kind = XPR_SWITCH;
6258 ret->edata = exprData_makePair (e, s);
6259
6260 if (!exprNode_isError (s))
6261 {
6262 exprNode fs = exprNode_firstStatement (s);
6263 ret->loc = fileloc_update (ret->loc, s->loc);
6264
6265 if (exprNode_isUndefined (fs)
6266 || exprNode_isCaseMarker (fs) || exprNode_isLabelMarker (fs)
6267 || exprNode_isDefaultMarker (fs)) {
6268 ;
6269 } else {
6270 voptgenerror (FLG_FIRSTCASE,
6271 message
6272 ("Statement after switch is not a case: %s", exprNode_unparse (fs)),
6273 fs->loc);
6274 }
6275 }
6276
6277 if (!exprNode_isError (e))
6278 {
6279 if (checkSwitchExpr (e, s, &allpaths))
6280 {
6281 ret->exitCode = XK_MUSTRETURN;
6282 }
6283 else
6284 {
6285 ret->exitCode = e->exitCode;
6286 }
6287
6288 ret->canBreak = e->canBreak;
6289 ret->mustBreak = e->mustBreak;
6290 }
6291 /*
6292 ** forgot this!
6293 ** exprNode.c:3883,32: Variable allpaths used before definition
6294 */
6295 else
6296 {
6297 allpaths = FALSE;
6298 }
6299
6300 DPRINTF (("Context exit switch!"));
6301 context_exitSwitch (ret, allpaths);
6302 DPRINTF (("Context exit switch done!"));
6303
6304 return ret;
6305}
6306
6307static void checkInfiniteLoop (/*@notnull@*/ exprNode test,
6308 /*@notnull@*/ exprNode body)
6309{
6310 sRefSet tuses = test->uses;
6311
6312 if (!sRefSet_isEmpty (test->uses))
6313 {
6314 sRefSet sets = sRefSet_newCopy (body->sets);
6315 bool hasError = TRUE;
6316 bool innerState = FALSE;
6317 sRefSet tuncon = sRefSet_undefined;
6318
6319 sets = sRefSet_union (sets, test->sets);
6320 sets = sRefSet_union (sets, body->msets);
6321 sets = sRefSet_union (sets, test->msets);
6322
6323 sRefSet_allElements (tuses, el)
6324 {
6325 if (sRef_isUnconstrained (el))
6326 {
6327 tuncon = sRefSet_insert (tuncon, el);
6328 }
6329 else
6330 {
6331 if (sRefSet_member (sets, el))
6332 {
6333 hasError = FALSE;
6334 break;
6335 }
6336 }
6337
6338 if (sRef_isInternalState (el)
6339 || sRef_isFileStatic (sRef_getRootBase (el)))
6340 {
6341 innerState = TRUE;
6342 }
6343 } end_sRefSet_allElements ;
6344
6345 if (hasError)
6346 {
6347 sRefSet suncon = sRefSet_undefined;
6348 bool sinner = FALSE;
6349
6350 sRefSet_allElements (sets, el)
6351 {
6352 if (sRef_isUnconstrained (el))
6353 {
6354 suncon = sRefSet_insert (suncon, el);
6355 }
6356 else if (sRef_isInternalState (el))
6357 {
6358 sinner = TRUE;
6359 }
6360 else
6361 {
6362 ;
6363 }
6364 } end_sRefSet_allElements ;
6365
6366 if (sinner && innerState)
6367 {
6368 ;
6369 }
6370 else if (sRefSet_isEmpty (tuncon)
6371 && sRefSet_isEmpty (suncon))
6372 {
6373 voptgenerror
6374 (FLG_INFLOOPS,
6375 message
6376 ("Suspected infinite loop. No value used in loop test (%q) "
6377 "is modified by test or loop body.",
6378 sRefSet_unparsePlain (tuses)),
6379 test->loc);
6380 }
6381 else
6382 {
6383 if (sRefSet_isEmpty (tuncon))
6384 {
6385 voptgenerror
6386 (FLG_INFLOOPSUNCON,
6387 message ("Suspected infinite loop. No condition values "
6388 "modified. Modification possible through "
6389 "unconstrained calls: %q",
6390 sRefSet_unparsePlain (suncon)),
6391 test->loc);
6392 }
6393 else
6394 {
6395 voptgenerror
6396 (FLG_INFLOOPSUNCON,
6397 message ("Suspected infinite loop. No condition values "
6398 "modified. Possible undetected dependency through "
6399 "unconstrained calls in loop test: %q",
6400 sRefSet_unparsePlain (tuncon)),
6401 test->loc);
6402 }
6403 }
6404 }
6405
6406 sRefSet_free (sets);
6407 }
6408}
6409
6410exprNode exprNode_while (/*@keep@*/ exprNode t, /*@keep@*/ exprNode b)
6411{
6412 exprNode ret;
6413 bool emptyErr = FALSE;
6414 char *s;
6415 // s = exprNode_generateConstraints (t);
6416 // printf("pred: %s\n", s);
6417 // s = exprNode_generateConstraints (b);
6418 //printf ("body: %s\n", s);
6419 //constraintList_print(b->constraints);
6420
6421 if (context_maybeSet (FLG_WHILEEMPTY))
6422 {
6423 if (exprNode_isEmptyStatement (b))
6424 {
6425 emptyErr = optgenerror
6426 (FLG_WHILEEMPTY,
6427 cstring_makeLiteral
6428 ("Body of while statement is empty"),
6429 exprNode_loc (b));
6430 }
6431 }
6432
6433 if (!emptyErr && context_maybeSet (FLG_WHILEBLOCK))
6434 {
6435 if (exprNode_isDefined (b)
6436 && !exprNode_isBlock (b))
6437 {
6438 if (context_inIterDef ()
6439 && (b->kind == XPR_STMTLIST
6440 || b->kind == XPR_TOK))
6441 {
6442 ; /* no error */
6443 }
6444 else
6445 {
6446 voptgenerror (FLG_WHILEBLOCK,
6447 message
6448 ("Body of while statement is not a block: %s",
6449 exprNode_unparse (b)),
6450 exprNode_loc (b));
6451 }
6452 }
6453 }
6454
6455 if (exprNode_isError (t))
6456 {
6457 if (exprNode_isError (b))
6458 {
6459 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
6460 }
6461 else
6462 {
6463 ret = exprNode_createPartialCopy (b);
6464 }
6465 }
6466 else
6467 {
6468 exprNode test;
6469
6470 ret = exprNode_createPartialCopy (t);
6471
6472 llassert (t->kind == XPR_WHILEPRED);
6473
6474 test = exprData_getSingle (t->edata);
6475
6476 if (!exprNode_isError (b) && exprNode_isDefined (test))
6477 {
6478 if (context_maybeSet (FLG_INFLOOPS)
6479 || context_maybeSet (FLG_INFLOOPSUNCON))
6480 {
6481 /*
6482 ** check that some variable in the predicate is set by the body
6483 ** if the predicate uses any variables
6484 */
6485
6486 checkInfiniteLoop (test, b);
6487 }
6488
6489 exprNode_mergeUSs (ret, b);
6490
6491 if (exprNode_isDefined (b))
6492 {
6493 ret->exitCode = exitkind_makeConditional (b->exitCode);
6494 }
6495 }
6496 }
6497
6498 ret->edata = exprData_makePair (t, b);
6499 ret->kind = XPR_WHILE;
6500
6501 if (exprNode_isDefined (t) && exprNode_mustEscape (t))
6502 {
6503 voptgenerror
6504 (FLG_CONTROL,
6505 message ("Predicate always exits: %s", exprNode_unparse (t)),
6506 exprNode_loc (t));
6507 }
6508
6509 ret->exitCode = XK_NEVERESCAPE;
6510
6511 /*
6512 ** If loop is infinite, and there is no break inside,
6513 ** exit code is never reach.
6514 */
6515
6516 if (exprNode_knownIntValue (t))
6517 {
6518 if (!exprNode_isZero (t))
6519 {
6520 if (exprNode_isDefined (b))
6521 {
6522 if (!b->canBreak)
6523 {
6524 /* Really, it means never reached. */
6525 ret->exitCode = XK_MUSTEXIT;
6526 }
6527 }
6528 }
6529 }
6530 else
6531 {
6532 ;
6533 }
6534
6535 ret->canBreak = FALSE;
6536 ret->mustBreak = FALSE;
6537
6538 return ret;
6539}
6540
6541/*
6542** do { b } while (t);
6543**
6544** note: body passed as first argument
6545*/
6546
6547exprNode exprNode_doWhile (/*@only@*/ exprNode b, /*@only@*/ exprNode t)
6548{
6549 exprNode ret;
6550
6551 if (exprNode_isError (t))
6552 {
6553 if (exprNode_isError (b))
6554 {
6555 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
6556 }
6557 else
6558 {
6559 ret = exprNode_createPartialCopy (b);
6560
6561 ret->exitCode = exitkind_makeConditional (b->exitCode);
6562 exprNode_checkUse (ret, b->sref, b->loc);
6563 ret->exitCode = b->exitCode;
6564 ret->canBreak = b->canBreak;
6565 ret->mustBreak = b->mustBreak;
6566 }
6567 }
6568 else
6569 {
6570 ret = exprNode_createPartialCopy (t);
6571 exprNode_checkPred (cstring_makeLiteralTemp ("while"), t);
6572
6573 if (!exprNode_isError (b))
6574 {
6575 /*
6576 ** forgot the copy's --- why wasn't this detected??
6577 */
6578
6579 ret->sets = sRefSet_copy (ret->sets, b->sets);
6580 ret->msets = sRefSet_copy (ret->msets, b->msets);
6581 ret->uses = sRefSet_copy (ret->uses, b->uses);
6582
6583 /* left this out --- causes and aliasing bug (infinite loop)
6584 should be detected?? */
6585
6586 exprNode_checkUse (ret, b->sref, b->loc);
6587 exprNode_mergeUSs (ret, t);
6588 exprNode_checkUse (ret, t->sref, t->loc);
6589
6590 ret->exitCode = b->exitCode;
6591 ret->canBreak = b->canBreak;
6592 ret->mustBreak = b->mustBreak;
6593 }
6594 }
6595
6596 context_exitDoWhileClause (t);
6597
6598 ret->kind = XPR_DOWHILE;
6599 ret->edata = exprData_makePair (t, b);
6600 return ret;
6601}
6602
6603exprNode exprNode_for (/*@keep@*/ exprNode inc, /*@keep@*/ exprNode body)
6604{
6605 exprNode ret;
6606 bool emptyErr = FALSE;
6607
6608 if (context_maybeSet (FLG_FOREMPTY))
6609 {
6610 if (exprNode_isEmptyStatement (body))
6611 {
6612 emptyErr = optgenerror
6613 (FLG_FOREMPTY,
6614 cstring_makeLiteral
6615 ("Body of for statement is empty"),
6616 exprNode_loc (body));
6617 }
6618 }
6619
6620 if (!emptyErr && context_maybeSet (FLG_FORBLOCK))
6621 {
6622 if (exprNode_isDefined (body)
6623 && !exprNode_isBlock (body))
6624 {
6625 if (context_inIterDef ()
6626 && (body->kind == XPR_STMTLIST
6627 || body->kind == XPR_TOK))
6628 {
6629 ; /* no error */
6630 }
6631 else
6632 {
6633 voptgenerror (FLG_FORBLOCK,
6634 message
6635 ("Body of for statement is not a block: %s",
6636 exprNode_unparse (body)),
6637 exprNode_loc (body));
6638 }
6639 }
6640 }
6641
6642 /*
6643 ** for ud purposes: (alreadly) init -> test -> (now) LOOP: body + inc + test
6644 */
6645
6646 if (exprNode_isError (body))
6647 {
6648 ret = exprNode_createPartialCopy (inc);
6649 }
6650 else
6651 {
6652 ret = exprNode_createPartialCopy (body);
6653
6654 ret->exitCode = exitkind_makeConditional (body->exitCode);
6655
6656 exprNode_mergeUSs (inc, body);
6657
6658 if (exprNode_isDefined (inc))
6659 {
6660 exprNode tmp;
6661
6662 context_setMessageAnnote (cstring_makeLiteral ("in post loop increment"));
6663
6664
6665 tmp = exprNode_effect (exprData_getTripleInc (inc->edata));
6666 exprNode_freeShallow (tmp);
6667
6668 context_clearMessageAnnote ();
6669 context_setMessageAnnote (cstring_makeLiteral ("in post loop test"));
6670
6671 tmp = exprNode_effect (exprData_getTripleTest (inc->edata));
6672 exprNode_freeShallow (tmp);
6673
6674 context_clearMessageAnnote ();
6675
6676 ret->uses = sRefSet_copy (ret->uses, inc->uses);
6677 ret->sets = sRefSet_copy (ret->sets, inc->sets);
6678 ret->msets = sRefSet_copy (ret->msets, inc->msets);
6679 }
6680 }
6681
6682 ret->kind = XPR_FOR;
6683 ret->edata = exprData_makePair (inc, body);
6684
6685 if (exprNode_isDefined (inc)) {
6686 exprNode test = exprData_getTripleTest (inc->edata);
6687
6688 if (exprNode_isUndefined (test)) {
6689 if (exprNode_isDefined (body)) {
6690 if (!body->canBreak) {
6691 /* Really, it means never reached. */
6692 ret->exitCode = XK_MUSTEXIT;
6693 }
6694 }
6695 }
6696 }
6697
6698 return (ret);
6699}
6700
6701/*
6702** for (init; test; inc)
6703** ==>
6704** init;
6705** while (test) { body; inc; }
6706**
6707** Now: check use of init (may set vars for test)
6708** check use of test
6709** no checks on inc
6710_*/
6711
6712/*@observer@*/ guardSet exprNode_getForGuards (exprNode pred)
6713{
6714 exprNode test;
6715
6716 if (exprNode_isError (pred)) return guardSet_undefined;
6717
6718 llassert (pred->kind == XPR_FORPRED);
6719
6720 test = exprData_getTripleTest (pred->edata);
6721
6722 if (!exprNode_isError (test))
6723 {
6724 return (test->guards);
6725 }
6726
6727 return guardSet_undefined;
6728}
6729
6730exprNode exprNode_whilePred (/*@only@*/ exprNode test)
6731{
6732 exprNode ret = exprNode_createSemiCopy (test);
6733
6734 if (exprNode_isDefined (test))
6735 {
6736 exprNode_copySets (ret, test);
6737 exprNode_checkPred (cstring_makeLiteralTemp ("while"), test);
6738 exprNode_checkUse (ret, test->sref, test->loc);
6739
6740 exprNode_produceGuards (test);
6741
6742 ret->guards = guardSet_copy (test->guards);
6743 }
6744
6745 ret->edata = exprData_makeSingle (test);
6746 ret->kind = XPR_WHILEPRED;
6747 return ret;
6748}
6749
6750exprNode exprNode_forPred (/*@only@*/ exprNode init, /*@only@*/ exprNode test,
6751 /*@only@*/ exprNode inc)
6752{
6753 exprNode ret;
6754
6755 /*
6756 ** for ud purposes: init -> test -> LOOP: [ body, inc ]
6757 */
6758
6759 exprNode_checkPred (cstring_makeLiteralTemp ("for"), test);
6760
6761 if (!exprNode_isError (inc))
6762 {
6763 ret = exprNode_createPartialCopy (inc);
6764 }
6765 else
6766 {
6767 if (!exprNode_isError (init))
6768 {
6769 ret = exprNode_createPartialCopy (init);
6770 }
6771 else if (!exprNode_isError (test))
6772 {
6773 ret = exprNode_createPartialCopy (test);
6774 }
6775 else
6776 {
6777 ret = exprNode_createUnknown ();
6778 }
6779 }
6780
6781 exprNode_mergeUSs (ret, init);
6782
6783 if (exprNode_isDefined (init))
6784 {
6785 exprNode_checkUse (ret, init->sref, init->loc);
6786 }
6787
6788 exprNode_mergeUSs (ret, test);
6789
6790 if (exprNode_isDefined (test))
6791 {
6792 exprNode_checkUse (ret, test->sref, test->loc);
6793 }
6794
6795 ret->kind = XPR_FORPRED;
6796 ret->edata = exprData_makeFor (init, test, inc);
6797 return (ret);
6798}
6799
6800/*@notnull@*/ /*@only@*/ exprNode exprNode_goto (/*@only@*/ cstring label)
6801{
6802 exprNode ret = exprNode_createUnknown ();
6803
6804 if (context_inMacro ())
6805 {
6806 voptgenerror (FLG_MACROSTMT,
6807 message ("Macro %s uses goto (not functional)",
6808 context_inFunctionName ()),
6809 g_currentloc);
6810 }
6811
6812 ret->kind = XPR_GOTO;
6813 ret->edata = exprData_makeLiteral (label);
6814 ret->mustBreak = TRUE;
6815 ret->exitCode = XK_GOTO;
6816 ret->canBreak = TRUE;
6817 return ret;
6818}
6819
6820exprNode exprNode_continue (/*@only@*/ lltok l, int qcontinue)
6821{
6822 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (lltok_getLoc (l)));
6823
6824 ret->kind = XPR_CONTINUE;
6825 ret->edata = exprData_makeTok (l);
6826 ret->canBreak = TRUE;
6827 ret->mustBreak = TRUE;
6828
6829 if (qcontinue == QSAFEBREAK)
6830 {
6831 ; /* no checking */
6832 }
6833 else if (qcontinue == QINNERCONTINUE)
6834 {
6835 if (!context_inDeepLoop ())
6836 {
6837 voptgenerror
6838 (FLG_LOOPLOOPCONTINUE,
6839 cstring_makeLiteral ("Continue statement marked with innercontinue "
6840 "is not inside a nested loop"),
6841 exprNode_loc (ret));
6842 }
6843 }
6844 else if (qcontinue == BADTOK)
6845 {
6846 if (context_inDeepLoop ())
6847 {
6848 voptgenerror
6849 (FLG_LOOPLOOPCONTINUE,
6850 cstring_makeLiteral ("Continue statement in nested loop"),
6851 exprNode_loc (ret));
6852 }
6853 }
6854 else
6855 {
6856 llbuglit ("exprNode_continue: bad qcontinue");
6857 }
6858
6859 return ret;
6860}
6861
6862exprNode exprNode_break (/*@only@*/ lltok l, int bqual)
6863{
6864 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (lltok_getLoc (l)));
6865 clause breakClause = context_breakClause ();
6866
6867 ret->kind = XPR_BREAK;
6868 ret->edata = exprData_makeTok (l);
6869 ret->canBreak = TRUE;
6870 ret->mustBreak = TRUE;
6871
6872 if (breakClause == NOCLAUSE)
6873 {
6874 voptgenerror
6875 (FLG_SYNTAX,
6876 cstring_makeLiteral ("Break not inside while, for or switch statement"),
6877 exprNode_loc (ret));
6878 }
6879 else
6880 {
6881 if (bqual != BADTOK)
6882 {
6883 switch (bqual)
6884 {
6885 case QSAFEBREAK:
6886 break;
6887 case QINNERBREAK:
6888 if (breakClause == SWITCHCLAUSE)
6889 {
6890 if (!context_inDeepSwitch ())
6891 {
6892 voptgenerror (FLG_SYNTAX,
6893 cstring_makeLiteral
6894 ("Break preceded by innerbreak is not in a deep switch"),
6895 exprNode_loc (ret));
6896 }
6897 }
6898 else
6899 {
6900 if (!context_inDeepLoop ())
6901 {
6902 voptgenerror (FLG_SYNTAX,
6903 cstring_makeLiteral
6904 ("Break preceded by innerbreak is not in a deep loop"),
6905 exprNode_loc (ret));
6906 }
6907 }
6908 break;
6909 case QLOOPBREAK:
6910 if (breakClause == SWITCHCLAUSE)
6911 {
6912 voptgenerror (FLG_SYNTAX,
6913 cstring_makeLiteral
6914 ("Break preceded by loopbreak is breaking a switch"),
6915 exprNode_loc (ret));
6916 }
6917 break;
6918 case QSWITCHBREAK:
6919 if (breakClause != SWITCHCLAUSE)
6920 {
6921 voptgenerror
6922 (FLG_SYNTAX,
6923 message ("Break preceded by switchbreak is breaking %s",
6924 cstring_makeLiteralTemp
6925 ((breakClause == WHILECLAUSE
6926 || breakClause == DOWHILECLAUSE) ? "a while loop"
6927 : (breakClause == FORCLAUSE) ? "a for loop"
6928 : (breakClause == ITERCLAUSE) ? "an iterator"
6929 : "<error loop>")),
6930 exprNode_loc (ret));
6931 }
6932 break;
6933 BADDEFAULT;
6934 }
6935 }
6936 else
6937 {
6938 if (breakClause == SWITCHCLAUSE)
6939 {
6940 clause nextBreakClause = context_nextBreakClause ();
6941
6942 switch (nextBreakClause)
6943 {
6944 case NOCLAUSE: break;
6945 case WHILECLAUSE:
6946 case DOWHILECLAUSE:
6947 case FORCLAUSE:
6948 case ITERCLAUSE:
6949 voptgenerror
6950 (FLG_LOOPSWITCHBREAK,
6951 cstring_makeLiteral ("Break statement in switch inside loop"),
6952 exprNode_loc (ret));
6953 break;
6954 case SWITCHCLAUSE:
6955 voptgenerror
6956 (FLG_SWITCHSWITCHBREAK,
6957 cstring_makeLiteral ("Break statement in switch inside switch"),
6958 exprNode_loc (ret));
6959 break;
6960 BADDEFAULT;
6961 }
6962 }
6963 else
6964 {
6965 if (context_inDeepLoop ())
6966 {
6967 voptgenerror
6968 (FLG_LOOPLOOPBREAK,
6969 cstring_makeLiteral ("Break statement in nested loop"),
6970 exprNode_loc (ret));
6971 }
6972 else
6973 {
6974 if (context_inDeepLoopSwitch ())
6975 {
6976 voptgenerror
6977 (FLG_SWITCHLOOPBREAK,
6978 cstring_makeLiteral ("Break statement in loop inside switch"),
6979 exprNode_loc (ret));
6980 }
6981 }
6982 }
6983 }
6984 }
6985
6986 return ret;
6987}
6988
6989exprNode exprNode_nullReturn (/*@only@*/ lltok t)
6990{
6991 fileloc loc = lltok_getLoc (t);
6992 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (loc));
6993
6994 context_returnFunction ();
6995 exprChecks_checkNullReturn (loc);
6996
6997 ret->kind = XPR_NULLRETURN;
6998 ret->edata = exprData_makeTok (t);
6999 ret->exitCode = XK_MUSTRETURN;
7000 return ret;
7001}
7002
7003exprNode exprNode_return (/*@only@*/ exprNode e)
7004{
7005 exprNode ret;
7006
7007 if (exprNode_isError (e))
7008 {
7009 ret = exprNode_createUnknown ();
7010 }
7011 else
7012 {
7013 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (e->loc));
7014
7015 exprNode_checkUse (ret, e->sref, e->loc);
7016 exprNode_checkReturn (e);
7017 }
7018
7019 context_returnFunction ();
7020 ret->kind = XPR_RETURN;
7021 ret->edata = exprData_makeSingle (e);
7022 ret->exitCode = XK_MUSTRETURN;
7023
7024 return (ret);
7025}
7026
7027exprNode exprNode_comma (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
7028{
7029 exprNode ret;
7030
7031 if (exprNode_isError (e1))
7032 {
7033 if (exprNode_isError (e2))
7034 {
7035 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
7036 }
7037 else
7038 {
7039 ret = exprNode_createPartialCopy (e2);
7040 exprNode_checkUse (ret, e2->sref, e2->loc);
7041 ret->sref = e2->sref;
7042 }
7043 }
7044 else
7045 {
7046 ret = exprNode_createPartialCopy (e1);
7047
7048 exprNode_checkUse (ret, e1->sref, e1->loc);
7049
7050 if (!exprNode_isError (e2))
7051 {
7052 exprNode_mergeUSs (ret, e2);
7053 exprNode_checkUse (ret, e2->sref, e2->loc);
7054 ret->sref = e2->sref;
7055 }
7056 }
7057
7058 ret->kind = XPR_COMMA;
7059 ret->edata = exprData_makePair (e1, e2);
7060
7061 if (exprNode_isDefined (e1))
7062 {
7063 if (exprNode_isDefined (e2))
7064 {
7065 ret->typ = e2->typ;
7066
7067 if (exprNode_mustEscape (e1) || e1->mustBreak)
7068 {
7069 voptgenerror
7070 (FLG_UNREACHABLE,
7071 message ("Second clause of comma expression is unreachable: %s",
7072 exprNode_unparse (e2)),
7073 exprNode_loc (e2));
7074 }
7075
7076 ret->exitCode = exitkind_combine (e1->exitCode, e2->exitCode);
7077 ret->mustBreak = e1->mustBreak || e2->mustBreak;
7078 ret->canBreak = e1->canBreak || e2->canBreak;
7079 }
7080 else
7081 {
7082 if (exprNode_mustEscape (e1) || e1->mustBreak)
7083 {
7084 voptgenerror
7085 (FLG_UNREACHABLE,
7086 message ("Second clause of comma expression is unreachable: %s",
7087 exprNode_unparse (e2)),
7088 exprNode_loc (e2));
7089 }
7090
7091 ret->exitCode = e1->exitCode;
7092 ret->canBreak = e1->canBreak;
7093 }
7094 }
7095 else
7096 {
7097 if (exprNode_isDefined (e2))
7098 {
7099 ret->exitCode = e2->exitCode;
7100 ret->mustBreak = e2->mustBreak;
7101 ret->canBreak = e2->canBreak;
7102 }
7103 }
7104
7105 return (ret);
7106}
7107
7108static bool exprNode_checkOneInit (/*@notnull@*/ exprNode el, exprNode val)
7109{
7110 ctype t1 = exprNode_getType (el);
7111 ctype t2 = exprNode_getType (val);
7112 bool hasError = FALSE;
7113
7114 if (ctype_isUnknown (t1))
7115 {
7116 voptgenerror (FLG_IMPTYPE,
7117 message ("Variable has unknown (implicitly int) type: %s",
7118 exprNode_unparse (el)),
7119 el->loc);
7120
7121 t1 = ctype_int;
7122 el->typ = ctype_int;
7123 }
7124
7125 if (exprNode_isDefined (val) && val->kind == XPR_INITBLOCK)
7126 {
7127 exprNodeList vals = exprData_getArgs (val->edata);
7128
7129 if (ctype_isRealAP (t1))
7130 {
7131 int i = 0;
7132 int nerrors = 0;
7133
7134 exprNodeList_elements (vals, oneval)
7135 {
7136 cstring istring = message ("%d", i);
7137 exprNode newel =
7138 exprNode_arrayFetch
7139 (exprNode_fakeCopy (el),
7140 exprNode_numLiteral (ctype_int, istring,
7141 fileloc_copy (el->loc), i));
7142
7143 if (exprNode_isDefined (newel))
7144 {
7145 if (exprNodeList_size (vals) == 1
7146 && ctype_isString (exprNode_getType (oneval))
7147 && ctype_isChar (exprNode_getType (newel)))
7148 {
7149 exprNode_freeIniter (newel);
7150 }
7151 else
7152 {
7153 if (exprNode_checkOneInit (newel, oneval))
7154 {
7155 hasError = TRUE;
7156 nerrors++;
7157
7158 if (nerrors > 3 && exprNodeList_size (vals) > 6)
7159 {
7160 llgenmsg
7161 (message ("Additional initialization errors "
7162 "for %s not reported",
7163 exprNode_unparse (el)),
7164 exprNode_loc (el));
7165 exprNode_freeIniter (newel);
7166 break;
7167 }
7168 else
7169 {
7170 exprNode_freeIniter (newel);
7171 }
7172 }
7173 else
7174 {
7175 exprNode_freeIniter (newel);
7176 }
7177 }
7178 }
7179
7180 cstring_free (istring);
7181 i++;
7182 /*@-branchstate@*/
7183 } end_exprNodeList_elements;
7184 /*@=branchstate@*/
7185 }
7186 else if (ctype_isStruct (ctype_realType (t1)))
7187 {
7188 uentryList fields = ctype_getFields (t1);
7189 int i = 0;
7190
7191 if (uentryList_size (fields) != exprNodeList_size (vals))
7192 {
7193 if (uentryList_size (fields) > exprNodeList_size (vals))
7194 {
7195 hasError = optgenerror
7196 (FLG_FULLINITBLOCK,
7197 message ("Initializer block for "
7198 "%s has %d field%p, but %s has %d field%p: %q",
7199 exprNode_unparse (el),
7200 exprNodeList_size (vals),
7201 ctype_unparse (t1),
7202 uentryList_size (fields),
7203 exprNodeList_unparse (vals)),
7204 val->loc);
7205 }
7206 else
7207 {
7208 hasError = optgenerror
7209 (FLG_TYPE,
7210 message ("Initializer block for "
7211 "%s has %d field%p, but %s has %d field%p: %q",
7212 exprNode_unparse (el),
7213 exprNodeList_size (vals),
7214 ctype_unparse (t1),
7215 uentryList_size (fields),
7216 exprNodeList_unparse (vals)),
7217 val->loc);
7218 }
7219 }
7220 else
7221 {
7222 exprNodeList_elements (vals, oneval)
7223 {
7224 uentry thisfield = uentryList_getN (fields, i);
7225 exprNode newel =
7226 exprNode_fieldAccess (exprNode_fakeCopy (el),
7227 uentry_getName (thisfield));
7228
7229 if (exprNode_isDefined (newel))
7230 {
7231 if (exprNode_checkOneInit (newel, oneval))
7232 {
7233 hasError = TRUE;
7234 }
7235
7236 exprNode_freeIniter (newel);
7237 }
7238
7239 i++;
7240 } end_exprNodeList_elements;
7241 }
7242 }
7243 else
7244 {
7245 hasError = optgenerror
7246 (FLG_TYPE,
7247 message ("Initializer block used for "
7248 "%s where %t is expected: %s",
7249 exprNode_unparse (el), t1, exprNode_unparse (val)),
7250 val->loc);
7251 }
7252 }
7253 else
7254 {
7255 if (exprNode_isDefined (val))
7256 {
7257 doAssign (el, val, TRUE);
7258
7259 if (!exprNode_matchType (t1, val))
7260 {
7261 hasError = gentypeerror
7262 (t1, val, t2, el,
7263 message ("Initial value of %s is type %t, "
7264 "expects %t: %s",
7265 exprNode_unparse (el),
7266 t2, t1, exprNode_unparse (val)),
7267 val->loc);
7268 }
7269 }
7270 }
7271
7272 return hasError;
7273}
7274
7275exprNode exprNode_makeInitialization (/*@only@*/ idDecl t,
7276 /*@only@*/ exprNode e)
7277{
7278 uentry ue = usymtab_lookup (idDecl_observeId (t));
7279 bool isUsed = uentry_isUsed (ue);
7280 exprNode ret = exprNode_fromIdentifierAux (ue);
7281 ctype ct = ctype_realishType (ret->typ);
7282 fileloc loc;
7283
7284 if (ctype_isUnknown (ct))
7285 {
7286 voptgenerror (FLG_IMPTYPE,
7287 message ("Variable has unknown (implicitly int) type: %s",
7288 idDecl_getName (t)),
7289 exprNode_isDefined (e) ? exprNode_loc (e) : g_currentloc);
7290
7291 ct = ctype_int;
7292 }
7293
7294 if (exprNode_isError (e))
7295 {
7296 e = exprNode_createUnknown ();
7297 loc = g_currentloc;
7298
7299 /* error: assume initializer is defined */
7300 sRef_setDefined (ret->sref, loc);
7301 }
7302 else
7303 {
7304 loc = exprNode_loc (e);
7305
7306 /*
7307 ** evs - 9 Apr 1995
7308 **
7309 ** was addSafeUse --- what's the problem?
7310 **
7311 ** int x = 3, y = x ?
7312 */
7313
7314 exprNode_checkUse (ret, e->sref, e->loc);
7315
7316 if (ctype_isUnknown (e->typ) && uentry_isValid (ue))
7317 {
7318 exprNode lhs = exprNode_createId (ue);
7319
7320 /*
7321 ** static storage should be undefined before initializing
7322 */
7323
7324 if (uentry_isStatic (ue))
7325 {
7326 sRef_setDefState (lhs->sref, SS_PARTIAL, fileloc_undefined);
7327 }
7328
7329 (void) exprNode_checkOneInit (lhs, e);
7330
7331 if (uentry_isStatic (ue))
7332 {
7333 sRef_setDefState (lhs->sref, SS_DEFINED, fileloc_undefined);
7334 }
7335
7336 exprNode_free (lhs);
7337 }
7338 else
7339 {
7340 if (!exprNode_matchType (ct, e))
7341 {
7342 if (exprNode_isZero (e) && ctype_isArrayPtr (ct))
7343 {
7344 ;
7345 }
7346 else
7347 {
7348 (void) gentypeerror
7349 (exprNode_getType (e), e, exprNode_getType (ret), ret,
7350 message
7351 ("Variable %s initialized to type %t, expects %t: %s",
7352 exprNode_unparse (ret), exprNode_getType (e),
7353 exprNode_getType (ret),
7354 exprNode_unparse (e)),
7355 e->loc);
7356 }
7357 }
7358 }
7359
7360 if (uentry_isStatic (ue))
7361 {
7362 sRef_setDefState (ret->sref, SS_PARTIAL, fileloc_undefined);
7363 }
7364
7365 doAssign (ret, e, TRUE);
7366
7367 if (uentry_isStatic (ue))
7368 {
7369 sRef_setDefState (ret->sref, SS_DEFINED, fileloc_undefined);
7370 }
7371 }
7372
7373 if (context_inIterDef ())
7374 {
7375 /* should check if it is yield */
7376 uentry_setUsed (ue, loc);
7377 }
7378 else
7379 {
7380 if (!isUsed) /* could be @unused@-qualified variable */
7381 {
7382 uentry_setNotUsed (ue);
7383 }
7384 }
7385
7386 ret->exitCode = XK_NEVERESCAPE;
7387 ret->mustBreak = FALSE;
7388
7389 /*
7390 ** Must be before new kind is assigned!
7391 */
7392
7393 exprData_free (ret->edata, ret->kind);
7394
7395 ret->kind = XPR_INIT;
7396 ret->edata = exprData_makeInit (t, e);
7397 exprNode_mergeUSs (ret, e);
7398 return ret;
7399}
7400
7401exprNode exprNode_iter (/*@observer@*/ uentry name,
7402 /*@only@*/ exprNodeList alist,
7403 /*@only@*/ exprNode body,
7404 /*@observer@*/ uentry end)
7405{
7406 exprNode ret;
7407 cstring iname;
7408
7409 llassert (uentry_isValid (name));
7410
7411 uentry_setUsed (name, exprNode_loc (body));
7412
7413 ret = exprNode_createPartialCopy (body);
7414 iname = uentry_getName (name);
7415
7416 if (uentry_isInvalid (end))
7417 {
7418 llerror (FLG_ITER,
7419 message ("Iter %s not balanced with end_%s", iname, iname));
7420 }
7421 else
7422 {
7423 cstring ename = uentry_getName (end);
7424
7425 if (!cstring_equalPrefix (ename, "end_"))
7426 {
7427 llerror (FLG_ITER, message ("Iter %s not balanced with end_%s: %s",
7428 iname, iname, ename));
7429 }
7430 else
7431 {
7432 if (!cstring_equal (iname, cstring_suffix (ename, 4)))
7433 {
7434 llerror (FLG_ITER,
7435 message ("Iter %s not balanced with end_%s: %s",
7436 iname, iname, ename));
7437 }
7438 }
7439
7440 cstring_free (ename);
7441 }
7442
7443 context_exitIterClause (body);
7444
7445 ret->kind = XPR_ITER;
7446 ret->edata = exprData_makeIter (name, alist, body, end);
7447
7448 if (uentry_isIter (name))
7449 {
7450 (void) checkArgsReal (name, body,
7451 uentry_getParams (name), alist, TRUE, ret);
7452 }
7453
7454 cstring_free (iname);
7455
7456 return ret;
7457}
7458
7459exprNode
7460exprNode_iterNewId (/*@only@*/ cstring s)
7461{
7462 exprNode e = exprNode_new ();
7463 uentry ue = uentryList_getN (uentry_getParams (getCurrentIter ()), iterParamNo ());
7464
7465 llassert (processingIterVars ());
7466
7467 e->loc = context_getSaveLocation ();
7468
7469 if (fileloc_isUndefined (e->loc))
7470 {
7471 fileloc_free (e->loc);
7472 e->loc = fileloc_copy (g_currentloc);
7473 }
7474
7475 e->uses = sRefSet_new ();
7476 e->sets = sRefSet_new ();
7477 e->msets = sRefSet_new ();
7478 e->kind = XPR_VAR;
7479 e->val = multiVal_unknown ();
7480 e->guards = guardSet_new ();
7481 e->sref = defref;
7482 e->isJumpPoint = FALSE;
7483 e->exitCode = XK_NEVERESCAPE;
7484
7485 /*> missing fields, detected by lclint <*/
7486 e->canBreak = FALSE;
7487 e->mustBreak = FALSE;
7488 e->etext = cstring_undefined;
7489
7490 if (uentry_isYield (ue))
7491 {
7492 uentry uue = uentry_makeVariable (s, uentry_getType (ue),
7493 fileloc_copy (e->loc),
7494 FALSE);
7495 sRef sr;
7496
7497 uue = usymtab_supEntrySrefReturn (uue);
7498
7499 sr = uentry_getSref (uue);
7500 sRef_mergeStateQuiet (sr, uentry_getSref (ue));
7501 sr = uentry_getSref (uue);
7502 sRef_setDefined (sr, e->loc);
7503
7504 e->typ = uentry_getType (uue);
7505 e->sref = sr;
7506 e->edata = exprData_makeId (uue);
7507 uentry_setUsed (uue, g_currentloc);
7508 }
7509 else
7510 {
7511 uentry uue;
7512
7513 sRef_setGlobalScope ();
7514 uue = uentry_makeVariableLoc (s, ctype_unknown);
7515
7516 e->typ = ctype_unknown;
7517 e->edata = exprData_makeId (uue);
7518
7519 uentry_setUsed (uue, e->loc);
7520 uentry_setHasNameError (uue);
7521
7522 if (context_getFlag (FLG_REPEATUNRECOG))
7523 {
7524 uentry_markOwned (uue);
7525 }
7526 else
7527 {
7528 usymtab_supGlobalEntry (uue);
7529 }
7530
7531 sRef_clearGlobalScope ();
7532
7533 voptgenerror (FLG_UNRECOG, message ("Unrecognized identifier: %s", s),
7534 e->loc);
7535 }
7536
7537
7538 cstring_free (s);
7539 return (e);
7540}
7541
7542exprNode
7543exprNode_iterExpr (/*@returned@*/ exprNode e)
7544{
7545 if (!processingIterVars ())
7546 {
7547 llcontbuglit ("checkIterParam: not in iter");
7548 return e;
7549 }
7550
7551 if (uentry_isYield (uentryList_getN (uentry_getParams (getCurrentIter ()),
7552 iterParamNo ())))
7553 {
7554 if (exprNode_isDefined (e))
7555 {
7556 if (fileloc_isDefined (e->loc))
7557 {
7558 voptgenerror
7559 (FLG_ITER,
7560 message ("Yield parameter is not simple identifier: %s",
7561 exprNode_unparse (e)),
7562 e->loc);
7563 }
7564 else
7565 {
7566 voptgenerror
7567 (FLG_ITER,
7568 message ("Yield parameter is not simple identifier: %s",
7569 exprNode_unparse (e)),
7570 g_currentloc);
7571
7572 }
7573 }
7574 }
7575 return e;
7576}
7577
7578exprNode
7579exprNode_iterId (/*@observer@*/ uentry c)
7580{
7581 uentry ue;
7582
7583 llassert (processingIterVars ());
7584
7585 ue = uentryList_getN (uentry_getParams (getCurrentIter ()),
7586 iterParamNo ());
7587
7588 if (uentry_isYield (ue))
7589 {
7590 ctype ct = uentry_getType (ue);
7591 exprNode e = exprNode_createPlain (ct);
7592 cstring name = uentry_getName (c);
7593 uentry le = uentry_makeVariable (name, ct, fileloc_undefined, FALSE);
7594
7595 uentry_setUsed (ue, g_currentloc);
7596 uentry_setHasNameError (ue);
7597
7598 cstring_free (name);
7599
7600 e->kind = XPR_VAR;
7601 e->edata = exprData_makeId (le);
7602 e->loc = context_getSaveLocation ();
7603 e->sref = uentry_getSref (le);
7604
7605 usymtab_supEntrySref (le);
7606
7607 if (!context_inHeader ())
7608 {
7609 if (optgenerror
7610 (FLG_ITER,
7611 message ("Yield parameter shadows local declaration: %q",
7612 uentry_getName (c)),
7613 fileloc_isDefined (e->loc) ? e->loc : g_currentloc))
7614 {
7615 uentry_showWhereDeclared (c);
7616 }
7617 }
7618
7619 return e;
7620 }
7621
7622 return (exprNode_fromIdentifierAux (c));
7623}
7624
7625exprNode exprNode_iterStart (/*@observer@*/ uentry name, /*@only@*/ exprNodeList alist)
7626{
7627 exprNode ret = exprNode_create (ctype_unknown);
7628
7629 ret->kind = XPR_ITERCALL;
7630 ret->edata = exprData_makeIterCall (name, alist);
7631
7632 if (uentry_isIter (name))
7633 {
7634 uentryList params = uentry_getParams (name);
7635
7636 if (context_inIterDef ()
7637 && uentryList_size (params) == exprNodeList_size (alist))
7638 {
7639 int i = 0;
7640
7641 exprNodeList_elements (alist, arg)
7642 {
7643 uentry parg = uentryList_getN (params, i);
7644
7645 if (uentry_isYield (parg))
7646 {
7647 uentry ue = exprNode_getUentry (arg);
7648
7649 if (uentry_isValid (ue))
7650 {
7651 ;
7652 }
7653 }
7654
7655 i++;
7656 } end_exprNodeList_elements;
7657 }
7658
7659 (void) checkArgsReal (name, ret, params, alist, TRUE, ret);
7660 checkUnspecCall (ret, params, alist);
7661 }
7662
7663 return ret;
7664}
7665
7666/*@exposed@*/ sRef exprNode_getSref (exprNode e)
7667{
7668 if (exprNode_isDefined (e))
7669 {
7670 /*@access sRef@*/
7671 if (e->sref == defref) /*@noaccess sRef@*/
7672 {
7673 /*@-mods@*/
7674 e->sref = sRef_makeUnknown ();
7675 sRef_setAliasKind (e->sref, AK_ERROR, fileloc_undefined);
7676 /*@=mods@*/
7677 return e->sref;
7678 }
7679 else
7680 {
7681 return e->sref;
7682 }
7683 }
7684 else
7685 {
7686 return sRef_undefined;
7687 }
7688}
7689
7690/*@observer@*/ cstring
7691exprNode_unparseFirst (exprNode e)
7692{
7693 if (exprNode_isDefined (e))
7694 {
7695 cstring ret;
7696
7697 if (e->kind == XPR_STMTLIST
7698 || e->kind == XPR_COMMA || e->kind == XPR_COND)
7699 {
7700 exprNode first = exprData_getPairA (e->edata);
7701
7702 if (exprNode_isDefined (first))
7703 {
7704 return (exprNode_unparseFirst (exprData_getPairA (e->edata)));
7705 }
7706 else
7707 {
7708 return (cstring_makeLiteralTemp ("..."));
7709 }
7710 }
7711
7712 ret = cstring_elide (exprNode_unparse (e), 20);
7713 cstring_markOwned (ret);
7714
7715 return (ret);
7716 }
7717 else
7718 {
7719 return cstring_makeLiteralTemp ("<error>");
7720 }
7721}
7722
7723/*@observer@*/ cstring
7724exprNode_unparse (exprNode e)
7725{
7726 if (exprNode_isError (e))
7727 {
7728 return cstring_makeLiteralTemp ("<error>");
7729 }
7730
7731 if (cstring_isDefined (e->etext))
7732 {
7733 return e->etext;
7734 }
7735 else
7736 {
7737 cstring ret = exprNode_doUnparse (e);
7738
7739 /*@-modifies@*/ /* benevolent */
7740 e->etext = ret;
7741 /*@=modifies@*/
7742 return ret;
7743 }
7744}
7745
7746/*@observer@*/ fileloc
7747exprNode_loc (exprNode e)
7748{
7749 if (exprNode_isError (e))
7750 {
7751 return (g_currentloc);
7752 }
7753 else
7754 {
7755 return (e->loc);
7756 }
7757}
7758
7759/*
7760** executes exprNode e
7761** recursively rexecutes as though in original parse using
7762** information in e->edata
7763*/
7764
7765static /*@only@*/ exprNodeList exprNodeList_effect (exprNodeList e)
7766{
7767 exprNodeList ret = exprNodeList_new ();
7768
7769 exprNodeList_elements (e, current)
7770 {
7771 exprNodeList_addh (ret, exprNode_effect (current));
7772 } end_exprNodeList_elements;
7773
7774 return ret;
7775}
7776
7777static /*@only@*/ exprNode exprNode_effect (exprNode e)
7778 /*@globals internalState@*/
7779{
7780 bool innerEffect = inEffect;
7781 exprNode ret;
7782 exprData data;
7783
7784 inEffect = TRUE;
7785
7786 context_clearJustPopped ();
7787
7788 if (exprNode_isError (e))
7789 {
7790 ret = exprNode_undefined;
7791 }
7792 else
7793 {
7794 /*
7795 ** Turn off expose and dependent transfer checking.
7796 ** Need to pass exposed internal nodes,
7797 ** [ copying would be a waste! ]
7798 ** [ Actually, I think I wasted a lot more time than its worth ]
7799 ** [ trying to do this. ]
7800 */
7801
7802 /*@-exposetrans@*/
7803 /*@-observertrans@*/
7804 /*@-dependenttrans@*/
7805
7806 data = e->edata;
7807
7808 switch (e->kind)
7809 {
7810 case XPR_PARENS:
7811 ret = exprNode_addParens (exprData_getUopTok (data),
7812 exprNode_effect (exprData_getUopNode (data)));
7813 break;
7814 case XPR_ASSIGN:
7815 ret = exprNode_assign (exprNode_effect (exprData_getOpA (data)),
7816 exprNode_effect (exprData_getOpB (data)),
7817 exprData_getOpTok (data));
7818 break;
7819 case XPR_INITBLOCK:
7820 ret = exprNode_undefined;
7821 break;
7822 case XPR_CALL:
7823 ret = exprNode_functionCall (exprNode_effect (exprData_getFcn (data)),
7824 exprNodeList_effect (exprData_getArgs (data)));
7825 break;
7826 case XPR_EMPTY:
7827 ret = e;
7828 break;
7829
7830 case XPR_LABEL:
7831 ret = e;
7832 break;
7833
7834 case XPR_CONST:
7835 case XPR_VAR:
7836 {
7837 cstring id = exprData_getId (data);
7838 uentry ue = usymtab_lookupSafe (id);
7839
7840 ret = exprNode_fromIdentifierAux (ue);
7841 ret->loc = fileloc_update (ret->loc, e->loc);
7842 break;
7843 }
7844 case XPR_BODY:
7845 ret = e;
7846 break;
7847 case XPR_FETCH:
7848 ret = exprNode_arrayFetch (exprNode_effect (exprData_getPairA (data)),
7849 exprNode_effect (exprData_getPairB (data)));
7850 break;
7851 case XPR_OP:
7852 ret = exprNode_op (exprNode_effect (exprData_getOpA (data)),
7853 exprNode_effect (exprData_getOpB (data)),
7854 exprData_getOpTok (data));
7855 break;
7856
7857 case XPR_POSTOP:
7858 ret = exprNode_postOp (exprNode_effect (exprData_getUopNode (data)),
7859 exprData_getUopTok (data));
7860 break;
7861 case XPR_PREOP:
7862 ret = exprNode_preOp (exprNode_effect (exprData_getUopNode (data)),
7863 exprData_getUopTok (data));
7864 break;
7865
7866 case XPR_OFFSETOF:
7867 case XPR_SIZEOFT:
7868 case XPR_SIZEOF:
7869 case XPR_ALIGNOFT:
7870 case XPR_ALIGNOF:
7871 ret = e;
7872 break;
7873
7874 case XPR_VAARG:
7875 ret = exprNode_vaArg (exprData_getCastTok (data),
7876 exprNode_effect (exprData_getCastNode (data)),
7877 exprData_getCastType (data));
7878 break;
7879
7880 case XPR_CAST:
7881 ret = exprNode_cast (exprData_getCastTok (data),
7882 exprNode_effect (exprData_getCastNode (data)),
7883 exprData_getCastType (data));
7884 break;
7885 case XPR_ITERCALL:
7886 ret = exprNode_iterStart (exprData_getIterCallIter (data),
7887 exprNodeList_effect
7888 (exprData_getIterCallArgs (data)));
7889 break;
7890
7891 case XPR_ITER:
7892 ret = exprNode_iter (exprData_getIterSname (data),
7893 exprNodeList_effect (exprData_getIterAlist (data)),
7894 exprNode_effect (exprData_getIterBody (data)),
7895 exprData_getIterEname (data));
7896 break;
7897
7898 case XPR_FOR:
7899 ret = exprNode_for (exprNode_effect (exprData_getPairA (data)),
7900 exprNode_effect (exprData_getPairB (data)));
7901 break;
7902
7903 case XPR_FORPRED:
7904 ret = exprNode_forPred (exprNode_effect (exprData_getTripleInit (data)),
7905 exprNode_effect (exprData_getTripleTest (data)),
7906 exprNode_effect (exprData_getTripleInc (data)));
7907 break;
7908
7909 case XPR_TOK:
7910 ret = exprNode_createTok (exprData_getTok (data));
7911 break;
7912
7913 case XPR_GOTO:
7914 ret = exprNode_goto (exprData_getLiteral (data));
7915 ret->loc = fileloc_update (ret->loc, e->loc);
7916 break;
7917
7918 case XPR_CONTINUE:
7919 ret = exprNode_continue (exprData_getTok (data), QSAFEBREAK);
7920 break;
7921
7922 case XPR_BREAK:
7923 ret = exprNode_break (exprData_getTok (data), QSAFEBREAK);
7924 break;
7925
7926 case XPR_RETURN:
7927 ret = exprNode_return (exprNode_effect (exprData_getSingle (data)));
7928 break;
7929
7930 case XPR_NULLRETURN:
7931 ret = exprNode_nullReturn (exprData_getTok (data));
7932 break;
7933
7934 case XPR_COMMA:
7935 ret = exprNode_comma (exprNode_effect (exprData_getPairA (data)),
7936 exprNode_effect (exprData_getPairB (data)));
7937 break;
7938
7939 case XPR_COND:
7940 ret = exprNode_cond (exprNode_effect (exprData_getTriplePred (data)),
7941 exprNode_effect (exprData_getTripleTrue (data)),
7942 exprNode_effect (exprData_getTripleFalse (data)));
7943 break;
7944 case XPR_IF:
7945 ret = exprNode_if (exprNode_effect (exprData_getPairA (data)),
7946 exprNode_effect (exprData_getPairB (data)));
7947 break;
7948
7949 case XPR_IFELSE:
7950 ret = exprNode_ifelse (exprNode_effect (exprData_getTriplePred (data)),
7951 exprNode_effect (exprData_getTripleTrue (data)),
7952 exprNode_effect (exprData_getTripleFalse (data)));
7953 break;
7954 case XPR_WHILEPRED:
7955 ret = exprNode_whilePred (exprData_getSingle (data));
7956 break;
7957
7958 case XPR_WHILE:
7959 ret = exprNode_while (exprNode_effect (exprData_getPairA (data)),
7960 exprNode_effect (exprData_getPairB (data)));
7961 break;
7962
7963 case XPR_DOWHILE:
7964 ret = exprNode_doWhile (exprNode_effect (exprData_getPairA (data)),
7965 exprNode_effect (exprData_getPairB (data)));
7966 break;
7967
7968 case XPR_BLOCK:
7969 ret = exprNode_makeBlock (exprNode_effect (exprData_getSingle (data)));
7970 break;
7971
7972 case XPR_STMT:
7973 ret = exprNode_statement (exprNode_effect (exprData_getUopNode (data)),
7974 exprData_getUopTok (data));
7975 break;
7976
7977 case XPR_STMTLIST:
7978 ret = exprNode_concat (exprNode_effect (exprData_getPairA (data)),
7979 exprNode_effect (exprData_getPairB (data)));
7980 break;
7981
7982 case XPR_FTCASE:
7983 case XPR_CASE:
7984 ret = exprNode_caseMarker
7985 (exprNode_effect (exprData_getSingle (data)),
7986 TRUE);
7987 break;
7988
7989 case XPR_FTDEFAULT:
7990 case XPR_DEFAULT:
7991 ret = exprNode_createTok (exprData_getTok (data));
7992 break;
7993
7994 case XPR_SWITCH:
7995 ret = exprNode_switch (exprNode_effect (exprData_getPairA (data)),
7996 exprNode_effect (exprData_getPairB (data)));
7997 break;
7998
7999 case XPR_INIT:
8000 ret = exprNode_makeInitialization
8001 (exprData_getInitId (data),
8002 exprNode_effect (exprData_getInitNode (data)));
8003 break;
8004
8005 case XPR_FACCESS:
8006 ret = exprNode_fieldAccess (exprNode_effect (exprData_getFieldNode (data)),
8007 cstring_copy (exprData_getFieldName (data)));
8008 break;
8009
8010 case XPR_ARROW:
8011 ret = exprNode_arrowAccess (exprNode_effect (exprData_getFieldNode (data)),
8012 cstring_copy (exprData_getFieldName (data)));
8013 break;
8014
8015 case XPR_STRINGLITERAL:
8016 ret = e;
8017 break;
8018
8019 case XPR_NUMLIT:
8020 ret = e;
8021 break;
8022
8023 case XPR_NODE:
8024 ret = e;
8025 break;
8026 /*@-branchstate@*/
8027 }
8028 /*@=branchstate@*/
8029 /*@=observertrans@*/
8030 /*@=exposetrans@*/
8031 /*@=dependenttrans@*/
8032 }
8033
8034 if (!innerEffect)
8035 {
8036 inEffect = FALSE;
8037 }
8038
8039 return ret;
8040}
8041
8042static /*@observer@*/ cstring exprNode_rootVarName (exprNode e)
8043{
8044 cstring ret;
8045 exprData data;
8046
8047 if (exprNode_isError (e))
8048 {
8049 return cstring_undefined;
8050 }
8051
8052 data = e->edata;
8053
8054 switch (e->kind)
8055 {
8056 case XPR_PARENS:
8057 ret = exprNode_rootVarName (exprData_getUopNode (data));
8058 break;
8059 case XPR_ASSIGN:
8060 ret = exprNode_rootVarName (exprData_getOpA (data));
8061 break;
8062 case XPR_CONST:
8063 case XPR_VAR:
8064 ret = exprData_getId (data);
8065 break;
8066 case XPR_LABEL:
8067 case XPR_TOK:
8068 case XPR_ITERCALL:
8069 case XPR_EMPTY:
8070 case XPR_CALL:
8071 case XPR_INITBLOCK:
8072 case XPR_BODY:
8073 case XPR_FETCH:
8074 case XPR_OP:
8075 case XPR_POSTOP:
8076 case XPR_PREOP:
8077 case XPR_OFFSETOF:
8078 case XPR_ALIGNOFT:
8079 case XPR_ALIGNOF:
8080 case XPR_SIZEOFT:
8081 case XPR_SIZEOF:
8082 case XPR_VAARG:
8083 case XPR_CAST:
8084 case XPR_ITER:
8085 case XPR_FOR:
8086 case XPR_FORPRED:
8087 case XPR_BREAK:
8088 case XPR_RETURN:
8089 case XPR_NULLRETURN:
8090 case XPR_COMMA:
8091 case XPR_COND:
8092 case XPR_IF:
8093 case XPR_IFELSE:
8094 case XPR_WHILE:
8095 case XPR_WHILEPRED:
8096 case XPR_DOWHILE:
8097 case XPR_GOTO:
8098 case XPR_CONTINUE:
8099 case XPR_FTDEFAULT:
8100 case XPR_DEFAULT:
8101 case XPR_SWITCH:
8102 case XPR_FTCASE:
8103 case XPR_CASE:
8104 case XPR_BLOCK:
8105 case XPR_STMT:
8106 case XPR_STMTLIST:
8107 case XPR_INIT:
8108 case XPR_FACCESS:
8109 case XPR_ARROW:
8110 case XPR_NODE:
8111 case XPR_NUMLIT:
8112 case XPR_STRINGLITERAL:
8113 ret = cstring_undefined;
8114 break;
8115 }
8116
8117 return ret;
8118}
8119
8120
8121static /*@only@*/ cstring exprNode_doUnparse (exprNode e)
8122{
8123 cstring ret;
8124 exprData data;
8125
8126 if (exprNode_isError (e))
8127 {
8128 static /*@only@*/ cstring error = cstring_undefined;
8129
8130 if (!cstring_isDefined (error))
8131 {
8132 error = cstring_makeLiteral ("<error>");
8133 }
8134
8135 return error;
8136 }
8137
8138 data = e->edata;
8139
8140 switch (e->kind)
8141 {
8142 case XPR_PARENS:
8143 ret = message ("(%s)", exprNode_unparse (exprData_getUopNode (e->edata)));
8144 break;
8145 case XPR_ASSIGN:
8146 ret = message ("%s %s %s",
8147 exprNode_unparse (exprData_getOpA (data)),
8148 lltok_unparse (exprData_getOpTok (data)),
8149 exprNode_unparse (exprData_getOpB (data)));
8150 break;
8151 case XPR_CALL:
8152 ret = message ("%s(%q)",
8153 exprNode_unparse (exprData_getFcn (data)),
8154 exprNodeList_unparse (exprData_getArgs (data)));
8155 break;
8156 case XPR_INITBLOCK:
8157 ret = message ("{ %q }", exprNodeList_unparse (exprData_getArgs (data)));
8158 break;
8159 case XPR_EMPTY:
8160 ret = cstring_undefined;
8161 break;
8162 case XPR_LABEL:
8163 ret = message ("%s:", exprData_getId (data));
8164 break;
8165 case XPR_CONST:
8166 case XPR_VAR:
8167 ret = cstring_copy (exprData_getId (data));
8168 break;
8169 case XPR_FETCH:
8170 ret = message ("%s[%s]", exprNode_unparse (exprData_getPairA (data)),
8171 exprNode_unparse (exprData_getPairB (data)));
8172 break;
8173 case XPR_BODY:
8174 ret = message ("<body>");
8175 break;
8176 case XPR_OP:
8177 ret = message ("%s %s %s",
8178 exprNode_unparse (exprData_getOpA (data)),
8179 lltok_unparse (exprData_getOpTok (data)),
8180 exprNode_unparse (exprData_getOpB (data)));
8181 break;
8182
8183 case XPR_PREOP:
8184 ret = message ("%s%s",
8185 lltok_unparse (exprData_getUopTok (data)),
8186 exprNode_unparse (exprData_getUopNode (data)));
8187 break;
8188
8189 case XPR_POSTOP:
8190 ret = message ("%s%s",
8191 exprNode_unparse (exprData_getUopNode (data)),
8192 lltok_unparse (exprData_getUopTok (data)));
8193 break;
8194
8195 case XPR_OFFSETOF:
8196 ret = message ("offsetof(%s,%q)",
8197 ctype_unparse (qtype_getType (exprData_getOffsetType (data))),
8198 cstringList_unparseSep (exprData_getOffsetName (data), cstring_makeLiteralTemp (".")));
8199 break;
8200
8201 case XPR_SIZEOFT:
8202 ret = message ("sizeof(%s)", ctype_unparse (qtype_getType (exprData_getType (data))));
8203 break;
8204
8205 case XPR_SIZEOF:
8206 ret = message ("sizeof(%s)", exprNode_unparse (exprData_getSingle (data)));
8207 break;
8208
8209 case XPR_ALIGNOFT:
8210 ret = message ("alignof(%s)", ctype_unparse (qtype_getType (exprData_getType (data))));
8211 break;
8212
8213 case XPR_ALIGNOF:
8214 ret = message ("alignof(%s)", exprNode_unparse (exprData_getSingle (data)));
8215 break;
8216
8217 case XPR_VAARG:
8218 ret = message ("va_arg(%s, %q)",
8219 exprNode_unparse (exprData_getCastNode (data)),
8220 qtype_unparse (exprData_getCastType (data)));
8221 break;
8222
8223 case XPR_ITERCALL:
8224 ret = message ("%q(%q)",
8225 uentry_getName (exprData_getIterCallIter (data)),
8226 exprNodeList_unparse (exprData_getIterCallArgs (data)));
8227 break;
8228 case XPR_ITER:
8229 ret = message ("%q(%q) %s %q",
8230 uentry_getName (exprData_getIterSname (data)),
8231 exprNodeList_unparse (exprData_getIterAlist (data)),
8232 exprNode_unparse (exprData_getIterBody (data)),
8233 uentry_getName (exprData_getIterEname (data)));
8234 break;
8235 case XPR_CAST:
8236 ret = message ("(%q)%s",
8237 qtype_unparse (exprData_getCastType (data)),
8238 exprNode_unparse (exprData_getCastNode (data)));
8239 break;
8240
8241 case XPR_FOR:
8242 ret = message ("%s %s",
8243 exprNode_unparse (exprData_getPairA (data)),
8244 exprNode_unparse (exprData_getPairB (data)));
8245 break;
8246
8247 case XPR_FORPRED:
8248 ret = message ("for (%s; %s; %s)",
8249 exprNode_unparse (exprData_getTripleInit (data)),
8250 exprNode_unparse (exprData_getTripleTest (data)),
8251 exprNode_unparse (exprData_getTripleInc (data)));
8252 break;
8253
8254 case XPR_GOTO:
8255 ret = message ("goto %s", exprData_getLiteral (data));
8256 break;
8257
8258 case XPR_CONTINUE:
8259 ret = cstring_makeLiteral ("continue");
8260 break;
8261
8262 case XPR_BREAK:
8263 ret = cstring_makeLiteral ("break");
8264 break;
8265
8266 case XPR_RETURN:
8267 ret = message ("return %s", exprNode_unparse (exprData_getSingle (data)));
8268 break;
8269
8270 case XPR_NULLRETURN:
8271 ret = cstring_makeLiteral ("return");
8272 break;
8273
8274 case XPR_COMMA:
8275 ret = message ("%s, %s",
8276 exprNode_unparse (exprData_getPairA (data)),
8277 exprNode_unparse (exprData_getPairB (data)));
8278 break;
8279
8280 case XPR_COND:
8281 ret = message ("%s ? %s : %s",
8282 exprNode_unparse (exprData_getTriplePred (data)),
8283 exprNode_unparse (exprData_getTripleTrue (data)),
8284 exprNode_unparse (exprData_getTripleFalse (data)));
8285 break;
8286 case XPR_IF:
8287 ret = message ("if (%s) %s",
8288 exprNode_unparse (exprData_getPairA (data)),
8289 exprNode_unparse (exprData_getPairB (data)));
8290 break;
8291
8292 case XPR_IFELSE:
8293 ret = message ("if (%s) %s else %s",
8294 exprNode_unparse (exprData_getTriplePred (data)),
8295 exprNode_unparse (exprData_getTripleTrue (data)),
8296 exprNode_unparse (exprData_getTripleFalse (data)));
8297 break;
8298 case XPR_WHILE:
8299 ret = message ("while (%s) %s",
8300 exprNode_unparse (exprData_getPairA (data)),
8301 exprNode_unparse (exprData_getPairB (data)));
8302 break;
8303
8304 case XPR_WHILEPRED:
8305 ret = cstring_copy (exprNode_unparse (exprData_getSingle (data)));
8306 break;
8307
8308 case XPR_TOK:
8309 ret = cstring_copy (lltok_unparse (exprData_getTok (data)));
8310 break;
8311
8312 case XPR_DOWHILE:
8313 ret = message ("do { %s } while (%s)",
8314 exprNode_unparse (exprData_getPairB (data)),
8315 exprNode_unparse (exprData_getPairA (data)));
8316 break;
8317
8318 case XPR_BLOCK:
8319 ret = message ("{ %s }", exprNode_unparseFirst (exprData_getSingle (data)));
8320 break;
8321
8322 case XPR_STMT:
8323 ret = cstring_copy (exprNode_unparse (exprData_getUopNode (data)));
8324 break;
8325
8326 case XPR_STMTLIST:
8327 ret = message ("%s; %s",
8328 exprNode_unparse (exprData_getPairA (data)),
8329 exprNode_unparse (exprData_getPairB (data)));
8330 break;
8331
8332 case XPR_FTDEFAULT:
8333 case XPR_DEFAULT:
8334 ret = cstring_makeLiteral ("default:");
8335 break;
8336
8337 case XPR_SWITCH:
8338 ret = message ("switch (%s) %s",
8339 exprNode_unparse (exprData_getPairA (data)),
8340 exprNode_unparse (exprData_getPairB (data)));
8341 break;
8342
8343 case XPR_FTCASE:
8344 case XPR_CASE:
8345 ret = message ("case %s:",
8346 exprNode_unparse (exprData_getSingle (data)));
8347 break;
8348
8349 case XPR_INIT:
8350 ret = message ("%s = %s",
8351 idDecl_getName (exprData_getInitId (data)),
8352 exprNode_unparse (exprData_getInitNode (data)));
8353 break;
8354
8355 case XPR_FACCESS:
8356 ret = message ("%s.%s",
8357 exprNode_unparse (exprData_getFieldNode (data)),
8358 exprData_getFieldName (data));
8359 break;
8360
8361 case XPR_ARROW:
8362 ret = message ("%s->%s",
8363 exprNode_unparse (exprData_getFieldNode (data)),
8364 exprData_getFieldName (data));
8365 break;
8366
8367 case XPR_STRINGLITERAL:
8368 ret = cstring_copy (exprData_getLiteral (data));
8369 break;
8370
8371 case XPR_NUMLIT:
8372 ret = cstring_copy (exprData_getLiteral (data));
8373 break;
8374
8375 case XPR_NODE:
8376 ret = cstring_makeLiteral ("<node>");
8377 break;
8378 }
8379
8380 return ret;
8381}
8382
8383bool
8384exprNode_isCharLit (exprNode e)
8385{
8386 if (exprNode_isDefined (e))
8387 {
8388 return (multiVal_isChar (exprNode_getValue (e)));
8389 }
8390 else
8391 {
8392 return FALSE;
8393 }
8394}
8395
8396bool
8397exprNode_isNumLit (exprNode e)
8398{
8399 if (exprNode_isDefined (e))
8400 {
8401 return (multiVal_isInt (exprNode_getValue (e)));
8402 }
8403 else
8404 {
8405 return FALSE;
8406 }
8407}
8408
8409static bool
8410exprNode_isFalseConstant (exprNode e)
8411{
8412 if (exprNode_isDefined (e))
8413 {
8414 cstring s = exprNode_rootVarName (e);
8415
8416 if (cstring_equal (s, context_getFalseName ()))
8417 {
8418 return TRUE;
8419 }
8420 }
8421
8422 return FALSE;
8423}
8424
8425bool
8426exprNode_matchLiteral (ctype expected, exprNode e)
8427{
8428 if (exprNode_isDefined (e))
8429 {
8430 multiVal m = exprNode_getValue (e);
8431
8432 if (multiVal_isDefined (m))
8433 {
8434 if (multiVal_isInt (m))
8435 {
8436 long int val = multiVal_forceInt (m);
8437
8438 if (ctype_isDirectBool (ctype_realishType (expected)))
8439 {
8440 if (val == 0)
8441 {
8442 return FALSE; /* really?! return TRUE; allow use of 0 for FALSE */
8443 }
8444 else
8445 {
8446 return FALSE;
8447 }
8448 }
8449
8450 if (ctype_isRealInt (expected))
8451 {
8452 /*
8453 ** unsigned <- [ constant >= 0 is okay ]
8454 */
8455
8456 if (ctype_isUnsigned (expected))
8457 {
8458 if (val < 0)
8459 {
8460 return FALSE;
8461 }
8462 }
8463
8464 /*
8465 ** No checks on sizes of integers...maybe add
8466 ** these later.
8467 */
8468
8469 DPRINTF (("Here: %s => %s", exprNode_unparse (e), ctype_unparse (expected)));
8470 DPRINTF (("Type: %s / %s", ctype_unparse (exprNode_getType (e)),
8471 bool_unparse (ctype_isInt (exprNode_getType (e)))));
8472
8473 if (context_getFlag (FLG_NUMLITERAL)
8474 && (ctype_isRegularInt (exprNode_getType (e)) || val == 0)) {
8475 return TRUE;
8476 } else {
8477 if (val == 0) {
8478 return TRUE;
8479 } else {
8480 return FALSE; /* evs 2000-05-17: previously, always returned TRUE */
8481 }
8482 }
8483 }
8484 else if (ctype_isChar (expected))
8485 {
8486 return FALSE;
8487 }
8488 else if (ctype_isArrayPtr (expected))
8489 {
8490 return (val == 0);
8491 }
8492 else if (ctype_isAnyFloat (expected))
8493 {
8494 return (context_getFlag (FLG_NUMLITERAL));
8495 }
8496 else
8497 {
8498 return FALSE;
8499 }
8500 }
8501 else if (multiVal_isDouble (m))
8502 {
8503 if (ctype_isAnyFloat (expected))
8504 {
8505 return TRUE;
8506 }
8507 }
8508 else if (multiVal_isChar (m))
8509 {
8510 char val = multiVal_forceChar (m);
8511
8512 if (ctype_isChar (expected))
8513 {
8514 if (ctype_isUnsigned (expected) && ((int)val) < 0)
8515 {
8516 return FALSE;
8517 }
8518 else
8519 {
8520 return TRUE;
8521 }
8522 }
8523 }
8524 else
8525 {
8526 return FALSE;
8527 }
8528 }
8529 }
8530
8531 return FALSE;
8532}
8533
8534bool
8535exprNode_matchType (ctype expected, exprNode e)
8536{
8537 ctype actual;
8538
8539 if (!exprNode_isDefined (e)) return TRUE;
8540
8541 actual = ctype_realishType (exprNode_getType (e));
8542
8543 if (ctype_match (ctype_realishType (expected), actual))
8544 {
8545 return TRUE;
8546 }
8547
8548 llassert (!exprNode_isError (e));
8549 return (exprNode_matchLiteral (expected, e));
8550}
8551
8552static bool
8553exprNode_matchTypes (exprNode e1, exprNode e2)
8554{
8555 ctype t1;
8556 ctype t2;
8557
8558 if (!exprNode_isDefined (e1)) return TRUE;
8559 if (!exprNode_isDefined (e2)) return TRUE;
8560
8561 /*
8562 ** realish type --- keep bools, bools
8563 */
8564
8565 t1 = ctype_realishType (exprNode_getType (e1));
8566 t2 = ctype_realishType (exprNode_getType (e2));
8567
8568 if (ctype_match (t1, t2))
8569 {
8570 return TRUE;
8571 }
8572
8573 return (exprNode_matchLiteral (t1, e2) || exprNode_matchLiteral (t2, e1));
8574}
8575
8576/*
8577** pass e as ct
8578*/
8579
8580static bool
8581 exprNode_matchArgType (ctype ct, exprNode e)
8582{
8583 ctype et;
8584
8585 if (!exprNode_isDefined (e))
8586 {
8587 return TRUE;
8588 }
8589
8590 et = ctype_realType (exprNode_getType (e));
8591
8592 if (ctype_matchArg (ct, et)) return TRUE;
8593
8594 llassert (!exprNode_isError (e));
8595 return (exprNode_matchLiteral (ct, e));
8596}
8597
8598static /*@only@*/ exprNodeSList
8599 exprNode_flatten (/*@dependent@*/ exprNode e) /*@*/
8600{
8601 if (exprNode_isDefined (e))
8602 {
8603 if (e->kind == XPR_STMTLIST)
8604 {
8605 return (exprNodeSList_append
8606 (exprNode_flatten (exprData_getPairA (e->edata)),
8607 exprNode_flatten (exprData_getPairB (e->edata))));
8608 }
8609 else if (e->kind == XPR_BLOCK)
8610 {
8611 return (exprNode_flatten (exprData_getSingle (e->edata)));
8612 }
8613 else
8614 {
8615 return (exprNodeSList_singleton (e));
8616 }
8617 }
8618
8619 return exprNodeSList_new ();
8620}
8621
8622static /*@exposed@*/ exprNode
8623exprNode_lastStatement (/*@returned@*/ exprNode e)
8624{
8625 if (exprNode_isDefined (e))
8626 {
8627 if (e->kind == XPR_STMTLIST)
8628 {
8629 exprNode b = exprData_getPairB (e->edata);
8630
8631 if (exprNode_isDefined (b))
8632 {
8633 return exprNode_lastStatement (b);
8634 }
8635 else
8636 {
8637 return exprNode_lastStatement (exprData_getPairA (e->edata));
8638 }
8639 }
8640 else if (e->kind == XPR_BLOCK)
8641 {
8642 return (exprNode_lastStatement (exprData_getSingle (e->edata)));
8643 }
8644 else
8645 {
8646 return (e);
8647 }
8648 }
8649
8650 return exprNode_undefined;
8651}
8652
8653static /*@exposed@*/ exprNode
8654exprNode_firstStatement (/*@returned@*/ exprNode e)
8655{
8656 if (exprNode_isDefined (e))
8657 {
8658 if (e->kind == XPR_STMTLIST)
8659 {
8660 exprNode b = exprData_getPairA (e->edata);
8661
8662 if (exprNode_isDefined (b))
8663 {
8664 return exprNode_firstStatement (b);
8665 }
8666 else
8667 {
8668 return exprNode_firstStatement (exprData_getPairB (e->edata));
8669 }
8670 }
8671 else if (e->kind == XPR_BLOCK)
8672 {
8673 return (exprNode_firstStatement (exprData_getSingle (e->edata)));
8674 }
8675 else
8676 {
8677 return (e);
8678 }
8679 }
8680
8681 return exprNode_undefined;
8682}
8683
8684static void
8685exprNode_mergeUSs (exprNode res, exprNode other)
8686{
8687 if (exprNode_isDefined (res) && exprNode_isDefined (other))
8688 {
8689 res->msets = sRefSet_union (res->msets, other->msets);
8690 res->sets = sRefSet_union (res->sets, other->sets);
8691 res->uses = sRefSet_union (res->uses, other->uses);
8692 }
8693}
8694
8695static void
8696exprNode_mergeCondUSs (exprNode res, exprNode other1, exprNode other2)
8697{
8698 if (exprNode_isDefined (res))
8699 {
8700 if (exprNode_isDefined (other1))
8701 {
8702 res->sets = sRefSet_union (res->sets, other1->sets);
8703 res->msets = sRefSet_union (res->msets, other1->msets);
8704 res->uses = sRefSet_union (res->uses, other1->uses);
8705 }
8706 if (exprNode_isDefined (other2))
8707 {
8708 res->sets = sRefSet_union (res->sets, other2->sets);
8709 res->msets = sRefSet_union (res->msets, other2->msets);
8710 res->uses = sRefSet_union (res->uses, other2->uses);
8711 }
8712 }
8713}
8714
8715/*
8716** modifies e->uses
8717**
8718** Reports errors is s is not defined.
8719*/
8720
8721static void
8722exprNode_addUse (exprNode e, sRef s)
8723{
8724 if (exprNode_isDefined (e))
8725 {
8726 e->uses = sRefSet_insert (e->uses, s);
8727 }
8728}
8729
8730void
8731exprNode_checkUse (exprNode e, sRef s, fileloc loc)
8732{
8733 if (sRef_isKnown (s) && !sRef_isConst (s))
8734 {
8735 /*
8736 ** need to check all outer types are useable
8737 */
8738
8739 DPRINTF (("Check use: %s / %s",
8740 exprNode_unparse (e), sRef_unparse (s)));
8741
8742 exprNode_addUse (e, s);
8743
8744 if (!context_inProtectVars ())
8745 {
8746 /*
8747 ** only report the deepest error
8748 */
8749
8750 sRef errorRef = sRef_undefined;
8751 sRef lastRef = sRef_undefined;
8752 bool deadRef = FALSE;
8753 bool unuseable = FALSE;
8754 bool errorMaybe = FALSE;
8755
8756 while (sRef_isValid (s) && sRef_isKnown (s))
8757 {
8758 ynm readable = sRef_isReadable (s);
8759
8760 if (!(ynm_toBoolStrict (readable)))
8761 {
8762 if (ynm_isMaybe (readable))
8763 {
8764 lastRef = errorRef;
8765 errorRef = s;
8766 deadRef = sRef_isPossiblyDead (errorRef);
8767 unuseable = sRef_isUnuseable (errorRef);
8768 errorMaybe = TRUE;
8769 }
8770 else
8771 {
8772 lastRef = errorRef;
8773 errorRef = s;
8774 deadRef = sRef_isDead (errorRef);
8775 unuseable = sRef_isUnuseable (errorRef);
8776 errorMaybe = FALSE;
8777 }
8778
8779 if (!sRef_isPartial (s))
8780 {
8781 sRef_setDefined (s, fileloc_undefined);
8782 }
8783 }
8784
8785 s = sRef_getBaseSafe (s);
8786 } /* end while */
8787
8788 if (sRef_isValid (errorRef))
8789 {
8790 if (sRef_isValid (lastRef) && sRef_isField (lastRef)
8791 && sRef_isPointer (errorRef))
8792 {
8793 errorRef = lastRef;
8794 }
8795
8796 if (deadRef)
8797 {
8798 if (sRef_isThroughArrayFetch (errorRef))
8799 {
8800 if (optgenerror
8801 (FLG_STRICTUSERELEASED,
8802 message ("%q %q may be used after being released",
8803 sRef_unparseKindNamePlain (errorRef),
8804 sRef_unparse (errorRef)),
8805 loc))
8806 {
8807 sRef_showRefKilled (errorRef);
8808
8809 if (sRef_isKept (errorRef))
8810 {
8811 sRef_clearAliasState (errorRef, loc);
8812 }
8813 }
8814 }
8815 else
8816 {
8817 DPRINTF (("HERE: %s", sRef_unparse (errorRef)));
8818
8819 if (optgenerror
8820 (FLG_USERELEASED,
8821 message ("%q %q %qused after being released",
8822 sRef_unparseKindNamePlain (errorRef),
8823 sRef_unparse (errorRef),
8824 cstring_makeLiteral (errorMaybe
8825 ? "may be " : "")),
8826 loc))
8827 {
8828 sRef_showRefKilled (errorRef);
8829
8830 if (sRef_isKept (errorRef))
8831 {
8832 sRef_clearAliasState (errorRef, loc);
8833 }
8834 }
8835 }
8836 }
8837 else if (unuseable)
8838 {
8839 if (optgenerror
8840 (FLG_USEDEF,
8841 message ("%q %q%qused in inconsistent state",
8842 sRef_unparseKindName (errorRef),
8843 sRef_unparseOpt (errorRef),
8844 cstring_makeLiteral (errorMaybe ? "may be " : "")),
8845 loc))
8846 {
8847 sRef_showStateInconsistent (errorRef);
8848 }
8849 }
8850 else
8851 {
8852 DPRINTF (("HERE: %s", sRef_unparse (errorRef)));
8853
8854 voptgenerror
8855 (FLG_USEDEF,
8856 message ("%q %q%qused before definition",
8857 sRef_unparseKindName (errorRef),
8858 sRef_unparseOpt (errorRef),
8859 cstring_makeLiteral (errorMaybe ? "may be " : "")),
8860 loc);
8861 }
8862
8863 sRef_setDefined (errorRef, loc);
8864
8865 if (sRef_isAddress (errorRef))
8866 {
8867 sRef_setDefined (sRef_getRootBase (errorRef), loc);
8868 }
8869 } /* end is error */
8870 }
8871 }
8872
8873 setCodePoint ();
8874}
8875
8876static void
8877checkSafeUse (exprNode e, sRef s)
8878{
8879 if (exprNode_isDefined (e) && sRef_isKnown (s))
8880 {
8881 e->uses = sRefSet_insert (e->uses, s);
8882 }
8883}
8884
8885static void
8886exprNode_checkSetAny (exprNode e, /*@dependent@*/ cstring name)
8887{
8888 if (exprNode_isDefined (e))
8889 {
8890 e->sets = sRefSet_insert (e->sets, sRef_makeUnconstrained (name));
8891 }
8892}
8893
8894void
8895exprNode_checkSet (exprNode e, sRef s)
8896{
8897 sRef defines = sRef_undefined;
8898
8899 if (sRef_isValid (s) && !sRef_isNothing (s))
8900 {
8901 uentry ue = sRef_getBaseUentry (s);
8902
8903 if (uentry_isValid (ue))
8904 {
8905 uentry_setLset (ue);
8906 }
8907
8908 if (!ynm_toBoolStrict (sRef_isWriteable (s)))
8909 {
8910 voptgenerror (FLG_USEDEF,
8911 message ("Attempt to set unuseable storage: %q",
8912 sRef_unparse (s)),
8913 exprNode_loc (e));
8914 }
8915
8916 if (sRef_isMeaningful (s))
8917 {
8918
8919 if (sRef_isDead (s))
8920 {
8921 sRef base = sRef_getBaseSafe (s);
8922
8923 if (sRef_isValid (base)
8924 && sRef_isDead (base))
8925 {
8926 sRef_setPartial (s, exprNode_loc (e));
8927 }
8928
8929 defines = s; /* okay - modifies for only param */
8930 }
8931 else if (sRef_isPartial (s))
8932 {
8933 sRef eref = exprNode_getSref (e);
8934
8935 if (!sRef_isPartial (eref))
8936 {
8937 /*
8938 ** should do something different here???
8939 */
8940
8941 sRef_setDefinedComplete (eref, exprNode_loc (e));
8942 }
8943 else
8944 {
8945 sRef_setPartialDefinedComplete (eref, exprNode_loc (e));
8946 }
8947
8948 if (sRef_isMeaningful (eref))
8949 {
8950 defines = eref;
8951 }
8952 else
8953 {
8954 defines = s;
8955 }
8956 }
8957 else if (sRef_isAllocated (s))
8958 {
8959 sRef eref = exprNode_getSref (e);
8960
8961
8962 if (!sRef_isAllocated (eref))
8963 {
8964 sRef_setDefinedComplete (eref, exprNode_loc (e));
8965 }
8966 else
8967 {
8968 sRef base = sRef_getBaseSafe (eref);
8969
8970 if (sRef_isValid (base))
8971 {
8972 sRef_setPdefined (base, exprNode_loc (e));
8973 }
8974 }
8975
8976 defines = s;
8977 }
8978 else
8979 {
8980 sRef_setDefinedNCComplete (s, exprNode_loc (e));
8981 defines = s;
8982 }
8983
8984 }
8985 else /* not meaningful...but still need to insert it */
8986 {
8987 defines = s;
8988 }
8989 }
8990
8991 if (exprNode_isDefined (e) && sRef_isValid (defines))
8992 {
8993 e->sets = sRefSet_insert (e->sets, defines);
8994 }
8995}
8996
8997void
8998exprNode_checkMSet (exprNode e, sRef s)
8999{
9000 if (sRef_isValid (s) && !sRef_isNothing (s))
9001 {
9002 uentry ue = sRef_getBaseUentry (s);
9003
9004 if (uentry_isValid (ue))
9005 {
9006 uentry_setLset (ue);
9007 }
9008
9009 if (!ynm_toBoolStrict (sRef_isWriteable (s)))
9010 {
9011 voptgenerror (FLG_USEDEF,
9012 message ("Attempt to set unuseable storage: %q", sRef_unparse (s)),
9013 exprNode_loc (e));
9014 }
9015
9016 if (sRef_isMeaningful (s))
9017 {
9018 sRef_setDefinedComplete (s, exprNode_loc (e));
9019 }
9020
9021 if (exprNode_isDefined (e))
9022 {
9023 e->msets = sRefSet_insert (e->msets, s);
9024 }
9025 }
9026}
9027
9028static void
9029checkUnspecCall (/*@notnull@*/ /*@dependent@*/ exprNode fcn, uentryList params, exprNodeList args)
9030{
9031 checkAnyCall (fcn, cstring_undefined, params, args,
9032 FALSE, sRefSet_undefined, FALSE, 0);
9033}
9034
9035static void
9036checkOneArg (uentry ucurrent, /*@notnull@*/ exprNode current,
9037 /*@dependent@*/ exprNode fcn, bool isSpec, int argno, int totargs)
9038{
9039 setCodePoint ();
9040
9041 if (uentry_isYield (ucurrent))
9042 {
9043 sRef_setDefined (exprNode_getSref (current), exprNode_loc (current));
9044 exprNode_checkSet (current, current->sref);
9045 }
9046 else
9047 {
9048 if (uentry_isSefParam (ucurrent))
9049 {
9050 sRefSet sets = current->sets;
9051 sRef ref = exprNode_getSref (current);
9052
9053 if (sRef_isMacroParamRef (ref))
9054 {
9055 uentry ue = sRef_getUentry (ref);
9056
9057 if (!uentry_isSefParam (ue))
9058 {
9059 voptgenerror
9060 (FLG_SEFPARAMS,
9061 message
9062 ("Parameter %d to %s is declared sef, but "
9063 "the argument is a macro parameter declared "
9064 "without sef: %s",
9065 argno, exprNode_unparse (fcn),
9066 exprNode_unparse (current)),
9067 exprNode_loc (current));
9068 }
9069 }
9070
9071 if (!sRefSet_isEmpty (sets))
9072 {
9073 sRefSet reported = sRefSet_undefined;
9074
9075 sRefSet_realElements (current->sets, el)
9076 {
9077 if (sRefSet_isSameNameMember (reported, el))
9078 {
9079 ; /* don't report again */
9080 }
9081 else
9082 {
9083 if (sRef_isUnconstrained (el))
9084 {
9085 voptgenerror
9086 (FLG_SEFUNSPEC,
9087 message
9088 ("Parameter %d to %s is declared sef, but "
9089 "the argument calls unconstrained function %s "
9090 "(no guarantee it will not modify something): %s",
9091 argno, exprNode_unparse (fcn),
9092 sRef_unconstrainedName (el),
9093 exprNode_unparse (current)),
9094 exprNode_loc (current));
9095 }
9096 else
9097 {
9098 voptgenerror
9099 (FLG_SEFPARAMS,
9100 message
9101 ("Parameter %d to %s is declared sef, but "
9102 "the argument may modify %q: %s",
9103 argno, exprNode_unparse (fcn),
9104 sRef_unparse (el),
9105 exprNode_unparse (current)),
9106 exprNode_loc (current));
9107 }
9108 }
9109 } end_sRefSet_realElements;
9110 }
9111 }
9112
9113 checkPassTransfer (current, ucurrent, isSpec, fcn, argno, totargs);
9114 exprNode_mergeUSs (fcn, current);
9115 }
9116}
9117
9118static void
9119 checkAnyCall (/*@dependent@*/ exprNode fcn,
9120 /*@dependent@*/ cstring fname,
9121 uentryList pn,
9122 exprNodeList args,
9123 bool hasMods, sRefSet mods,
9124 bool isSpec,
9125 int specialArgs)
9126{
9127 int paramno = 0;
9128 int nargs = exprNodeList_size (args);
9129
9130 setCodePoint ();
9131
9132 /*
9133 ** concat all args ud's to f, add each arg sref as a use unless
9134 ** it was specified as "out", in which case it is a def.
9135 */
9136
9137 uentryList_reset (pn);
9138
9139 /*
9140 ** aliasing checks:
9141 **
9142 ** if paramn is only or unique, no other arg may alias argn
9143 */
9144
9145 exprNodeList_elements (args, current)
9146 {
9147 paramno++;
9148
9149 if (exprNode_isDefined (current))
9150 {
9151 if ((!uentryList_isUndefined (pn) && !uentryList_isFinished (pn)))
9152 {
9153 uentry ucurrent = uentryList_current (pn);
9154
9155 if (specialArgs == 0
9156 || (paramno < specialArgs))
9157 {
9158 checkOneArg (ucurrent, current, fcn, isSpec, paramno, nargs);
9159
9160 if (context_maybeSet (FLG_ALIASUNIQUE))
9161 {
9162 if (uentry_isOnly (ucurrent)
9163 || uentry_isUnique (ucurrent))
9164 {
9165 checkUniqueParams (fcn, current, args,
9166 paramno, ucurrent);
9167 }
9168 }
9169 }
9170 }
9171 else /* uentry is undefined */
9172 {
9173 if (specialArgs == 0)
9174 {
9175 exprNode_checkUseParam (current);
9176 }
9177
9178 exprNode_mergeUSs (fcn, current);
9179 }
9180 }
9181 uentryList_advanceSafe (pn);
9182 } end_exprNodeList_elements;
9183
9184 if (hasMods)
9185 {
9186 setCodePoint ();
9187
9188 sRefSet_allElements (mods, s)
9189 {
9190 sRef fb;
9191 sRef rb = sRef_getRootBase (s);
9192
9193 if (sRef_isGlobal (rb))
9194 {
9195 context_usedGlobal (rb);
9196 }
9197
9198 fb = sRef_fixBaseParam (s, args);
9199
9200 if (!sRef_isMacroParamRef (fb))
9201 {
9202 if (sRef_isNothing (fb))
9203 {
9204 ;
9205 }
9206 else
9207 {
9208 if (sRef_isValid (fb))
9209 {
9210 uentry ue = sRef_getBaseUentry (s);
9211
9212 if (uentry_isValid (ue))
9213 {
9214 uentry_setLset (ue);
9215 }
9216 }
9217
9218 fcn->sets = sRefSet_insert (fcn->sets, fb);
9219 }
9220 }
9221 sRef_clearDerivedComplete (s);
9222 } end_sRefSet_allElements;
9223
9224 setCodePoint ();
9225 }
9226 else
9227 {
9228 if (context_hasMods ())
9229 {
9230 if (context_maybeSet (FLG_MODUNCON))
9231 {
9232 voptgenerror
9233 (FLG_MODUNCON,
9234 message ("Undetected modification possible "
9235 "from call to unconstrained function %s: %s",
9236 fname,
9237 exprNode_unparse (fcn)),
9238 exprNode_loc (fcn));
9239 }
9240 }
9241 else
9242 {
9243 if (context_maybeSet (FLG_MODUNCONNOMODS)
9244 && !(context_inIterDef () || context_inIterEnd ()))
9245 {
9246 voptgenerror
9247 (FLG_MODUNCONNOMODS,
9248 message ("Undetected modification possible "
9249 "from call to unconstrained function %s: %s",
9250 fname,
9251 exprNode_unparse (fcn)),
9252 exprNode_loc (fcn));
9253 }
9254 }
9255
9256 exprNode_checkSetAny (fcn, fname);
9257 }
9258}
9259
9260void exprNode_checkUseParam (exprNode current)
9261{
9262 if (exprNode_isDefined (current))
9263 {
9264 exprNode_checkUse (current, current->sref, current->loc);
9265 }
9266}
9267
9268static ctype
9269 checkNumerics (ctype tr1, ctype tr2, ctype te1, ctype te2,
9270 /*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2,
9271 lltok op)
9272{
9273 ctype ret = tr1;
9274
9275 if (!ctype_match (tr1, tr2))
9276 {
9277 if ((ctype_isRealInt (tr1) || ctype_isReal (tr1)) &&
9278 (ctype_isRealInt (tr2) || ctype_isReal (tr2)))
9279 {
9280 ;
9281 }
9282 else
9283 {
9284 (void) gentypeerror
9285 (tr1, e1, tr2, e2,
9286 message ("Incompatible types for %s (%s, %s): %s %s %s",
9287 lltok_unparse (op),
9288 ctype_unparse (te1),
9289 ctype_unparse (te2),
9290 exprNode_unparse (e1), lltok_unparse (op),
9291 exprNode_unparse (e2)),
9292 e1->loc);
9293 }
9294 ret = ctype_unknown;
9295 }
9296 else
9297 {
9298 if (ctype_isForceRealNumeric (&tr1) && ctype_isForceRealNumeric (&tr2))
9299 {
9300 ret = ctype_resolveNumerics (tr1, tr2);
9301 }
9302 else if (!context_msgStrictOps ())
9303 {
9304 if (ctype_isPointer (tr1))
9305 {
9306 if (ctype_isPointer (tr2) && !exprNode_isNullValue (e2))
9307 {
9308 ret = ctype_int;
9309 }
9310 else if (ctype_isInt (tr2))
9311 {
9312 ret = te1;
9313 }
9314 else
9315 {
9316 ret = ctype_unknown;
9317 }
9318 }
9319 else if (ctype_isPointer (tr2))
9320 {
9321 if (ctype_isPointer (tr1))
9322 {
9323 ret = ctype_int;
9324 }
9325 else if (ctype_isInt (tr1))
9326 {
9327 ret = te2;
9328 }
9329 else
9330 {
9331 ret = ctype_unknown;
9332 }
9333 }
9334 else
9335 {
9336 ret = ctype_resolveNumerics (tr1, tr2);
9337 }
9338 }
9339 else
9340 {
9341 int opid = lltok_getTok (op);
9342 bool comparop = (opid == EQ_OP || opid == NE_OP
9343 || opid == TLT || opid == TGT
9344 || opid == LE_OP || opid == GE_OP);
9345
9346 if (!ctype_isNumeric (tr1) && !ctype_isNumeric (tr2))
9347 {
9348 if (comparop
9349 && ((ctype_isEnum (tr1) && ctype_isEnum (tr2))
9350 || (ctype_isBool (tr1) && ctype_isBool (tr2))
9351 || (ctype_isChar (tr1) && ctype_isChar (tr2))))
9352 {
9353 ; /* no error */
9354 }
9355 else
9356 {
9357 if (ctype_sameName (te1, te2))
9358 {
9359 voptgenerror
9360 (FLG_STRICTOPS,
9361 message ("Operands of %s are non-numeric (%t): %s %s %s",
9362 lltok_unparse (op), te1,
9363 exprNode_unparse (e1), lltok_unparse (op),
9364 exprNode_unparse (e2)),
9365 e1->loc);
9366 }
9367 else
9368 {
9369 voptgenerror
9370 (FLG_STRICTOPS,
9371 message ("Operands of %s are non-numerics (%t, %t): %s %s %s",
9372 lltok_unparse (op), te1, te2,
9373 exprNode_unparse (e1), lltok_unparse (op),
9374 exprNode_unparse (e2)),
9375 e1->loc);
9376 }
9377 }
9378 }
9379 else if (!ctype_isNumeric (tr1))
9380 {
9381 voptgenerror
9382 (FLG_STRICTOPS,
9383 message ("Right operand of %s is non-numeric (%t): %s %s %s",
9384 lltok_unparse (op), te1,
9385 exprNode_unparse (e1), lltok_unparse (op),
9386 exprNode_unparse (e2)),
9387 e1->loc);
9388 }
9389 else
9390 {
9391 if (!ctype_isNumeric (tr2))
9392 {
9393 voptgenerror
9394 (FLG_STRICTOPS,
9395 message ("Left operand of %s is non-numeric (%t): %s %s %s",
9396 lltok_unparse (op), te2,
9397 exprNode_unparse (e1), lltok_unparse (op),
9398 exprNode_unparse (e2)),
9399 e2->loc);
9400 }
9401 }
9402
9403 ret = ctype_unknown;
9404 }
9405 }
9406
9407 return ret;
9408}
9409
9410static void
9411abstractOpError (ctype tr1, ctype tr2, lltok op,
9412 /*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2,
9413 fileloc loc1, fileloc loc2)
9414{
9415 if (ctype_isRealAbstract (tr1) && ctype_isRealAbstract (tr2))
9416 {
9417 if (ctype_match (tr1, tr2))
9418 {
9419 voptgenerror
9420 (FLG_ABSTRACT,
9421 message ("Operands of %s are abstract type (%t): %s %s %s",
9422 lltok_unparse (op), tr1,
9423 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
9424 loc1);
9425 }
9426 else
9427 {
9428 voptgenerror
9429 (FLG_ABSTRACT,
9430 message ("Operands of %s are abstract types (%t, %t): %s %s %s",
9431 lltok_unparse (op), tr1, tr2,
9432 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
9433 loc1);
9434 }
9435 }
9436 else if (ctype_isRealAbstract (tr1))
9437 {
9438 voptgenerror
9439 (FLG_ABSTRACT,
9440 message ("Left operand of %s is abstract type (%t): %s %s %s",
9441 lltok_unparse (op), tr1,
9442 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
9443 loc1);
9444 }
9445 else
9446 {
9447 if (ctype_isRealAbstract (tr2))
9448 {
9449 voptgenerror
9450 (FLG_ABSTRACT,
9451 message ("Right operand of %s is abstract type (%t): %s %s %s",
9452 lltok_unparse (op), tr2,
9453 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
9454 loc2);
9455 }
9456 }
9457}
9458
9459/*
9460** e1 <= e2
9461**
9462** requies e1 and e2 and not error exprNode's.
9463**
9464** Checks:
9465**
9466** If e1 is a component of an abstract type, and e2 is mutable and client-visible,
9467** the rep of the abstract type is exposed.
9468**
9469** The order is very important:
9470**
9471** check rep expose (move into check transfer)
9472** check transfer
9473** setup aliases
9474*/
9475
9476/*
9477** This isn't really a sensible procedure, but the indententation
9478** was getting too deep.
9479*/
9480
9481static void
9482checkOneRepExpose (sRef ysr, sRef base,
9483 /*@notnull@*/ exprNode e1,
9484 /*@notnull@*/ exprNode e2, ctype ct,
9485 sRef s2b)
9486{
9487 if (!(sRef_isOnly (ysr) || sRef_isKeep (ysr)
9488 || sRef_isOwned (ysr) || sRef_isExposed (ysr)))
9489 {
9490 if (sRef_isAnyParam (base) && !sRef_isExposed (base))
9491 {
9492 if (sRef_isIReference (ysr))
9493 {
9494 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
9495 {
9496 voptgenerror
9497 (FLG_ASSIGNEXPOSE,
9498 message
9499 ("Assignment of mutable component of parameter %q "
9500 "to component of abstract "
9501 "type %s exposes rep: %s = %s",
9502 sRef_unparse (base),
9503 ctype_unparse (ct),
9504 exprNode_unparse (e1), exprNode_unparse (e2)),
9505 e1->loc);
9506 }
9507 else
9508 {
9509 voptgenerror
9510 (FLG_ASSIGNEXPOSE,
9511 message
9512 ("Assignment of mutable component of parameter %q "
9513 "(through alias %q) to component of abstract "
9514 "type %s exposes rep: %s = %s",
9515 sRef_unparse (base),
9516 sRef_unparse (e2->sref),
9517 ctype_unparse (ct),
9518 exprNode_unparse (e1), exprNode_unparse (e2)),
9519 e1->loc);
9520 }
9521 }
9522 else
9523 {
9524 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
9525 {
9526 voptgenerror
9527 (FLG_ASSIGNEXPOSE,
9528 message ("Assignment of mutable parameter %q "
9529 "to component of abstract type %s "
9530 "exposes rep: %s = %s",
9531 sRef_unparse (base),
9532 ctype_unparse (ct),
9533 exprNode_unparse (e1),
9534 exprNode_unparse (e2)),
9535 e1->loc);
9536 }
9537 else
9538 {
9539 voptgenerror
9540 (FLG_ASSIGNEXPOSE,
9541 message ("Assignment of mutable parameter %q "
9542 "(through alias %q) to "
9543 "component of abstract type %s exposes "
9544 "rep: %s = %s",
9545 sRef_unparse (base),
9546 sRef_unparse (e2->sref),
9547 ctype_unparse (ct),
9548 exprNode_unparse (e1),
9549 exprNode_unparse (e2)),
9550 e1->loc);
9551 }
9552 }
9553 }
9554
9555 if (sRef_isGlobal (s2b))
9556 {
9557 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
9558 {
9559 voptgenerror
9560 (FLG_REPEXPOSE,
9561 message ("Assignment of global %q "
9562 "to component of "
9563 "abstract type %s exposes rep: %s = %s",
9564 sRef_unparse (base),
9565 ctype_unparse (ct),
9566 exprNode_unparse (e1), exprNode_unparse (e2)),
9567 e1->loc);
9568 }
9569 else
9570 {
9571 voptgenerror
9572 (FLG_REPEXPOSE,
9573 message ("Assignment of global %q (through alias %q) "
9574 "to component of "
9575 "abstract type %s exposes rep: %s = %s",
9576 sRef_unparse (base),
9577 sRef_unparse (e2->sref),
9578 ctype_unparse (ct),
9579 exprNode_unparse (e1), exprNode_unparse (e2)),
9580 e1->loc);
9581 }
9582 }
9583 }
9584}
9585
9586static void
9587doAssign (/*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2, bool isInit)
9588{
9589 if (ctype_isRealFunction (exprNode_getType (e1))
9590 && !ctype_isRealPointer (exprNode_getType (e1)))
9591 {
9592 voptgenerror
9593 (FLG_TYPE,
9594 message ("Invalid left-hand side of assignment (function type %s): %s",
9595 ctype_unparse (exprNode_getType (e1)),
9596 exprNode_unparse (e1)),
9597 e1->loc);
9598 }
9599
9600 if (context_getFlag (FLG_ASSIGNEXPOSE) && ctype_isMutable (e2->typ))
9601 {
9602 ctype t2 = exprNode_getType (e2);
9603 sRef sr = sRef_getRootBase (e1->sref);
9604 ctype ct = sRef_getType (sr);
9605
9606 if (ctype_isAbstract (t2)
9607 && !(uentry_isMutableDatatype (usymtab_getTypeEntry (ctype_typeId (t2)))))
9608 {
9609 /* it is immutable, okay to reference */
9610 goto donerepexpose;
9611 }
9612
9613 if (ctype_isAbstract (ct) && sRef_isIReference (e1->sref))
9614 {
9615 sRef s2b = sRef_getRootBase (e2->sref);
9616 sRef s1 = e1->sref;
9617 sRef s1b = sRef_getRootBase (s1);
9618 sRefSet aliases;
9619
9620 aliases = usymtab_canAlias (e2->sref);
9621
9622 if (!sRef_similar (s2b, s1b)
9623 && !sRef_isExposed (s1)
9624 && !(sRef_isOnly (s2b) || sRef_isKeep (s2b) || sRef_isExposed (s2b)))
9625 {
9626 if (sRef_isAnyParam (s2b) && !sRef_isOnly (s2b)
9627 && !sRef_isOwned (s2b) && !sRef_isKeep (s2b)
9628 && !sRef_isExposed (s2b))
9629 {
9630 if (sRef_isIReference (e2->sref))
9631 {
9632 voptgenerror
9633 (FLG_ASSIGNEXPOSE,
9634 message
9635 ("Assignment of mutable component of parameter %q "
9636 "to component of abstract type %s exposes rep: %s = %s",
9637 sRef_unparse (s2b),
9638 ctype_unparse (ct),
9639 exprNode_unparse (e1), exprNode_unparse (e2)),
9640 e1->loc);
9641 }
9642 else
9643 {
9644 voptgenerror
9645 (FLG_ASSIGNEXPOSE,
9646 message ("Assignment of mutable parameter %q to "
9647 "component of abstract type %s exposes rep: %s = %s",
9648 sRef_unparse (s2b),
9649 ctype_unparse (ct),
9650 exprNode_unparse (e1), exprNode_unparse (e2)),
9651 e1->loc);
9652 }
9653 }
9654
9655 if (sRef_isGlobal (s2b))
9656 {
9657 voptgenerror
9658 (FLG_ASSIGNEXPOSE,
9659 message ("Assignment of global %q to component of "
9660 "abstract type %s exposes rep: %s = %s",
9661 sRef_unparse (s2b),
9662 ctype_unparse (ct),
9663 exprNode_unparse (e1), exprNode_unparse (e2)),
9664 e1->loc);
9665 }
9666
9667 sRefSet_realElements (aliases, ysr)
9668 {
9669 sRef base = sRef_getRootBase (ysr);
9670
9671 if (sRef_similar (ysr, s2b) || sRef_similar (s1b, base)
9672 || sRef_sameName (base, s1b))
9673 {
9674 ; /* error already reported or same sref */
9675 }
9676 else
9677 {
9678 checkOneRepExpose (ysr, base, e1, e2, ct, s2b);
9679 }
9680 } end_sRefSet_realElements;
9681 }
9682 sRefSet_free (aliases);
9683 }
9684 }
9685
9686 donerepexpose:
9687
9688 /*
9689 ** function variables don't really work...
9690 */
9691
9692 if (!ctype_isFunction (ctype_realType (e2->typ)))
9693 {
9694 if (isInit)
9695 {
9696 checkInitTransfer (e1, e2);
9697 }
9698 else
9699 {
9700 checkAssignTransfer (e1, e2);
9701 }
9702 }
9703 else
9704 {
9705 sRef fref = e2->sref;
9706
9707 sRef_setDefState (e1->sref, sRef_getDefState (fref), e1->loc);
9708 sRef_setNullState (e1->sref, sRef_getNullState (fref), e1->loc);
9709
9710 /* Need to typecheck the annotation on the parameters */
9711
9712 if (ctype_isRealFunction (e1->typ)) {
9713 uentryList e1p = ctype_argsFunction (ctype_realType (e1->typ));
9714 uentryList e2p = ctype_argsFunction (ctype_realType (e2->typ));
9715
9716 if (!uentryList_isMissingParams (e1p)
9717 && !uentryList_isMissingParams (e2p)
9718 && uentryList_size (e1p) > 0) {
9719 if (uentryList_size (e1p) == uentryList_size (e2p)) {
9720 int n = 0;
9721
9722 uentryList_elements (e1p, el1) {
9723 uentry el2;
9724
9725 el2 = uentryList_getN (e2p, n);
9726 n++;
9727 uentry_checkMatchParam (el1, el2, n, e2);
9728 } end_uentryList_elements;
9729 }
9730 }
9731 }
9732 }
9733
9734 if (isInit && sRef_isGlobal (e1->sref))
9735 {
9736 ;
9737 }
9738 else
9739 {
9740 updateAliases (e1, e2);
9741 }
dc92450f 9742 // updateEnvironment (e1, e2);
616915dd 9743}
9744
9745static void
9746checkMacroParen (exprNode e)
9747{
9748 if (exprNode_isError (e) || e->kind == XPR_CAST)
9749 {
9750 ;
9751 }
9752 else
9753 {
9754 if (sRef_isUnsafe (e->sref) && !exprNode_isInParens (e))
9755 {
9756 voptgenerror
9757 (FLG_MACROPARENS,
9758 message ("Macro parameter used without parentheses: %s",
9759 exprNode_unparse (e)),
9760 e->loc);
9761 }
9762 }
9763}
9764
9765static void
9766reflectNullTest (/*@notnull@*/ exprNode e, bool isnull)
9767{
9768 if (isnull)
9769 {
9770 e->guards = guardSet_addTrueGuard (e->guards, e->sref);
9771 }
9772 else
9773 {
9774 e->guards = guardSet_addFalseGuard (e->guards, e->sref);
9775 }
9776}
9777
9778/*
9779** e1 <= e2
9780**
9781** if e2 is a parameter or global derived location which
9782** can be modified (that is, e2 is a mutable abstract type,
9783** or a derived pointer), then e1 can alias e2.
9784**
9785** e1 can alias everything which e2 can alias.
9786**
9787** Also, if e1 is guarded, remove from guard sets!
9788*/
9789
9790static void updateAliases (/*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2)
9791{
9792 if (!context_inProtectVars ())
9793 {
9794 /*
9795 ** depends on types of e1 and e2
9796 */
9797
9798 sRef s1 = e1->sref;
9799 sRef s2 = e2->sref;
9800 ctype t1 = exprNode_getType (e1);
9801
9802 /* handle pointer sRefs, record fields, arrays, etc... */
9803
9804 if (!ctype_isRealSU (t1))
9805 {
9806 sRef_copyRealDerivedComplete (s1, s2);
9807 }
9808
9809 if (ctype_isMutable (t1) && sRef_isKnown (s1))
9810 {
9811 usymtab_clearAlias (s1);
9812 usymtab_addMustAlias (s1, s2);
9813 }
9814
9815 if (sRef_possiblyNull (s1) && usymtab_isGuarded (s1))
9816 {
9817 usymtab_unguard (s1);
9818 }
9819 }
9820}
9821
9822exprNode exprNode_updateLocation (/*@returned@*/ exprNode e, /*@temp@*/ fileloc loc)
9823{
9824 if (exprNode_isDefined (e))
9825 {
9826 e->loc = fileloc_update (e->loc, loc);
9827 }
9828 else
9829 {
9830 e = exprNode_createLoc (ctype_unknown, fileloc_copy (loc));
9831 }
9832
9833 return (e);
9834}
9835
9836static void checkUniqueParams (exprNode fcn,
9837 /*@notnull@*/ exprNode current,
9838 exprNodeList args,
9839 int paramno, uentry ucurrent)
9840{
9841 int iparamno = 0;
9842 sRef thisref = exprNode_getSref (current);
9843
9844 /*
9845 ** Check if any argument could match this argument.
9846 */
9847
9848 exprNodeList_elements (args, icurrent)
9849 {
9850 iparamno++;
9851
9852 if (iparamno != paramno)
9853 {
9854 sRef sr = exprNode_getSref (icurrent);
9855
9856 if (sRef_similarRelaxed (thisref, sr))
9857 {
9858 if (!sRef_isConst (thisref) && !sRef_isConst (sr))
9859 {
9860 voptgenerror
9861 (FLG_ALIASUNIQUE,
9862 message
9863 ("Parameter %d (%s) to function %s is declared %s but "
9864 "is aliased by parameter %d (%s)",
9865 paramno,
9866 exprNode_unparse (current),
9867 exprNode_unparse (fcn),
9868 alkind_unparse (uentry_getAliasKind (ucurrent)),
9869 iparamno, exprNode_unparse (icurrent)),
9870 current->loc);
9871 }
9872 }
9873 else
9874 {
9875 sRefSet aliases = usymtab_canAlias (sr);
9876
9877 sRefSet_allElements (aliases, asr)
9878 {
9879 if (ctype_isUnknown (sRef_getType (thisref)))
9880 {
9881 sRef_setType (thisref, uentry_getType (ucurrent));
9882 }
9883
9884 if (sRef_similarRelaxed (thisref, asr))
9885 {
9886 if (sRef_isExternal (asr))
9887 {
9888 if (sRef_isLocalState (thisref))
9889 {
9890 ; /* okay */
9891 }
9892 else
9893 {
9894 sRef base = sRef_getRootBase (asr);
9895
9896 if (!sRef_similar (sRef_getBase (asr), thisref))
9897 {
9898 if (sRef_isUnique (base) || sRef_isOnly (base)
9899 || sRef_isKept (base)
9900 || (sRef_isAddress (asr) && sRef_isLocalVar (base))
9901 || (sRef_isAddress (thisref)
9902 && sRef_isLocalVar (sRef_getRootBase (thisref))))
9903 {
9904 ; /* okay, no error */
9905 }
9906 else
9907 {
9908 voptgenerror
9909 (FLG_MAYALIASUNIQUE,
9910 message
9911 ("Parameter %d (%s) to function %s is declared %s but "
9912 "may be aliased externally by parameter %d (%s)",
9913 paramno,
9914 exprNode_unparse (current),
9915 exprNode_unparse (fcn),
9916 alkind_unparse (uentry_getAliasKind (ucurrent)),
9917 iparamno, exprNode_unparse (icurrent)),
9918 current->loc);
9919 }
9920 }
9921 }
9922 }
9923 else
9924 {
9925 voptgenerror
9926 (FLG_ALIASUNIQUE,
9927 message
9928 ("Parameter %d (%s) to function %s is declared %s but "
9929 "is aliased externally by parameter %d (%s) through "
9930 "alias %q",
9931 paramno,
9932 exprNode_unparse (current),
9933 exprNode_unparse (fcn),
9934 alkind_unparse (uentry_getAliasKind (ucurrent)),
9935 iparamno, exprNode_unparse (icurrent),
9936 sRef_unparse (asr)),
9937 current->loc);
9938 }
9939 }
9940 } end_sRefSet_allElements;
9941 sRefSet_free (aliases);
9942 }
9943 }
9944 } end_exprNodeList_elements;
9945}
9946
9947long exprNode_getLongValue (exprNode e) {
9948 long value;
9949
9950 if (exprNode_hasValue (e)
9951 && multiVal_isInt (exprNode_getValue (e)))
9952 {
9953 value = multiVal_forceInt (exprNode_getValue (e));
9954 }
9955 else
9956 {
9957 value = 0;
9958 }
9959
9960 return value;
9961}
9962
9963fileloc exprNode_getfileloc (exprNode p_e)
9964{
9965 if (p_e)
9966 return fileloc_copy ( p_e->loc );
9967 else
9968 return fileloc_undefined;
9969}
9970
9971fileloc exprNode_getNextSequencePoint (exprNode e)
9972{
9973 /*
9974 ** Returns the location of the sequence point following e.
9975 **
9976 ** Only works for statements (for now).
9977 */
9978
9979 if (exprNode_isDefined (e) && e->kind == XPR_STMT) {
9980 lltok t = exprData_getUopTok (e->edata);
9981 return lltok_getLoc (t);
9982 } else {
9983 #warning fix
9984 // llcontbug (message ("Cannot get next sequence point: %s", exprNode_unparse (e)));
9985 return fileloc_undefined;
9986 }
9987 }
9988
9989
9280addf 9990/*drl added
9991 */
9992exprNode exprNode_fakeCopy (exprNode e)
9993{
9994 /*@-temptrans@*/ /*@-retalias@*/
9995 return e;
9996 /*@=temptrans@*/ /*@=retalias@*/
9997}
9998
9999exprNode exprNode_createNew(ctype c)
10000{
10001 exprNode ret;
10002
10003 ret = exprNode_createPlain (c);
10004
10005 return ret;
10006}
This page took 1.510128 seconds and 5 git commands to generate.