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