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