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