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