Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

exprNode.c

Go to the documentation of this file.
00001 /*
00002 ** LCLint - annotation-assisted static program checker
00003 ** Copyright (C) 1994-2000 University of Virginia,
00004 **         Massachusetts Institute of Technology
00005 **
00006 ** This program is free software; you can redistribute it and/or modify it
00007 ** under the terms of the GNU General Public License as published by the
00008 ** Free Software Foundation; either version 2 of the License, or (at your
00009 ** option) any later version.
00010 ** 
00011 ** This program is distributed in the hope that it will be useful, but
00012 ** WITHOUT ANY WARRANTY; without even the implied warranty of
00013 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 ** General Public License for more details.
00015 ** 
00016 ** The GNU General Public License is available from http://www.gnu.org/ or
00017 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00018 ** MA 02111-1307, USA.
00019 **
00020 ** For information on lclint: lclint-request@cs.virginia.edu
00021 ** To report a bug: lclint-bug@cs.virginia.edu
00022 ** For more information: http://lclint.cs.virginia.edu
00023 */
00024 /*
00025 ** exprNode.c
00026 */
00027 
00028 # include <ctype.h> /* for isdigit */
00029 # include "lclintMacros.nf"
00030 # include "basic.h"
00031 # include "cgrammar.h"
00032 # include "cgrammar_tokens.h"
00033 
00034 # include "exprChecks.h"
00035 # include "aliasChecks.h"
00036 # include "exprNodeSList.h"
00037 # include "exprData.i"
00038 
00039 static bool exprNode_isEmptyStatement (exprNode p_e);
00040 static /*@exposed@*/ exprNode exprNode_firstStatement (/*@returned@*/ exprNode p_e);
00041 static bool exprNode_isFalseConstant (exprNode p_e) /*@*/ ;
00042 static bool exprNode_isBlock (exprNode p_e);
00043 static void checkGlobUse (uentry p_glob, bool p_isCall, /*@notnull@*/ exprNode p_e);
00044 static void exprNode_addUse (exprNode p_e, sRef p_s);
00045 static bool exprNode_matchArgType (ctype p_ct, exprNode p_e);
00046 static exprNode exprNode_fakeCopy (exprNode p_e) /*@*/ ;
00047 static exprNode exprNode_statementError (/*@only@*/ exprNode p_e);
00048 static bool exprNode_matchTypes (exprNode p_e1, exprNode p_e2);
00049 static void checkUniqueParams (exprNode p_fcn,
00050                                /*@notnull@*/ exprNode p_current, exprNodeList p_args, 
00051                                int p_paramno, uentry p_ucurrent);
00052 static void updateAliases (/*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2);
00053 static void abstractOpError (ctype p_tr1, ctype p_tr2, lltok p_op, 
00054                              /*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2, 
00055                              fileloc p_loc1, fileloc p_loc2);
00056 static ctype checkNumerics (ctype p_tr1, ctype p_tr2, ctype p_te1, ctype p_te2,
00057                             /*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2, lltok p_op);
00058 static void doAssign (/*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2, bool p_isInit);
00059 static void checkSafeUse (exprNode p_e, sRef p_s);
00060 static void reflectNullTest (/*@notnull@*/ exprNode p_e, bool p_isnull);
00061 static void checkMacroParen (exprNode p_e);
00062 static exprNodeSList exprNode_flatten (/*@dependent@*/ exprNode p_e);
00063 static void exprNode_checkSetAny (exprNode p_e, /*@dependent@*/ cstring p_name);
00064 static void exprNode_checkUse (exprNode p_e, sRef p_s, fileloc p_loc);
00065 static void exprNode_mergeUSs (exprNode p_res, exprNode p_other);
00066 static void exprNode_mergeCondUSs (exprNode p_res, exprNode p_other1, exprNode p_other2);
00067 static /*@only@*/ /*@notnull@*/ exprNode exprNode_fromIdentifierAux (/*@observer@*/ uentry p_c);
00068 static void checkAnyCall (/*@notnull@*/ /*@dependent@*/ exprNode p_fcn, 
00069                           /*@dependent@*/ cstring p_fname,
00070                           uentryList p_pn, exprNodeList p_args, 
00071                           bool p_hasMods, sRefSet p_mods, bool p_isSpec,
00072                           int p_specialArgs);
00073 static void checkOneArg (uentry p_ucurrent, /*@notnull@*/ exprNode p_current, 
00074                          /*@dependent@*/ exprNode p_fcn, bool p_isSpec, int p_argno, int p_totargs);
00075 static void 
00076   checkUnspecCall (/*@notnull@*/ /*@dependent@*/ exprNode p_fcn, uentryList p_params, exprNodeList p_args);
00077 
00078 static /*@only@*/ exprNode exprNode_effect (exprNode p_e)
00079   /*@globals internalState@*/ ;
00080 static /*@only@*/ cstring exprNode_doUnparse (exprNode p_e);
00081 static /*@observer@*/ cstring exprNode_rootVarName (exprNode p_e);
00082 static /*@exposed@*/ exprNode 
00083   exprNode_lastStatement (/*@returned@*/ exprNode p_e);
00084 
00085 static /*@null@*/ sRef defref = sRef_undefined;
00086 static /*@only@*/ exprNode mustExitNode = exprNode_undefined;
00087 
00088 static int checkArgsReal (uentry p_fcn, /*@dependent@*/ exprNode p_f, 
00089                           uentryList p_cl, 
00090                           exprNodeList p_args, bool p_isIter, exprNode p_ret);
00091 
00092 static bool inEffect = FALSE;
00093 static int nowalloc = 0;
00094 static int totalloc = 0;
00095 static int maxalloc = 0;
00096 
00097 static /*@only@*/ uentry regArg;
00098 static /*@only@*/ uentry outArg;
00099 static /*@only@*/ uentry outStringArg;
00100 static /*@exposed@*/ sRef stdinRef;
00101 static /*@exposed@*/ sRef stdoutRef;
00102 static /*@only@*/ uentry csArg;
00103 static /*@only@*/ uentry csOnlyArg; 
00104 static ctype cstringType;
00105 static ctype ctypeType;
00106 static ctype filelocType; 
00107 static bool initMod = FALSE;
00108 
00109 /*
00110 ** must occur after library has been read
00111 */
00112 
00113 void exprNode_initMod (void)
00114   /*@globals undef regArg, undef outArg, undef outStringArg, 
00115              undef csOnlyArg, undef csArg; 
00116    @*/
00117 {
00118   uentry ue;
00119   idDecl tmp;
00120   
00121   initMod = TRUE;
00122   cstringType = ctype_unknown;
00123   ctypeType = ctype_unknown;
00124   filelocType = ctype_unknown;
00125 
00126   defref = sRef_undefined;
00127   
00128   if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
00129     {
00130       cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
00131     }
00132  
00133   if (usymtab_existsType (cstring_makeLiteralTemp ("ctype")))
00134     {
00135       ctypeType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("ctype"));
00136     }
00137 
00138   if (usymtab_existsType (cstring_makeLiteralTemp ("fileloc")))
00139     {
00140       filelocType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("fileloc"));
00141     }
00142 
00143   if (usymtab_existsGlob (cstring_makeLiteralTemp ("stdin")))
00144     {
00145       ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stdin"));
00146     }
00147   else /* define stdin */
00148     {
00149       ue = uentry_makeVariable (cstring_makeLiteralTemp ("stdin"), 
00150                                 ctype_unknown, 
00151                                 fileloc_getBuiltin (), 
00152                                 FALSE);
00153       uentry_setHasNameError (ue); 
00154       ue = usymtab_supGlobalEntryReturn (ue);
00155     }
00156 
00157   stdinRef = sRef_makePointer (uentry_getSref (ue));
00158   
00159   if (usymtab_existsGlob (cstring_makeLiteralTemp ("stdout")))
00160     {
00161       ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stdout"));
00162     }
00163   else
00164     {
00165       ue = uentry_makeVariable (cstring_makeLiteralTemp ("stdout"), 
00166                                 ctype_unknown, 
00167                                 fileloc_getBuiltin (), 
00168                                 FALSE);
00169       uentry_setHasNameError (ue); 
00170       ue = usymtab_supGlobalEntryReturn (ue);
00171     }
00172   
00173   stdoutRef = sRef_makePointer (uentry_getSref (ue));
00174 
00175   tmp = idDecl_create (cstring_undefined, qtype_create (ctype_unknown));
00176 
00177   regArg = uentry_makeParam (tmp, PARAMUNKNOWN);
00178 
00179   idDecl_setTyp (tmp, 
00180                  qtype_addQual (qtype_create (ctype_makePointer (ctype_unknown)),
00181                                 qual_createOut ()));
00182 
00183   outArg = uentry_makeParam (tmp, PARAMUNKNOWN);
00184 
00185   idDecl_setTyp (tmp, qtype_addQual (qtype_create (ctype_string), 
00186                                      qual_createOut ()));
00187   
00188   outStringArg = uentry_makeParam (tmp, PARAMUNKNOWN);
00189   
00190   idDecl_setTyp (tmp, qtype_addQual (qtype_addQual (qtype_create (cstringType), 
00191                                                     qual_createOnly ()),
00192                                      qual_createNull ()));
00193   
00194   csOnlyArg = uentry_makeParam (tmp, PARAMUNKNOWN);
00195   
00196   idDecl_setTyp (tmp, qtype_addQual (qtype_create (cstringType), qual_createNull ()));
00197   csArg = uentry_makeParam (tmp, PARAMUNKNOWN);
00198   
00199   idDecl_free (tmp);
00200 }
00201 
00202 void
00203 exprNode_destroyMod (void) 
00204    /*@globals killed regArg, killed outArg, killed outStringArg,
00205               killed mustExitNode, initMod @*/
00206 {
00207   if (initMod)
00208     {
00209       uentry_free (regArg);
00210       uentry_free (outArg);
00211       uentry_free (outStringArg);
00212       
00213       exprNode_free (mustExitNode);
00214       initMod = FALSE;
00215     /*@-branchstate@*/ 
00216     } 
00217   /*@=branchstate@*/
00218 }
00219 
00220 static void exprNode_resetSref (/*@notnull@*/ exprNode e)
00221 {
00222   e->sref = defref;
00223 }
00224 
00225 static exprNode exprNode_fakeCopy (exprNode e)
00226 {
00227   /*@-temptrans@*/ /*@-retalias@*/
00228   return e;
00229   /*@=temptrans@*/ /*@=retalias@*/
00230 }
00231 
00232 static bool isFlagKey (char key)
00233 {
00234   return (key == '-' || key == '+' || key == ' ' || key == '#');
00235 }
00236 
00237 static void exprNode_combineControl (/*@notnull@*/ exprNode ret,
00238                                      /*@notnull@*/ exprNode ifclause,
00239                                      /*@notnull@*/ exprNode elseclause)
00240 {
00241   ret->canBreak = ifclause->canBreak || elseclause->canBreak;
00242 
00243   ret->mustBreak =
00244     (ifclause->mustBreak || exprNode_mustEscape (ifclause))
00245       && (elseclause->mustBreak || exprNode_mustEscape (elseclause));
00246 
00247   ret->exitCode = exitkind_combine (ifclause->exitCode,
00248                                     elseclause->exitCode);
00249 
00250 }
00251 
00252 /*
00253 ** For exprNode's returned by exprNode_effect.
00254 */
00255 
00256 static bool shallowKind (exprKind kind)
00257 {
00258   return (kind == XPR_STRINGLITERAL
00259           || kind == XPR_NUMLIT
00260           || kind == XPR_EMPTY
00261           || kind == XPR_BODY
00262           || kind == XPR_NODE);
00263 }
00264 
00265 static void 
00266 exprNode_freeIniter (/*@only@*/ exprNode e)
00267 {
00268   if (!exprNode_isError (e))
00269     {
00270       switch (e->kind)
00271         {
00272         case XPR_FACCESS:
00273           sfree (e->edata->field);
00274           sfree (e->edata);
00275           break;
00276         case XPR_FETCH:
00277           exprNode_free (e->edata->op->b);
00278           /*@-compdestroy@*/ sfree (e->edata->op); /*@=compdestroy@*/
00279           sfree (e->edata);
00280           break;
00281         default:
00282           llbug (message ("other: %s", exprNode_unparse (e)));
00283         }
00284 
00285       multiVal_free (e->val);
00286       cstring_free (e->etext);
00287       fileloc_free (e->loc);
00288       sRefSet_free (e->uses);
00289       sRefSet_free (e->sets);
00290       sRefSet_free (e->msets);
00291       guardSet_free (e->guards);
00292       sfree (e);
00293     }
00294 }
00295 
00296 void 
00297 exprNode_freeShallow (/*@only@*/ exprNode e)
00298 {
00299   if (!exprNode_isError (e))
00300     {
00301       if (shallowKind (e->kind))
00302         {
00303                 }
00304       else
00305         {
00306           if (!inEffect)
00307             {
00308               if (e->kind == XPR_EMPTY
00309                   || e->kind == XPR_BODY
00310                   || e->kind == XPR_STRINGLITERAL
00311                   || e->kind == XPR_NUMLIT
00312                   || e->kind == XPR_NODE
00313                   || e->kind == XPR_OFFSETOF
00314                   || e->kind == XPR_ALIGNOFT
00315                   || e->kind == XPR_ALIGNOF
00316                   || e->kind == XPR_SIZEOFT
00317                   || e->kind == XPR_SIZEOF)
00318                 {
00319                   /* don't free anything */
00320                 }
00321               else
00322                 {
00323                   /* multiVal_free (e->val);  */
00324                   cstring_free (e->etext);
00325                   fileloc_free (e->loc);
00326                   sRefSet_free (e->uses);
00327                   sRefSet_free (e->sets);
00328                   sRefSet_free (e->msets);
00329                   guardSet_free (e->guards);
00330                   exprData_freeShallow (e->edata, e->kind); 
00331                   nowalloc--;
00332                   /*@-compdestroy@*/ sfree (e); /*@=compdestroy@*/
00333                   /*@-branchstate@*/
00334                 }
00335             }
00336         } /*@=branchstate@*/
00337     }
00338   }
00339 
00340 void
00341 exprNode_free (exprNode e)
00342 {
00343   if (!exprNode_isError (e))
00344     {
00345       if (!inEffect)
00346         {
00347           multiVal_free (e->val);
00348           cstring_free (e->etext);
00349           fileloc_free (e->loc);
00350           sRefSet_free (e->uses);
00351           sRefSet_free (e->sets);
00352           sRefSet_free (e->msets);
00353           guardSet_free (e->guards);
00354           exprData_free (e->edata, e->kind);
00355           
00356           nowalloc--;
00357           sfree (e);
00358           /*@-branchstate@*/ 
00359         } /*@=branchstate@*/
00360     }
00361 }
00362 
00363 exprNode
00364 exprNode_makeError ()
00365 {
00366   return exprNode_undefined;
00367 }
00368 
00369 static /*@out@*/ /*@only@*/ /*@notnull@*/ exprNode
00370 exprNode_new (void)
00371 {
00372   exprNode ret = (exprNode) dmalloc (sizeof (*ret));
00373   /* static int lastexpnodes = 0; */
00374 
00375   nowalloc++;
00376   totalloc++;
00377 
00378   if (nowalloc > maxalloc)
00379     {
00380       maxalloc = nowalloc;
00381     }
00382 
00383   return ret;
00384 }
00385 
00386 static /*@notnull@*/ /*@special@*/ exprNode
00387   exprNode_createPlain (ctype c) 
00388   /*@defines result@*/
00389   /*@post:isnull result->edata, result->loc, result->val, result->guards,
00390                  result->uses, result->sets, result->msets, result->etext @*/
00391   /*@*/
00392 {
00393   exprNode e = exprNode_new ();
00394 
00395   e->typ = c;
00396   e->kind = XPR_EMPTY;
00397   e->val = multiVal_undefined;
00398   e->sref = defref;
00399   e->etext = cstring_undefined;
00400   e->loc = fileloc_undefined;
00401   e->guards = guardSet_undefined;
00402   e->uses = sRefSet_undefined;
00403   e->sets = sRefSet_undefined;
00404   e->msets = sRefSet_undefined;
00405   e->edata = exprData_undefined;
00406   e->exitCode = XK_NEVERESCAPE;
00407   e->canBreak = FALSE;
00408   e->mustBreak = FALSE;
00409   e->isJumpPoint = FALSE;
00410   return (e);
00411 }
00412 
00413 /*@observer@*/ exprNode exprNode_makeMustExit (void)
00414 {
00415   if (exprNode_isUndefined (mustExitNode))
00416     {
00417       mustExitNode = exprNode_createPlain (ctype_unknown);
00418       mustExitNode->exitCode = XK_MUSTEXIT;
00419     }
00420 
00421   return mustExitNode;
00422 }
00423 
00424 
00425 static /*@notnull@*/ /*@special@*/ exprNode exprNode_create (ctype c)
00426   /*@defines result@*/
00427   /*@post:isnull result->edata, result->guards, result->val,
00428                  result->uses, result->sets, result->msets@*/
00429   /*@*/
00430 {
00431   exprNode e = exprNode_createPlain (c);
00432   e->loc = fileloc_copy (g_currentloc);
00433   return (e);
00434 }
00435 
00436 static /*@notnull@*/ /*@special@*/ exprNode exprNode_createUnknown (void)
00437   /*@defines result@*/
00438   /*@post:isnull result->edata, result->guards,
00439                  result->uses, result->sets, result->msets@*/
00440   /*@*/
00441 {
00442   return (exprNode_create (ctype_unknown));
00443 }
00444 
00445 static /*@notnull@*/ /*@special@*/ exprNode
00446   exprNode_createLoc (ctype c, /*@keep@*/ fileloc loc)
00447   /*@defines result@*/
00448   /*@post:isnull result->edata, result->guards, result->val,
00449                  result->uses, result->sets, result->msets@*/
00450   /*@*/
00451 {
00452   exprNode e = exprNode_createPlain (c);
00453   e->loc = loc;
00454   return (e);
00455 }
00456 
00457 static void 
00458   exprNode_copySets (/*@special@*/ /*@notnull@*/ exprNode ret, exprNode e)
00459   /*@defines ret->guards, ret->uses, ret->sets, ret->msets@*/
00460 {
00461   if (exprNode_isDefined (e))
00462     {
00463       ret->guards = guardSet_copy (e->guards);
00464       ret->uses = sRefSet_newCopy (e->uses);
00465       ret->sets = sRefSet_newCopy (e->sets);
00466       ret->msets = sRefSet_newCopy (e->msets); 
00467     }
00468   else
00469     {
00470       ret->guards = guardSet_undefined;
00471       ret->uses = sRefSet_undefined;
00472       ret->sets = sRefSet_undefined;
00473       ret->msets = sRefSet_undefined;
00474     }
00475 }
00476 
00477 static /*@notnull@*/ /*@special@*/ exprNode
00478   exprNode_createPartialLocCopy (exprNode e, /*@only@*/ fileloc loc)
00479   /*@defines result@*/
00480   /*@post:isnull result->edata, result->etext@*/
00481   /*@*/
00482 {
00483   exprNode ret = exprNode_new ();
00484 
00485   if (exprNode_isError (e))
00486     {
00487       ret->typ = ctype_unknown;
00488       ret->val = multiVal_undefined;
00489       ret->loc = loc;
00490       ret->guards = guardSet_undefined;
00491       ret->uses = sRefSet_undefined;
00492       ret->sets = sRefSet_undefined;
00493       ret->msets = sRefSet_undefined;
00494     }
00495   else
00496     {
00497       ret->typ = e->typ;
00498       ret->val = multiVal_copy (e->val);
00499       ret->loc = loc;
00500       ret->guards = guardSet_copy (e->guards);
00501       ret->uses = sRefSet_newCopy (e->uses);
00502       ret->sets = sRefSet_newCopy (e->sets);
00503       ret->msets = sRefSet_newCopy (e->msets); 
00504     }
00505 
00506   ret->kind = XPR_EMPTY;
00507   ret->sref = defref;
00508   ret->etext = cstring_undefined;
00509   ret->exitCode = XK_NEVERESCAPE;
00510   ret->canBreak = FALSE;
00511   ret->mustBreak = FALSE;
00512   ret->isJumpPoint = FALSE;
00513   ret->edata = exprData_undefined;
00514 
00515   return (ret);
00516 }
00517 
00518 
00519 static /*@notnull@*/ /*@special@*/ exprNode
00520   exprNode_createPartialCopy (exprNode e)
00521   /*@defines result@*/
00522   /*@post:isnull result->edata, result->etext@*/
00523   /*@*/
00524 {
00525   return (exprNode_createPartialLocCopy (e, fileloc_copy (exprNode_loc (e))));
00526 }
00527 
00528 static /*@notnull@*/ /*@special@*/ exprNode
00529   exprNode_createPartialNVCopy (exprNode e)
00530   /*@defines result@*/
00531   /*@post:isnull result->edata, result->etext, result->val @*/
00532   /*@*/
00533 {
00534   exprNode ret = exprNode_new ();
00535 
00536   if (exprNode_isError (e))
00537     {
00538       ret->typ = ctype_unknown;
00539       ret->loc = fileloc_undefined;
00540       ret->guards = guardSet_undefined;
00541       ret->uses = sRefSet_undefined;
00542       ret->sets = sRefSet_undefined;
00543       ret->msets = sRefSet_undefined;
00544     }
00545   else
00546     {
00547       ret->typ = e->typ;
00548       ret->loc = fileloc_copy (e->loc);
00549       ret->guards = guardSet_copy (e->guards);
00550       ret->uses = sRefSet_newCopy (e->uses);
00551       ret->sets = sRefSet_newCopy (e->sets);
00552       ret->msets = sRefSet_newCopy (e->msets); 
00553     }
00554   
00555   ret->val = multiVal_undefined;
00556   ret->kind = XPR_EMPTY;
00557   ret->sref = defref;
00558   ret->etext = cstring_undefined;
00559   ret->exitCode = XK_NEVERESCAPE;
00560   ret->canBreak = FALSE;
00561   ret->mustBreak = FALSE;
00562   ret->isJumpPoint = FALSE;
00563   ret->edata = exprData_undefined;
00564 
00565   return (ret);
00566 }
00567 
00568 static /*@notnull@*/ /*@special@*/ exprNode
00569   exprNode_createSemiCopy (exprNode e)
00570   /*@defines result@*/
00571   /*@post:isnull result->edata, result->etext, result->sets,
00572                  result->msets, result->uses, result->guards@*/
00573   /*@*/
00574 {
00575   if (exprNode_isError (e))
00576     {
00577       return exprNode_createPlain (ctype_unknown);
00578     }
00579   else
00580     {
00581       exprNode ret = exprNode_new ();
00582 
00583       ret->typ = e->typ;
00584       ret->val = multiVal_copy (e->val);
00585       ret->loc = fileloc_copy (e->loc);
00586       ret->guards = guardSet_undefined;
00587       ret->uses = sRefSet_undefined;
00588       ret->sets = sRefSet_undefined;
00589       ret->msets = sRefSet_undefined;
00590 
00591       ret->kind = XPR_EMPTY;
00592       ret->sref = defref;
00593       ret->etext = cstring_undefined;
00594       ret->exitCode = XK_NEVERESCAPE;
00595       ret->canBreak = FALSE;
00596       ret->mustBreak = FALSE;
00597       ret->isJumpPoint = FALSE;
00598       ret->edata = exprData_undefined;
00599       
00600       return (ret);
00601     }
00602 }
00603 
00604 bool
00605 exprNode_isNullValue (exprNode e)
00606 {
00607   if (exprNode_isDefined (e))
00608     {
00609       multiVal m = exprNode_getValue (e);
00610       
00611       if (multiVal_isInt (m))
00612         {
00613           return (multiVal_forceInt (m) == 0);
00614         }
00615     }
00616   
00617   return FALSE;
00618 }
00619 
00620 static bool
00621 exprNode_isUnknownConstant (/*@notnull@*/ exprNode e)
00622 {
00623   while (e->kind == XPR_PARENS)
00624     {
00625       e = exprData_getUopNode (e->edata);
00626       llassert (exprNode_isDefined (e));
00627     }
00628 
00629   if (e->kind == XPR_CONST)
00630     {
00631       multiVal m = exprNode_getValue (e);
00632 
00633       if (multiVal_isUnknown (m)) 
00634         {
00635           return TRUE;
00636         }
00637     }
00638   
00639   return FALSE;
00640 }
00641 
00642 /*@only@*/ exprNode
00643   exprNode_numLiteral (ctype c, /*@temp@*/ cstring t, 
00644                        /*@only@*/ fileloc loc, long val)
00645 {
00646   exprNode e = exprNode_createLoc (c, loc);
00647 
00648   e->kind = XPR_NUMLIT;
00649   
00650   llassert (multiVal_isUndefined (e->val));
00651   e->val = multiVal_makeInt (val);
00652   e->edata = exprData_makeLiteral (cstring_copy (t));
00653 
00654   if (val == 0)
00655     {
00656       e->sref = sRef_makeUnknown ();
00657       sRef_setDefNull (e->sref, e->loc);
00658     }
00659 
00660   DPRINTF (("Num lit: %s / %s", exprNode_unparse (e), ctype_unparse (exprNode_getType (e))));
00661   return (e);
00662 }
00663 
00664 /*@only@*/ exprNode
00665 exprNode_charLiteral (char c, cstring text, /*@only@*/ fileloc loc)
00666 {
00667   exprNode e = exprNode_createLoc (ctype_char, loc);
00668 
00669   if (context_getFlag (FLG_CHARINTLITERAL))
00670     {
00671       e->typ = ctype_makeConj (ctype_char, ctype_int);
00672     }
00673 
00674   e->kind = XPR_NUMLIT;
00675   e->val = multiVal_makeChar (c);
00676 
00677   e->edata = exprData_makeLiteral (cstring_copy (text));
00678   return (e);
00679 }
00680 
00681 /*@only@*/ exprNode
00682 exprNode_floatLiteral (double d, ctype ct, cstring text, /*@only@*/ fileloc loc)
00683 {
00684   exprNode e = exprNode_createLoc (ct, loc);
00685 
00686   e->kind = XPR_NUMLIT;
00687     e->val = multiVal_makeDouble (d);
00688   e->edata = exprData_makeLiteral (cstring_copy (text));
00689   return (e);
00690 }
00691 
00692 multiVal exprNode_getValue (exprNode e) 
00693 {
00694   while (exprNode_isInParens (e)) {
00695     if (e->edata != NULL) {
00696       e = exprData_getUopNode (e->edata);
00697     } else {
00698       break;
00699     }
00700   }
00701 
00702   if (exprNode_isDefined (e)) {
00703     return e->val; 
00704   } else {
00705     return multiVal_undefined;
00706   }
00707 }
00708 
00709 /*@only@*/ exprNode
00710 exprNode_stringLiteral (/*@only@*/ cstring t, /*@only@*/ fileloc loc)
00711 {
00712   exprNode e = exprNode_createLoc (ctype_string, loc);
00713   int len = cstring_length (t) - 2;
00714   char *ts = cstring_toCharsSafe (t);
00715   char *s = cstring_toCharsSafe (cstring_create (len + 1));
00716 
00717   if (context_getFlag (FLG_STRINGLITERALLEN))
00718     {
00719       if (len > context_getValue (FLG_STRINGLITERALLEN))
00720         {
00721           voptgenerror (FLG_STRINGLITERALLEN,
00722                         message
00723                         ("String literal length (%d) exceeds maximum "
00724                          "length (%d): %s",
00725                          len,
00726                          context_getValue (FLG_STRINGLITERALLEN),
00727                          t),
00728                         e->loc);
00729         }
00730     }
00731 
00732   strncpy (s, ts+1, size_fromInt (len));
00733   *(s + len) = '\0';
00734 
00735   
00736   e->kind = XPR_STRINGLITERAL;
00737   e->val = multiVal_makeString (cstring_fromCharsO (s));
00738   e->edata = exprData_makeLiteral (t);
00739   e->sref = sRef_makeType (ctype_string);
00740 
00741   if (context_getFlag (FLG_READONLYSTRINGS))
00742     {
00743       sRef_setAliasKind (e->sref, AK_STATIC, fileloc_undefined);
00744       sRef_setExKind (e->sref, XO_OBSERVER, loc);
00745     }
00746   else
00747     {
00748       sRef_setAliasKind (e->sref, AK_ERROR, fileloc_undefined);
00749     }
00750 
00751   return (e); /* s released */
00752 }
00753 
00754 exprNode exprNode_fromUIO (cstring c)
00755 {
00756   fileloc loc = context_getSaveLocation ();
00757   exprNode e  = exprNode_createPlain (ctype_unknown);
00758 
00759   e->kind = XPR_VAR;
00760 
00761   if (fileloc_isUndefined (loc))
00762     {
00763       loc = fileloc_copy (g_currentloc);
00764     }
00765 
00766   e->loc = loc; /* save loc was mangled */
00767   e->sref = defref;
00768 
00769   if (usymtab_exists (c))
00770     {
00771       uentry ue = usymtab_lookupEither (c);
00772 
00773       if (uentry_isDatatype (ue) 
00774           && uentry_isSpecified (ue))
00775         {
00776           llfatalerror
00777             (message ("%q: Specified datatype %s used in code, but not defined. "
00778                       "(Cannot continue reasonably from this error.)",
00779                       fileloc_unparse (e->loc), c));
00780         }
00781       else
00782         {
00783           BADBRANCH; 
00784         }
00785     }
00786   
00787   llassertprint (!usymtab_exists (c), ("Entry exists: %s", c));
00788 
00789   /*
00790   ** was supercedeGlobalEntry...is this better?
00791   */
00792 
00793   if (!context_inIterEnd ())
00794     {
00795       if (context_inMacro ())
00796         {
00797           if (context_getFlag (FLG_UNRECOG))
00798             {
00799               voptgenerror 
00800                 (FLG_MACROUNDEF, 
00801                  message ("Unrecognized identifier in macro definition: %s", c), e->loc);
00802             }
00803           else
00804             {
00805               flagcode_recordSuppressed (FLG_UNRECOG);
00806             }
00807         }
00808       else
00809         {
00810           voptgenerror 
00811             (FLG_UNRECOG, message ("Unrecognized identifier: %s", c),
00812              e->loc);
00813         }
00814     }
00815   
00816   e->edata = exprData_makeId (uentry_makeUnrecognized (c, fileloc_copy (loc)));
00817 
00818   /* No alias errors for unrecognized identifiers */
00819   sRef_setAliasKind (e->sref, AK_ERROR, loc); 
00820 
00821   return (e);
00822 }
00823 
00824 exprNode exprNode_createId (/*@observer@*/ uentry c)
00825 {
00826   if (uentry_isValid (c))
00827     {
00828       exprNode e = exprNode_new ();
00829       
00830       e->typ = uentry_getType (c);
00831 
00832       if (uentry_isFunction (c)
00833           && !sRef_isLocalVar (uentry_getSref (c)))
00834         {
00835           e->sref = sRef_undefined;
00836         }
00837       else
00838         {
00839           e->sref = uentry_getSref (c); 
00840         }
00841 
00842       if (sRef_isStateUnknown (e->sref) && uentry_isNonLocal (c))
00843         {
00844           sRef_setDefined (e->sref, fileloc_undefined);
00845         }
00846       
00847       /*
00848       ** yoikes!  leaving this out was a heinous bug...that would have been
00849       ** caught if i had lclint working first.  gag!
00850       */
00851       
00852       e->etext = cstring_undefined;
00853       
00854       if (uentry_isEitherConstant (c))
00855         {
00856           e->kind = XPR_CONST;
00857           e->val = multiVal_copy (uentry_getConstantValue (c));
00858         }
00859       else
00860         {
00861           e->kind = XPR_VAR;
00862           e->val = multiVal_unknown ();
00863         }
00864       
00865       e->edata = exprData_makeId (c);
00866       e->loc = context_getSaveLocation ();
00867       
00868       if (fileloc_isUndefined (e->loc))
00869         {
00870           fileloc_free (e->loc);
00871           e->loc = fileloc_copy (g_currentloc);
00872         }
00873 
00874       e->guards = guardSet_new ();
00875       e->sets = sRefSet_new ();
00876       e->msets = sRefSet_new ();
00877       e->uses = sRefSet_new ();
00878       
00879       /*> missing fields, detected by lclint <*/
00880       e->exitCode = XK_NEVERESCAPE;
00881       e->isJumpPoint = FALSE;
00882       e->canBreak = FALSE;
00883       e->mustBreak = FALSE;
00884       
00885       return e;
00886     }
00887   else
00888     {
00889             return exprNode_createUnknown ();
00890     }
00891 }
00892 
00893 /*@notnull@*/ exprNode
00894 exprNode_fromIdentifier (/*@observer@*/ uentry c)
00895 {
00896   exprNode ret;
00897 
00898   if (context_justPopped ()) /* watch out! c could be dead */
00899     { 
00900       uentry ce = usymtab_lookupSafe (LastIdentifier ());
00901 
00902       if (uentry_isValid (ce)) 
00903         {
00904           c = ce;
00905         }
00906       else
00907         {
00908           llbuglit ("Looks like Aunt Millie forgot to walk to dog again.");
00909         }
00910     }
00911 
00912   ret = exprNode_fromIdentifierAux (c);
00913   
00914   return ret;
00915 }
00916 
00917 
00918 static /*@only@*/ /*@notnull@*/ exprNode
00919 exprNode_fromIdentifierAux (/*@observer@*/ uentry c)
00920 {
00921   exprNode e = exprNode_createId (c);
00922   sRef sr = e->sref;
00923 
00924   uentry_setUsed (c, e->loc);
00925 
00926   if (uentry_isVar (c) && sRef_isGlobal (sr))
00927     {
00928       checkGlobUse (c, FALSE, e);
00929     }
00930 
00931   return (e);
00932 }
00933 
00934 static bool
00935 exprNode_isZero (exprNode e)
00936 {
00937   if (exprNode_isDefined (e))
00938     {
00939       multiVal m = exprNode_getValue (e);
00940       
00941       if (multiVal_isInt (m))
00942         {
00943           return (multiVal_forceInt (m) == 0);
00944         }
00945     }
00946 
00947   return FALSE;
00948 }
00949 
00950 static bool
00951 exprNode_isNonNegative (exprNode e)
00952 {
00953   if (exprNode_isDefined (e))
00954     {
00955       multiVal m = exprNode_getValue (e);
00956       
00957       if (multiVal_isInt (m))
00958         {
00959           return (multiVal_forceInt (m) >= 0);
00960         }
00961     }
00962 
00963   return FALSE;
00964 }
00965 
00966 /*
00967 ** a[x]  - uses a but NOT a[] 
00968 **         result sref = a[]  (set/use in assignment)
00969 ** 
00970 ** The syntax x[a] is also legal in C, and has the same 
00971 ** semantics.  If ind is an array, and arr is an int, flip
00972 ** the arguments.
00973 */
00974 
00975 /*@only@*/ exprNode
00976 exprNode_arrayFetch (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
00977 {
00978   /*
00979   ** error in arr, error propagates (no new messages)
00980   ** error in ind, assume valid and continue
00981   */
00982 
00983   if (exprNode_isError (e1))
00984     {
00985       exprNode_free (e2);
00986       return (exprNode_makeError ());
00987     }
00988   else
00989     {
00990       exprNode arr;
00991       exprNode ind;
00992       ctype carr = exprNode_getType (e1);
00993       ctype crarr = ctype_realType (carr);
00994  
00995       /*
00996       ** this sets up funny aliasing, that leads to spurious
00997       ** lclint errors.  Hence, the i2 comments.
00998       */
00999 
01000       if (!ctype_isRealArray (crarr) 
01001           && ctype_isRealNumeric (crarr) 
01002           && !exprNode_isError (e2)
01003           && ctype_isRealAP (exprNode_getType (e2)))  /* fetch like 3[a] */
01004         {
01005           arr = e2;
01006           ind = e1;
01007 
01008           carr = exprNode_getType (arr);
01009           crarr = ctype_realType (carr);
01010         }
01011       else
01012         {
01013           arr = e1;
01014           ind = e2;
01015         }
01016 
01017       if (sRef_possiblyNull (arr->sref))
01018         {
01019           if (!usymtab_isGuarded (arr->sref))
01020             {
01021               if (optgenerror (FLG_NULLDEREF,
01022                                message ("Index of %s pointer %q: %s", 
01023                                         sRef_nullMessage (arr->sref),
01024                                         sRef_unparse (arr->sref),
01025                                         exprNode_unparse (arr)),
01026                                arr->loc))
01027                 {
01028                   sRef_showNullInfo (arr->sref);
01029 
01030                   /* suppress future messages */
01031                   sRef_setNullError (arr->sref); 
01032                 }
01033             }
01034         }
01035 
01036       if (exprNode_isError (ind))
01037         {
01038           if ((ctype_isArrayPtr (crarr) 
01039                && !ctype_isFunction (crarr))
01040               || ctype_isUnknown (carr))
01041             {
01042               exprNode ret = exprNode_createPartialCopy (arr);
01043 
01044               if (ctype_isKnown (carr))
01045                 {
01046                   ret->typ = ctype_baseArrayPtr (crarr);
01047                 }
01048               else
01049                 {
01050                   ret->typ = ctype_unknown;
01051                 }
01052               
01053               ret->sref = sRef_makeArrayFetch (arr->sref);
01054               
01055               ret->kind = XPR_FETCH;
01056 
01057               /*
01058               ** Because of funny aliasing (when arr and ind are
01059               ** flipped) spurious errors would be reported here.
01060               */
01061          
01062               /*@i2@*/ ret->edata = exprData_makePair (arr, ind);             
01063               checkSafeUse (ret, arr->sref);
01064               return (ret);
01065             }
01066           else
01067             {
01068               voptgenerror (FLG_TYPE,
01069                             message ("Array fetch from non-array (%t): %s[%s]", carr, 
01070                                      exprNode_unparse (e1), exprNode_unparse (e2)),
01071                             arr->loc);
01072               exprNode_free (arr);
01073               return (exprNode_makeError ());
01074             }
01075         }
01076       else
01077         {
01078           if (!ctype_isForceRealInt (&(ind->typ)))
01079             {
01080               ctype rt = ctype_realType (ind->typ);
01081 
01082               if (ctype_isChar (rt))
01083                 {
01084                   vnoptgenerror
01085                     (FLG_CHARINDEX,
01086                      message ("Array fetch using non-integer, %t: %s[%s]",
01087                               ind->typ, 
01088                               exprNode_unparse (e1), exprNode_unparse (e2)),
01089                      arr->loc);
01090                 }
01091               else if (ctype_isEnum (rt))
01092                 {
01093                   vnoptgenerror
01094                     (FLG_ENUMINDEX,
01095                      message ("Array fetch using non-integer, %t: %s[%s]",
01096                               ind->typ, 
01097                               exprNode_unparse (e1), exprNode_unparse (e2)),
01098                      arr->loc);
01099                 }
01100               else
01101                 {
01102                   voptgenerror 
01103                     (FLG_TYPE,
01104                      message ("Array fetch using non-integer, %t: %s[%s]",
01105                               ind->typ, 
01106                               exprNode_unparse (e1), exprNode_unparse (e2)),
01107                      arr->loc);
01108                 }
01109 
01110               multiVal_free (ind->val);
01111               ind->val = multiVal_unknown ();
01112             }
01113           
01114           if (ctype_isArrayPtr (crarr) && !ctype_isFunction (crarr))
01115             {
01116               exprNode ret = exprNode_createSemiCopy (arr);
01117               multiVal m = exprNode_getValue (ind);
01118               
01119               ret->typ = ctype_baseArrayPtr (crarr);
01120               ret->kind = XPR_FETCH;
01121               
01122               if (multiVal_isInt (m))
01123                 {
01124                   int i = (int) multiVal_forceInt (m);
01125                   
01126                   if (sRef_isValid (arr->sref)) {
01127                     ret->sref = sRef_makeArrayFetchKnown (arr->sref, i);
01128                   } else {
01129                     ret->sref = sRef_undefined;
01130                   }
01131                 }
01132               else
01133                 {
01134                                   ret->sref = sRef_makeArrayFetch (arr->sref);
01135                 }
01136               
01137               ret->sets = sRefSet_realNewUnion (arr->sets, ind->sets);
01138               ret->msets = sRefSet_realNewUnion (arr->msets, ind->msets);
01139               ret->uses = sRefSet_realNewUnion (arr->uses, ind->uses);
01140               
01141               /* (see comment on spurious errors above) */
01142               /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
01143               
01144               exprNode_checkUse (ret, ind->sref, ind->loc);
01145               exprNode_checkUse (ret, arr->sref, arr->loc);
01146               
01147               return (ret);
01148             }
01149           else
01150             {
01151               if (ctype_isUnknown (carr))
01152                 {
01153                   exprNode ret = exprNode_createPartialCopy (arr);
01154                   
01155                   ret->kind = XPR_FETCH;
01156                   ret->typ = ctype_unknown;
01157                   ret->sets = sRefSet_union (ret->sets, ind->sets);
01158                   ret->msets = sRefSet_union (ret->msets, ind->msets);
01159                   ret->uses = sRefSet_union (ret->uses, ind->uses);
01160 
01161                   /* (see comment on spurious errors above) */            
01162                   /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
01163                   
01164                   exprNode_checkUse (ret, ind->sref, ind->loc);
01165                   exprNode_checkUse (ret, arr->sref, arr->loc);
01166                   return (ret);
01167                 }
01168               else
01169                 {
01170                   voptgenerror
01171                     (FLG_TYPE,
01172                      message ("Array fetch from non-array (%t): %s[%s]", carr, 
01173                               exprNode_unparse (e1), exprNode_unparse (e2)),
01174                      arr->loc);
01175 
01176                   exprNode_free (arr);
01177                   exprNode_free (ind);
01178 
01179                   return (exprNode_makeError ());
01180                 }
01181             }
01182         }
01183     }
01184   BADEXIT;
01185 }
01186 
01187 
01188 static int
01189 checkArgs (uentry fcn, /*@dependent@*/ exprNode f, ctype t, 
01190            exprNodeList args, exprNode ret)
01191 {
01192   return (checkArgsReal (fcn, f, ctype_argsFunction (t), args, FALSE, ret));
01193 }
01194 
01195 /*
01196 ** checkPrintfArgs --- checks arguments for printf-like functions
01197 **    Arguments before ... have already been checked.
01198 **    The argument before the ... is a char *.  
01199 **    argno is the format string argument.
01200 */
01201 
01202 static void
01203 checkPrintfArgs (/*@notnull@*/ /*@dependent@*/ exprNode f, uentry fcn, 
01204                  exprNodeList args, exprNode ret, int argno)
01205 {
01206   /*
01207   ** the last argument before the elips is the format string 
01208   */
01209 
01210   int i = argno;
01211   fileloc formatloc;
01212   int nargs = exprNodeList_size (args);
01213   uentryList params = uentry_getParams (fcn);
01214   exprNode a; 
01215 
01216   /*
01217   ** These should be ensured by checkSpecialFunction
01218   */
01219 
01220   llassert (uentryList_size (params) == argno + 1);
01221   llassert (uentry_isElipsisMarker (uentryList_getN (params, argno)));
01222 
01223   a = exprNodeList_getN (args, argno - 1);
01224   formatloc = fileloc_copy (exprNode_loc (a));
01225 
01226   if (exprNode_isDefined (a) && exprNode_isStringLiteral (a) 
01227       && exprNode_knownStringValue (a))
01228     {
01229       char *format = cstring_toCharsSafe (multiVal_forceString (exprNode_getValue (a)));
01230       char *code = format;
01231       char *ocode = code;
01232 
01233       nargs = exprNodeList_size (args);
01234 
01235       while ((code = strchr (code, '%')) != NULL)
01236         {
01237           char *origcode = code;
01238           char key = *(++code);                 
01239           ctype modtype = ctype_int;
01240           bool modified = FALSE;
01241 
01242           fileloc_addColumn (formatloc, code - ocode);
01243 
01244           /* ignore flags */
01245           while (isFlagKey (key)) 
01246             {
01247               key = *(++code);
01248               fileloc_incColumn (formatloc);
01249             }
01250 
01251           if (key == 'm') /* skipped in syslog */
01252             {
01253               continue; 
01254             }
01255           
01256           /* ignore field width */
01257           while (isdigit ((int) key) != 0) 
01258             {
01259               key = *(++code);
01260               fileloc_incColumn (formatloc);
01261             }
01262           
01263           /* ignore precision */
01264           if (key == '.')
01265             {
01266               key = *(++code);
01267               fileloc_incColumn (formatloc);
01268 
01269               /*
01270               ** In printf, '*' means: read the next arg as an int for the
01271               ** field width.  This seems to be missing from my copy of the 
01272               ** standard x3.159-1989.  Setion 4.9.6.1 refers to * (described
01273               ** later) but never does.
01274               */
01275               
01276               if (key == '*') 
01277                 {
01278                   ; /* don't do anything --- handle later */
01279                 }
01280               else
01281                 {
01282                   while (isdigit ((int) key) != 0)
01283                     {
01284                       key = *(++code);
01285                       fileloc_incColumn (formatloc);
01286                     }
01287                 }
01288             }
01289 
01290           if (key == 'h')
01291             {
01292               modtype = ctype_sint;  /* short */
01293               key = *(++code);
01294               fileloc_incColumn (formatloc);
01295             }
01296           else if (key == 'l' || key == 'L') 
01297             {
01298               modtype = ctype_lint; /* long */
01299               key = *(++code);
01300               fileloc_incColumn (formatloc);
01301 
01302               if (key == 'l' || key == 'L') { 
01303                 modtype = ctype_llint; /* long long */
01304                 key = *(++code);
01305                 fileloc_incColumn (formatloc);
01306               }
01307             }
01308           else
01309             {
01310               ; /* no modifier */
01311             }
01312           
01313           /* now, key = type of conversion to apply */
01314           ++code;
01315           fileloc_incColumn (formatloc);
01316 
01317           if (key != '%') 
01318             {
01319               if (i >= nargs)
01320                 {
01321                   if (optgenerror 
01322                       (FLG_TYPE,
01323                        message ("No argument corresponding to %q format "
01324                                 "code %d (%%%h): \"%s\"",
01325                                 uentry_getName (fcn),
01326                                 i, key,
01327                                 cstring_fromChars (format)),
01328                        f->loc))
01329                     {
01330                       if (fileloc_isDefined (formatloc)
01331                           && context_getFlag (FLG_SHOWCOL))
01332                         {
01333                           llgenindentmsg (cstring_makeLiteral ("Corresponding format code"),
01334                                           formatloc);
01335                         }
01336                     }
01337                   i++;
01338                 }
01339               else
01340                 {
01341                   a = exprNodeList_getN (args, i);
01342                   i++;
01343                   
01344                   if (!exprNode_isError (a))
01345                     {
01346                       ctype expecttype;
01347 
01348                       switch (key)
01349                         {
01350                         case '*': /* int argument for fieldwidth */
01351                           expecttype = ctype_int;
01352                           *(--code) = '%'; /* convert it for next code */
01353                           fileloc_subColumn (formatloc, 1);
01354                           /*@switchbreak@*/ break;              
01355                         case 'u':
01356                         case 'o':
01357                           expecttype = ctype_combine (ctype_uint, modtype);
01358                           /*@switchbreak@*/ break;
01359                           
01360                         case 'i': /* int argument */ 
01361                         case 'd':
01362                           expecttype = ctype_combine (ctype_int, modtype);
01363                           /*@switchbreak@*/ break;
01364 
01365                         case 'x': /* unsigned int */
01366                         case 'X':
01367                           expecttype = ctype_combine (ctype_uint, modtype);
01368                           /*@switchbreak@*/ break;
01369                           
01370                         case 'e':
01371                         case 'E':
01372                         case 'g':
01373                         case 'G':
01374                         case 'f': /* double */
01375                           expecttype = ctype_combine (ctype_double, modtype);
01376                           /*@switchbreak@*/ break;
01377                           
01378                         case 'c': /* int converted to char (check its a char?) */
01379                           expecttype = ctype_makeConj (ctype_char, ctype_uchar);
01380                           /*@switchbreak@*/ break;
01381                               
01382                         case 's': /* string */
01383                           expecttype = ctype_string;
01384                           /*@switchbreak@*/ break;
01385                         case '[': 
01386                           /* skip to ']' */
01387                           while (((key = *(++code)) != ']') 
01388                                  && (key != '\0'))
01389                             {
01390                               fileloc_incColumn (formatloc);
01391                             }
01392                           
01393                           if (key == '\0')
01394                             {
01395                               llfatalerrorLoc
01396                                 (message ("Bad character set format: %s", 
01397                                           cstring_fromChars (origcode)));
01398                             }
01399                           
01400                           expecttype = ctype_string;
01401                           /*@switchbreak@*/ break;
01402                           
01403                         case 'p': /* pointer */
01404                           expecttype = ctype_makePointer (ctype_void);
01405                           /* really! */
01406                           /*@switchbreak@*/ break;
01407                           
01408                         case 'n': /* pointer to int, modified by call! */
01409                           expecttype = ctype_combine (ctype_makePointer (ctype_int), modtype);
01410                           modified = TRUE;
01411                           uentry_setDefState (regArg, SS_ALLOCATED); /* corresponds to out */
01412                           /*@switchbreak@*/ break;
01413 
01414                         case 'm': /* in a syslog, it doesn't consume an argument */
01415                           /* should check we're really doing syslog */
01416                           
01417                           /*@switchbreak@*/ break;
01418 
01419                           
01420                         default:
01421                           expecttype = ctype_unknown;
01422                           
01423                           voptgenerror
01424                             (FLG_FORMATCODE,
01425                              message ("Unrecognized format code: %s", 
01426                                       cstring_fromChars (origcode)),
01427                              fileloc_isDefined (formatloc) 
01428                              ? formatloc : g_currentloc);
01429 
01430                           /*@switchbreak@*/ break;
01431                         }
01432 
01433                       if (!(exprNode_matchArgType (expecttype, a)))
01434                         {
01435                           if (ctype_isVoidPointer (expecttype) 
01436                               && ctype_isRealAbstract (a->typ)
01437                               && (context_getFlag (FLG_ABSTVOIDP)))
01438                             {
01439                               ;
01440                             }
01441                           else
01442                             {
01443                               if (llgenformattypeerror 
01444                                   (expecttype, exprNode_undefined,
01445                                    a->typ, a,
01446                                    message ("Format argument %d to %q (%%%h) expects "
01447                                             "%t gets %t: %s",
01448                                             i - argno,
01449                                             uentry_getName (fcn), 
01450                                             key, expecttype,
01451                                             a->typ, exprNode_unparse (a)),
01452                                    a->loc))
01453                                 {
01454                                   if (fileloc_isDefined (formatloc)
01455                                       && context_getFlag (FLG_SHOWCOL))
01456                                     {
01457                                       llgenindentmsg
01458                                         (cstring_makeLiteral 
01459                                          ("Corresponding format code"),
01460                                          formatloc);
01461                                     }
01462                                 }
01463                             }
01464                         }
01465 
01466                       uentry_setType (regArg, expecttype);
01467                       checkOneArg (regArg, a, f, FALSE, i+1, nargs);
01468                       
01469                       if (ctype_equal (expecttype, ctype_string))
01470                         {
01471                           exprNode_checkUse (a, sRef_makePointer (a->sref), a->loc);
01472                         }
01473                       
01474                       uentry_setType (regArg, ctype_unknown);
01475                       uentry_fixupSref (regArg);
01476                   
01477                       if (modified)
01478                         {
01479                           exprNode_checkCallModifyVal (a->sref, args, f, ret);
01480                         }
01481                     }
01482                   else
01483                     {
01484                       ;
01485                     }
01486                 }
01487             }
01488           ocode = code;
01489         }
01490   
01491       if (i < nargs)
01492         {
01493           voptgenerror (FLG_TYPE,
01494                         message ("Format string for %q has %d arg%p, given %d", 
01495                                  uentry_getName (fcn), i - argno, nargs - argno),
01496                         f->loc);
01497         }
01498     }
01499   else
01500     {
01501       /* no checking possible for compile-time unknown format strings */
01502     }
01503 
01504   fileloc_free (formatloc);
01505 }
01506 
01507 static void
01508 checkScanfArgs (/*@notnull@*/ /*@dependent@*/ exprNode f, uentry fcn, 
01509                  exprNodeList args, exprNode ret, int argno)
01510 {
01511   int i = argno;
01512   fileloc formatloc;
01513   int nargs = exprNodeList_size (args);
01514   uentryList params = uentry_getParams (fcn);
01515   exprNode a; 
01516 
01517   /*
01518   ** These should be ensured by checkSpecialFunction
01519   */
01520 
01521   llassert (uentryList_size (params) == argno + 1);
01522   llassert (uentry_isElipsisMarker (uentryList_getN (params, argno)));
01523 
01524   a = exprNodeList_getN (args, argno - 1);
01525   formatloc = fileloc_copy (exprNode_loc (a));
01526 
01527   if (exprNode_isDefined (a) && exprNode_isStringLiteral (a) 
01528       && exprNode_knownStringValue (a))
01529     {
01530       char *format = cstring_toCharsSafe (multiVal_forceString (exprNode_getValue (a)));
01531       char *code = format;
01532       char *ocode = code;
01533 
01534       nargs = exprNodeList_size (args);
01535 
01536       while ((code = strchr (code, '%')) != NULL)
01537         {
01538           char *origcode = code;
01539           char key = *(++code);                 
01540           ctype modtype = ctype_int;
01541           char modifier = '\0';
01542           bool modified = TRUE;
01543           bool ignore = FALSE;
01544 
01545           fileloc_addColumn (formatloc, code - ocode);
01546 
01547           /*
01548           ** this is based on ANSI standard library description of fscanf
01549           ** (from ANSI standard X3.159-1989, 4.9.6.1)
01550           */
01551               
01552           /* '*' suppresses assignment (does not need match argument) */
01553           
01554           if (key == '*') 
01555             {
01556               key = *(++code);
01557               modified = FALSE; 
01558               ignore = TRUE;
01559               fileloc_incColumn (formatloc);
01560             }
01561           
01562           /* ignore field width */
01563           while (isdigit ((int) key) != 0)
01564             {
01565               key = *(++code);
01566               fileloc_incColumn (formatloc);
01567             }
01568           
01569           if (key == 'h')
01570             {
01571               modtype = ctype_sint;  /* short */
01572               key = *(++code);
01573               fileloc_incColumn (formatloc);
01574             }
01575           else if (key == 'l' || key == 'L') 
01576             {
01577               modtype = ctype_lint; /* long */
01578               modifier = key;
01579 
01580               key = *(++code);
01581               fileloc_incColumn (formatloc);
01582 
01583               if (key == 'l' || key == 'L') { 
01584                 modtype = ctype_llint; /* long long */
01585                 key = *(++code);
01586                 fileloc_incColumn (formatloc);
01587               }
01588             }
01589           else
01590             {
01591               ; /* no modifier */
01592             }
01593           
01594           /* now, key = type of conversion to apply */
01595           ++code;
01596           fileloc_incColumn (formatloc);
01597 
01598           if (key != '%') 
01599             {
01600               if (ignore)
01601                 {
01602                   ;
01603                 }
01604               else
01605                 {
01606                   if (i >= nargs)
01607                     {
01608                       if (optgenerror 
01609                           (FLG_TYPE,
01610                            message ("No argument corresponding to %q format "
01611                                     "code %d (%%%h): \"%s\"",
01612                                     uentry_getName (fcn),
01613                                     i, key,
01614                                     cstring_fromChars (format)),
01615                            f->loc))
01616                         {
01617                           if (fileloc_isDefined (formatloc)
01618                               && context_getFlag (FLG_SHOWCOL))
01619                             {
01620                               llgenindentmsg
01621                                 (cstring_makeLiteral ("Corresponding format code"),
01622                                  formatloc);
01623                             }
01624                         }
01625                       i++;
01626                     }
01627                   else
01628                     {
01629                       a = exprNodeList_getN (args, i);
01630                       i++;
01631                   
01632                       if (!exprNode_isError (a))
01633                         {
01634                           ctype expecttype;
01635 
01636                           switch (key)
01637                             {
01638                             case '*': /* int argument for fieldwidth */
01639                               expecttype = ctype_makePointer (ctype_int);
01640                               *(--code) = '%'; /* convert it for next code */
01641                               fileloc_subColumn (formatloc, 1);
01642                               /*@switchbreak@*/ break;          
01643                             case 'u':
01644                             case 'o':
01645                               expecttype = ctype_makePointer (ctype_combine (ctype_uint, modtype));
01646                               /*@switchbreak@*/ break;
01647                               
01648                             case 'i': 
01649                             case 'd':
01650                             case 'x':
01651                             case 'X': /* unsigned int */
01652                               expecttype = ctype_makePointer (ctype_combine (ctype_int, modtype));
01653                               /*@switchbreak@*/ break;
01654                               
01655                             case 'e':
01656                             case 'E':
01657                             case 'g':
01658                             case 'G':
01659                             case 'f': 
01660                               /* printf is double, scanf is float! */
01661 
01662                               if (modifier == 'l') 
01663                                 {
01664                                   expecttype = ctype_makePointer (ctype_double);
01665                                 }
01666                               else if (modifier == 'L')
01667                                 {
01668                                   expecttype = ctype_makePointer (ctype_ldouble);
01669                                 }
01670                               else 
01671                                 {
01672                                   llassert (modifier == '\0');
01673                                   expecttype = ctype_makePointer (ctype_float);
01674                                 }
01675                               /*@switchbreak@*/ break;
01676                               
01677                             case 'c': /* int converted to char (check its a char?) */
01678                               expecttype = ctype_makePointer (ctype_makeConj (ctype_char, ctype_uchar));
01679                               /*@switchbreak@*/ break;
01680                               
01681                             case 's': /* string */
01682                               expecttype = ctype_string;
01683                               /*@switchbreak@*/ break;
01684 
01685                             case '[': 
01686                               /* skip to ']' */
01687                               while (((key = *(++code)) != ']') 
01688                                      && (key != '\0'))
01689                                 {
01690                                   fileloc_incColumn (formatloc);
01691                                 }
01692                               
01693                               if (key == '\0')
01694                                 {
01695                                   llfatalerrorLoc
01696                                     (message ("Bad character set format: %s", 
01697                                               cstring_fromChars (origcode)));
01698                                 }
01699                               
01700                               expecttype = ctype_string;
01701                               /*@switchbreak@*/ break;
01702                               
01703                             case 'p': /* pointer */
01704                               expecttype = ctype_unknown;
01705                               /* really! */
01706                               /*@switchbreak@*/ break;
01707                               
01708                             case 'n': /* pointer to int, modified by call! */
01709                               expecttype = ctype_makePointer (ctype_int);
01710                               /*@switchbreak@*/ break;
01711                           
01712                             default:
01713                               expecttype = ctype_unknown;
01714                               
01715                               voptgenerror
01716                                 (FLG_FORMATCODE,
01717                                  message ("Unrecognized format code: %s", 
01718                                           cstring_fromChars (origcode)),
01719                                  fileloc_isDefined (formatloc) 
01720                                  ? formatloc : g_currentloc);
01721                               
01722                               /*@switchbreak@*/ break;
01723                             }
01724                           
01725                           if (!(exprNode_matchArgType (expecttype, a)))
01726                             {
01727                               if (ctype_isVoidPointer (expecttype) 
01728                                   && ctype_isRealAbstract (a->typ)
01729                                   && (context_getFlag (FLG_ABSTVOIDP)))
01730                                 {
01731                                   ;
01732                                 }
01733                               else
01734                                 {
01735                                   if (modifier != '\0')
01736                                     {
01737                                       if (llgenformattypeerror 
01738                                           (expecttype, exprNode_undefined,
01739                                            a->typ, a,
01740                                            message ("Format argument %d to %q (%%%h%h) expects "
01741                                                     "%t gets %t: %s",
01742                                                     i - argno,
01743                                                     uentry_getName (fcn), 
01744                                                     modifier,
01745                                                     key, expecttype,
01746                                                     a->typ, exprNode_unparse (a)),
01747                                            a->loc))
01748                                         {
01749                                           if (fileloc_isDefined (formatloc)
01750                                               && context_getFlag (FLG_SHOWCOL))
01751                                             {
01752                                               llgenindentmsg
01753                                                 (cstring_makeLiteral 
01754                                                  ("Corresponding format code"),
01755                                                  formatloc);
01756                                             }
01757                                         }
01758 
01759                                     }
01760                                   else
01761                                     {
01762                                       if (llgenformattypeerror 
01763                                           (expecttype, exprNode_undefined,
01764                                            a->typ, a,
01765                                            message ("Format argument %d to %q (%%%h) expects "
01766                                                     "%t gets %t: %s",
01767                                                     i - argno,
01768                                                     uentry_getName (fcn), 
01769                                                     key, expecttype,
01770                                                     a->typ, exprNode_unparse (a)),
01771                                            a->loc))
01772                                         {
01773                                           if (fileloc_isDefined (formatloc)
01774                                               && context_getFlag (FLG_SHOWCOL))
01775                                             {
01776                                               llgenindentmsg
01777                                                 (cstring_makeLiteral 
01778                                                  ("Corresponding format code"),
01779                                                  formatloc);
01780                                             }
01781                                         }
01782                                     }
01783                                 }
01784                             }
01785                           
01786                           uentry_setType (outArg, expecttype);
01787                           checkOneArg (outArg, a, f, FALSE, i+1, nargs);
01788                           uentry_setType (outArg, ctype_unknown);
01789                           uentry_fixupSref (outArg);
01790                           
01791                           if (modified)
01792                             {
01793                               exprNode_checkCallModifyVal (a->sref, args, f, ret);
01794                             }
01795                         }
01796                       else
01797                         {
01798                                                   /* a->sref = defref; */
01799                         }
01800                     }
01801                 }
01802             }
01803           ocode = code;
01804         }
01805 
01806       if (i < nargs)
01807         {
01808           voptgenerror (FLG_TYPE,
01809                         message ("Format string for %q has %d arg%p, given %d", 
01810                                  uentry_getName (fcn), i - argno, nargs - argno),
01811                         f->loc);
01812         }
01813     }
01814   else
01815     {
01816       /* no checking possible for compile-time unknown format strings */
01817     }
01818 
01819   fileloc_free (formatloc);
01820 }
01821                           
01822 static void
01823 checkMessageArgs (/*@notnull@*/ /*@dependent@*/ exprNode f,
01824                   uentry fcn,
01825                   exprNodeList args,
01826                   /*@unused@*/ int argno)
01827 {
01828   /*
01829   ** the last argument before the elips is the format string 
01830   */
01831 
01832   int nargs = exprNodeList_size (args);
01833   int i = argno;
01834   fileloc formatloc;
01835   exprNode a; 
01836 
01837   a = exprNodeList_getN (args, argno - 1);
01838   formatloc = fileloc_copy (exprNode_loc (a));
01839 
01840   if (ctype_isUnknown (cstringType)) {
01841     if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
01842       {
01843         cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
01844       }
01845   }
01846  
01847   if (ctype_isUnknown (ctypeType)) {
01848     if (usymtab_existsType (cstring_makeLiteralTemp ("ctype")))
01849       {
01850         ctypeType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("ctype"));
01851       }
01852   }
01853 
01854   if (ctype_isUnknown (filelocType)) {
01855     if (usymtab_existsType (cstring_makeLiteralTemp ("fileloc")))
01856       {
01857         filelocType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("fileloc"));
01858       }
01859   }
01860 
01861   if (exprNode_isDefined (a) && exprNode_isStringLiteral (a) 
01862       && exprNode_knownStringValue (a))
01863     {
01864       cstring format = multiVal_forceString (exprNode_getValue (a));
01865       char *code = cstring_toCharsSafe (format);
01866       char *ocode = code;
01867 
01868       nargs = exprNodeList_size (args);
01869 
01870       while ((code = strchr (code, '%')) != NULL)
01871         {
01872           char *origcode = code;
01873           char key = *(++code);                 
01874           bool isOnly = FALSE;
01875 
01876           fileloc_addColumn (formatloc, code - ocode);
01877 
01878           while (key >= '0' && key <= '9')
01879             {
01880               key = *(++code);
01881               fileloc_incColumn (formatloc);
01882             }
01883           
01884           ++code;
01885           fileloc_incColumn (formatloc);
01886 
01887           if (key != '%') 
01888             {
01889               if (key == 'p')
01890                 {
01891                   goto nextKey;
01892                 }
01893 
01894               if (i >= nargs)
01895                 {
01896                   voptgenerror
01897                     (FLG_TYPE,
01898                      message ("Message missing format arg %d (%%%h): \"%s\"",
01899                               i + 1, key, format), 
01900                      f->loc);
01901                   i++;
01902                 }
01903               else
01904                 {
01905                   a = exprNodeList_getN (args, i);
01906                   i++;
01907                   
01908                 nextKey:
01909                   if (!exprNode_isError (a))
01910                     {
01911                       ctype expecttype;
01912                       
01913                       /*@-loopswitchbreak@*/
01914 
01915                       switch (key)
01916                         {
01917                         case 'c':
01918                         case 'h': 
01919                           expecttype = ctype_char; break;
01920                         case 's': 
01921                           expecttype = cstringType; break;
01922                         case 'q': 
01923                           expecttype = cstringType; isOnly = TRUE; break;
01924                         case 'x': 
01925                           expecttype = cstringType; isOnly = TRUE; break;
01926                         case 'd': expecttype = ctype_int; break;
01927                         case 'u': expecttype = ctype_uint; break;
01928                         case 'w': expecttype = ctype_ulint; break;
01929                         case 'f': expecttype = ctype_float; break;
01930                         case 'b': expecttype = ctype_bool; break;
01931                         case 't': expecttype = ctypeType; break;
01932                         case 'l': expecttype = filelocType; break;
01933                         case 'p':  /* a wee bit of a hack methinks */
01934                           expecttype = ctype_int;
01935                           break;
01936                         case 'r': expecttype = ctype_bool; break;
01937                         default:  
01938                           expecttype = ctype_unknown;
01939                           voptgenerror
01940                             (FLG_FORMATCODE,
01941                              message ("Unrecognized format code: %s", 
01942                                       cstring_fromChars (origcode)),
01943                              fileloc_isDefined (formatloc) 
01944                              ? formatloc : g_currentloc);
01945                           break;
01946                         }
01947                       /*@=loopswitchbreak@*/
01948 
01949                       if (!(exprNode_matchArgType (expecttype, a)))
01950                         {
01951                           if (ctype_isVoidPointer (expecttype) 
01952                               && ctype_isRealAbstract (a->typ)
01953                               && (context_getFlag (FLG_ABSTVOIDP)))
01954                             {
01955                               ;
01956                             }
01957                           else
01958                             {
01959                               if (llgenformattypeerror 
01960                                   (expecttype, exprNode_undefined,
01961                                    a->typ, a,
01962                                    message ("Format argument %d to %q (%%%h) expects "
01963                                             "%t gets %t: %s",
01964                                             i - argno,
01965                                             uentry_getName (fcn), 
01966                                             key, expecttype,
01967                                             a->typ, exprNode_unparse (a)),
01968                                    a->loc))
01969                                   {
01970                                   if (fileloc_isDefined (formatloc)
01971                                       && context_getFlag (FLG_SHOWCOL))
01972                                     {
01973                                       llgenindentmsg
01974                                         (cstring_makeLiteral 
01975                                          ("Corresponding format code"),
01976                                          formatloc);
01977                                     }
01978                                 }
01979                             }
01980                         }
01981                       
01982                       if (ctype_equal (expecttype, cstringType))
01983                         {
01984                           if (isOnly)
01985                             {
01986                               checkOneArg (csOnlyArg, a, f, FALSE, i+1, nargs);
01987                               uentry_fixupSref (csOnlyArg);
01988                             }
01989                           else
01990                             {
01991                               checkOneArg (csArg, a, f, FALSE, i+1, nargs);
01992                               uentry_fixupSref (csArg);
01993                             }
01994                         }
01995                       else
01996                         {
01997                                                   checkOneArg (regArg, a, f, FALSE, i+1, nargs);
01998                           uentry_fixupSref (regArg);
01999                         }
02000                     }
02001                 }
02002             }
02003         }
02004 
02005       if (i < nargs)
02006         {
02007           voptgenerror (FLG_TYPE,
02008                         message ("Format string for %q has %d arg%p, given %d", 
02009                                  uentry_getName (fcn), i - argno, nargs -argno),
02010                         f->loc);
02011         }
02012     }
02013   else
02014     {
02015       /* no checking possible for compile-time unknown format strings */
02016     }
02017 
02018   fileloc_free (formatloc);
02019 }
02020 
02021 static void
02022   checkExpressionDefinedAux (/*@notnull@*/ exprNode e1, 
02023                              /*@notnull@*/ exprNode e2, 
02024                              sRefSet sets1,
02025                              sRefSet sets2, 
02026                              lltok op,
02027                              flagcode flag)
02028 {
02029   bool hadUncon = FALSE;
02030 
02031   if (sRef_isGlobal (sRef_getRootBase (e1->sref)) && 
02032       sRefSet_hasUnconstrained (sets2))
02033     {
02034       voptgenerror
02035         (FLG_EVALORDERUNCON,
02036          message
02037          ("Expression may have undefined behavior (%q used in right operand "
02038           "may set global variable %q used in left operand): %s %s %s", 
02039           sRefSet_unparseUnconstrained (sets2),
02040           sRef_unparse (sRef_getRootBase (e1->sref)),
02041           exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
02042          e2->loc);
02043     }
02044 
02045   if (sRef_isGlobal (sRef_getRootBase (e2->sref)) && 
02046       sRefSet_hasUnconstrained (sets1))
02047     {
02048       voptgenerror
02049         (FLG_EVALORDERUNCON,
02050          message
02051          ("Expression has undefined behavior (%q used in left operand "
02052           "may set global variable %q used in right operand): %s %s %s", 
02053           sRefSet_unparseUnconstrained (sets1),
02054           sRef_unparse (e2->sref),
02055           exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
02056          e2->loc);
02057     }
02058 
02059   sRefSet_realElements (e1->uses, sr)
02060     {
02061       if (sRef_isMeaningful (sr) && sRefSet_member (sets2, sr))
02062         {
02063           voptgenerror
02064             (FLG_EVALORDER,
02065              message
02066              ("Expression has undefined behavior (left operand uses %q, "
02067               "modified by right operand): %s %s %s", 
02068               sRef_unparse (sr),
02069               exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
02070              e2->loc);
02071         }
02072     } end_sRefSet_realElements;
02073   
02074   sRefSet_realElements (sets1, sr)
02075     {
02076       if (sRef_isMeaningful (sr))
02077         {
02078           if (sRef_same (sr, e2->sref))
02079             {
02080               voptgenerror
02081                 (flag,
02082                  message
02083                  ("Expression has undefined behavior (value of right operand "
02084                   "modified by left operand): %s %s %s", 
02085                   exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
02086                  e2->loc);
02087             }
02088           else if (sRefSet_member (e2->uses, sr))
02089             {
02090               voptgenerror
02091                 (flag,
02092                  message 
02093                  ("Expression has undefined behavior (left operand modifies %q, "
02094                   "used by right operand): %s %s %s", 
02095                   sRef_unparse (sr),
02096                   exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
02097                  e2->loc);
02098             }
02099           else 
02100             {
02101               if (sRefSet_member (sets2, sr))
02102                 {
02103                   if (sRef_isUnconstrained (sr))
02104                     {
02105                       if (hadUncon)
02106                         {
02107                           ;
02108                         }
02109                       else
02110                         {
02111                           hadUncon = optgenerror
02112                             (FLG_EVALORDERUNCON,
02113                              message 
02114                              ("Expression may have undefined behavior.  Left operand "
02115                               "calls %q; right operand calls %q.  The unconstrained "
02116                               "functions may modify global state used by "
02117                               "the other operand): %s %s %s", 
02118                               sRefSet_unparseUnconstrained (sets1),
02119                               sRefSet_unparseUnconstrained (sets2),
02120                               exprNode_unparse (e1), lltok_unparse (op),
02121                               exprNode_unparse (e2)),
02122                              e2->loc);
02123                         }
02124                     }
02125                   else
02126                     {
02127                       voptgenerror
02128                         (flag,
02129                          message 
02130                          ("Expression has undefined behavior (both "
02131                           "operands modify %q): %s %s %s", 
02132                           sRef_unparse (sr), 
02133                           exprNode_unparse (e1), 
02134                           lltok_unparse (op), exprNode_unparse (e2)),
02135                          e2->loc);
02136                     }
02137                 }
02138             }
02139         }
02140     } end_sRefSet_realElements;
02141 }
02142 
02143 static void checkExpressionDefined (exprNode e1, exprNode e2, lltok op)
02144 {
02145   bool hasError = FALSE;
02146   
02147   if (exprNode_isError (e1) || exprNode_isError (e2))
02148     {
02149       return;
02150     }
02151 
02152   if (sRefSet_member (e2->sets, e1->sref))
02153     {
02154       if (e2->kind == XPR_CALL)
02155         {
02156          ;
02157         }
02158       else
02159         {
02160           hasError = optgenerror 
02161             (FLG_EVALORDER,
02162              message ("Expression has undefined behavior "
02163                       "(value of left operand is modified "
02164                       "by right operand): %s %s %s", 
02165                       exprNode_unparse (e1), lltok_unparse (op),
02166                       exprNode_unparse (e2)),
02167              e2->loc);
02168         }
02169     }
02170 
02171   if (context_getFlag (FLG_EVALORDERUNCON))
02172     {
02173       if (sRefSet_member (e2->msets, e1->sref))
02174         {
02175           if (e2->kind == XPR_CALL)
02176             {
02177               ;
02178             }
02179           else
02180             {
02181               hasError = optgenerror 
02182                 (FLG_EVALORDER,
02183                  message 
02184                  ("Expression has undefined behavior (value of left "
02185                   "operand may be modified by right operand): %s %s %s", 
02186                   exprNode_unparse (e1), lltok_unparse (op),
02187                   exprNode_unparse (e2)),
02188                  e2->loc);
02189             }
02190         }
02191     }
02192   
02193   if (!hasError)
02194     {
02195       checkExpressionDefinedAux (e1, e2, e1->sets, e2->sets, op, FLG_EVALORDER);
02196       
02197       if (context_maybeSet (FLG_EVALORDERUNCON))
02198         {
02199           checkExpressionDefinedAux (e1, e2, e1->msets, 
02200                                      e2->msets, op, FLG_EVALORDERUNCON);
02201         }
02202     }
02203 }
02204 
02205 static void checkSequencing (exprNode p_f, exprNodeList p_args); 
02206 
02207 static int
02208   checkArgsReal (uentry fcn, /*@dependent@*/ exprNode f, uentryList cl, 
02209                  exprNodeList args, bool isIter, exprNode ret)
02210 {
02211   int special = 0;
02212 
02213   if (!exprNode_isError (f))
02214     {
02215       if (!uentryList_isMissingParams (cl))
02216         {
02217           int nargs = exprNodeList_size (args);
02218           int expectargs = uentryList_size (cl);
02219           ctype last;
02220           int i = 0;
02221           
02222           if (expectargs == 0)
02223             {
02224               if (nargs != 0)
02225                 {
02226                   if (isIter)
02227                     {
02228                       voptgenerror
02229                         (FLG_TYPE,
02230                          message ("Iter %q invoked with %d args, "
02231                                   "declared void",
02232                                   uentry_getName (fcn),
02233                                   nargs),
02234                          f->loc);
02235                     }
02236                   else
02237                     {
02238                       voptgenerror 
02239                         (FLG_TYPE,
02240                          message ("Function %s called with %d args, "
02241                                   "declared void", 
02242                                   exprNode_unparse (f), nargs),
02243                          f->loc);
02244                     }
02245                 }
02246               return special;
02247             }
02248           
02249           last = uentry_getType (uentryList_getN (cl, expectargs - 1));
02250           
02251           exprNodeList_reset (args);
02252           
02253           uentryList_elements (cl, current)
02254             {
02255               ctype ct = uentry_getType (current);
02256               exprNode a;
02257               
02258               if (ctype_isElips (ct))
02259                 {
02260                   /*
02261                    ** do special checking for printf/scanf library functions
02262                    **
02263                    ** this is kludgey code, just for handling the special case
02264                    **
02265                    */
02266 
02267                   if (uentry_isPrintfLike (fcn))
02268                     {
02269                       checkPrintfArgs (f, fcn, args, ret, i);
02270                       special = i;
02271                     }
02272                   else if (uentry_isScanfLike (fcn))
02273                     {
02274                       checkScanfArgs (f, fcn, args, ret, i); 
02275                       special = i;
02276                     }
02277                   else if (uentry_isMessageLike (fcn))
02278                     {
02279                       checkMessageArgs (f, fcn, args, i);
02280                       special = i;
02281                     }
02282                   else
02283                     {
02284                       llassert (!uentry_isSpecialFunction (fcn));
02285                     }
02286                     
02287                   nargs = expectargs; /* avoid errors */
02288                   break;
02289                 }
02290               else
02291                 {
02292                   if (i >= nargs) break;
02293                   
02294                   a = exprNodeList_current (args);
02295                   exprNodeList_advance (args);
02296                   
02297                   i++;
02298                   
02299                   if (exprNode_isError (a))
02300                     {
02301                      ;
02302                     }
02303                   else
02304                     {
02305                       /* 
02306                         probably necessary? I'm not sure about this one
02307                         checkMacroParen (a);
02308                         */
02309                       
02310                       f->guards = guardSet_union (f->guards, a->guards);
02311                       
02312                       DPRINTF (("match arg: %s / %s", ctype_unparse (ct), ctype_unparse (a->typ)));
02313 
02314                       if (!(exprNode_matchArgType (ct, a)))
02315                         {
02316                           DPRINTF (("Args mismatch!"));
02317 
02318                           if (ctype_isVoidPointer (ct) 
02319                               && (ctype_isPointer (a->typ) 
02320                                   && (ctype_isRealAbstract (ctype_baseArrayPtr (a->typ)))))
02321                             {
02322                               vnoptgenerror 
02323                                 (FLG_ABSTVOIDP,
02324                                  message 
02325                                  ("Pointer to abstract type (%t) used "
02326                                   "as void pointer "
02327                                   "(arg %d to %q): %s",
02328                                   a->typ, i, 
02329                                   uentry_getName (fcn), 
02330                                   exprNode_unparse (a)),
02331                                  a->loc);
02332                             }
02333                           else
02334                             {
02335                               if (isIter)
02336                                 {
02337                                   (void) gentypeerror 
02338                                     (ct, exprNode_undefined,
02339                                      a->typ, a,
02340                                      message 
02341                                      ("Iter %q expects arg %d to "
02342                                       "be %t gets %t: %s",
02343                                       uentry_getName (fcn),
02344                                       i, ct, a->typ, exprNode_unparse (a)),
02345                                      a->loc);
02346                                 }
02347                               else
02348                                 {
02349                                   if (gentypeerror  
02350                                       (ct, 
02351                                        exprNode_undefined,
02352                                        a->typ,
02353                                        a,
02354                                        message 
02355                                        ("Function %q expects arg %d to be %t gets %t: %s",
02356                                         uentry_getName (fcn),
02357                                         i, ct, a->typ, exprNode_unparse (a)),
02358                                        a->loc))
02359                                     {
02360                                       DPRINTF (("Types: %s / %s",
02361                                                 ctype_unparse (ct),
02362                                                 ctype_unparse (a->typ)));
02363                                     }
02364 
02365                                   /*
02366                                   ** Clear null marker for abstract types.
02367                                   ** (It is not revealed, so suppress future messages.)
02368                                   */
02369 
02370                                   if (ctype_isAbstract (a->typ))
02371                                     {
02372                                       sRef_setNullUnknown (exprNode_getSref (a), a->loc);
02373                                     }
02374                                 }
02375                             }
02376                         }
02377                     }
02378                 }
02379             } end_uentryList_elements ;
02380           
02381           
02382           if (expectargs != nargs) /* note: not != since we may have ... */
02383             {
02384               if (ctype_isElips (last))
02385                 {
02386                   voptgenerror
02387                     (FLG_TYPE,
02388                      message ("Function %s called with %d args, expects at least %d",
02389                               exprNode_unparse (f),
02390                               nargs, expectargs - 1),
02391                      f->loc);
02392                 }
02393               else
02394                 {
02395                   if (isIter)
02396                     {
02397                       voptgenerror 
02398                         (FLG_TYPE,
02399                          message ("Iter %q invoked with %d args, expects %d",
02400                                   uentry_getName (fcn), nargs, expectargs),
02401                          f->loc);
02402                     }
02403                   else
02404                     {
02405                       voptgenerror 
02406                         (FLG_TYPE,
02407                          message ("Function %s called with %d args, expects %d",
02408                                   exprNode_unparse (f),
02409                                   nargs, expectargs),
02410                          f->loc);
02411                     }
02412                 }
02413             }
02414         }
02415     }
02416 
02417   return special;
02418 }
02419 
02420 /*
02421 ** Check for undefined code sequences in function arguments:
02422 **
02423 **   one parameter sets something used by another parameter
02424 **   one parameter sets something set  by another parameter
02425 */
02426 
02427 static void 
02428 checkSequencingOne (exprNode f, exprNodeList args, 
02429                     /*@notnull@*/ exprNode el, int argno)
02430 {
02431   /*
02432   ** Do second loop, iff +undefunspec
02433   */
02434 
02435   int checkloop;
02436   int numloops = context_maybeSet (FLG_EVALORDERUNCON) ? 2 : 1;
02437   
02438   for (checkloop = 0; checkloop < numloops; checkloop++)
02439     {
02440       sRefSet thissets;
02441 
02442       if (checkloop == 0)
02443         {
02444           thissets = el->sets;
02445         }
02446       else
02447         {
02448           llassert (checkloop == 1);
02449           thissets = el->msets;
02450         }
02451       
02452       sRefSet_realElements (thissets, thisset)
02453         {
02454           int j;
02455 
02456           /*@access exprNodeList@*/
02457           for (j = 0; j < args->nelements; j++)
02458             {
02459               exprNode jl = args->elements[j];
02460               int thisargno = j + 1;
02461 
02462               if (thisargno != argno && exprNode_isDefined (jl))
02463                 {
02464                   sRefSet otheruses = jl->uses;
02465                   
02466                   if (sRef_isGlobal (sRef_getRootBase (jl->sref)) && 
02467                       sRefSet_hasUnconstrained (thissets))
02468                     {
02469                       voptgenerror
02470                         (FLG_EVALORDERUNCON,
02471                          /*@-sefparams@*/
02472                          message
02473                          ("%q used in argument %d may set "
02474                           "global variable %q used by argument %d: %s(%q)", 
02475                           cstring_capitalizeFree (sRefSet_unparseUnconstrained (thissets)),
02476                           /*@=sefparams@*/
02477                           argno,
02478                           sRef_unparse (sRef_getRootBase (jl->sref)),
02479                           thisargno,
02480                           exprNode_unparse (f), exprNodeList_unparse (args)),
02481                          el->loc);
02482                     }
02483 
02484                   if (sRefSet_member (otheruses, thisset))
02485                     {
02486                       if (sRef_isUnconstrained (thisset))
02487                         {
02488                           voptgenerror 
02489                             (FLG_EVALORDERUNCON,
02490                              message 
02491                              ("Unconstrained functions used in arguments %d (%q) "
02492                               "and %d (%s) may modify "
02493                               "or use global state in undefined way: %s(%q)",
02494                               argno,
02495                               sRefSet_unparseUnconstrainedPlain (otheruses),
02496                               thisargno, 
02497                               sRef_unconstrainedName (thisset),
02498                               exprNode_unparse (f), 
02499                               exprNodeList_unparse (args)),
02500                              el->loc);
02501                         }
02502                       else
02503                         {
02504                           voptgenerror 
02505                             (FLG_EVALORDER,
02506                              message 
02507                              ("Argument %d modifies %q, used by argument %d "
02508                               "(order of evaluation of actual parameters is "
02509                               "undefined): %s(%q)",
02510                               argno, sRef_unparse (thisset), thisargno, 
02511                               exprNode_unparse (f), exprNodeList_unparse (args)),
02512                              el->loc);
02513                         }
02514                     }
02515                   else 
02516                     {
02517                       sRefSet othersets = jl->sets;
02518                       
02519                       if (sRefSet_member (othersets, thisset))
02520                         {
02521                           if (sRef_isUnconstrained (thisset))
02522                             {
02523                               voptgenerror 
02524                                 (FLG_EVALORDERUNCON,
02525                                  message 
02526                                  ("Unconstrained functions used in "
02527                                   "arguments %d (%q) and %d (%s) may modify "
02528                                   "or use global state in undefined way: %s(%q)",
02529                                   argno, 
02530                                   sRefSet_unparseUnconstrainedPlain (othersets),
02531                                   thisargno, 
02532                                   sRef_unconstrainedName (thisset),
02533                                   exprNode_unparse (f), exprNodeList_unparse (args)),
02534                                  el->loc);
02535                             }
02536                           else
02537                             {
02538                               voptgenerror 
02539                                 (FLG_EVALORDER,
02540                                  message 
02541                                  ("Argument %d modifies %q, set by argument %d (order of"
02542                                   " evaluation of actual parameters is undefined): %s(%q)",
02543                                   argno, sRef_unparse (thisset), thisargno, 
02544                                   exprNode_unparse (f), exprNodeList_unparse (args)),
02545                                  el->loc);
02546                             }
02547                         }
02548                     }
02549                 }
02550             }
02551           /*@noaccess exprNodeList@*/
02552         } end_sRefSet_realElements;
02553     }
02554 }
02555 
02556 static void
02557 checkSequencing (exprNode f, exprNodeList args)
02558 {
02559   if (exprNodeList_size (args) > 1)
02560     {
02561       int i;
02562       exprNode el;
02563       
02564       /*@access exprNodeList*/
02565       
02566       for (i = 0; i < args->nelements; i++)
02567         {
02568           el = args->elements[i];
02569           
02570           if (!exprNode_isError (el))
02571             {
02572               checkSequencingOne (f, args, el, i + 1);
02573             }
02574         }
02575       /*@noaccess exprNodeList*/
02576     }
02577 }
02578 
02579 /*
02580 ** requires le = exprNode_getUentry (f) 
02581 */
02582 
02583 static void
02584 checkGlobMods (/*@notnull@*/ /*@dependent@*/ exprNode f,
02585                uentry le, exprNodeList args, 
02586                /*@notnull@*/ exprNode ret, int specialArgs)
02587 {
02588   bool isSpec = FALSE;
02589   bool hasMods = FALSE;
02590   cstring fname;
02591   globSet usesGlobs = globSet_undefined;
02592   sRefSet mods = sRefSet_undefined;
02593   bool freshMods = FALSE;
02594   uentryList params = uentryList_undefined;
02595 
02596   /*
02597   ** check globals and modifies
02598   */
02599 
02600   setCodePoint ();
02601   
02602   if (!uentry_isValid (le))
02603     {
02604       ctype fr = ctype_realType (f->typ);
02605 
02606       if (ctype_isFunction (fr))
02607         {
02608           params = ctype_argsFunction (fr);
02609         }
02610       else
02611         {
02612           params = uentryList_missingParams;
02613         }
02614 
02615       if (!context_getFlag (FLG_MODNOMODS) 
02616           && !context_getFlag (FLG_GLOBUNSPEC))
02617         {
02618                     checkUnspecCall (f, params, args);
02619         }
02620       
02621       return;
02622     }
02623 
02624   fname = uentry_rawName (le);
02625 
02626   setCodePoint ();
02627 
02628   if (uentry_isFunction (le))
02629     {
02630       params = uentry_getParams (le);
02631       mods = uentry_getMods (le);
02632       hasMods = uentry_hasMods (le);
02633       usesGlobs = uentry_getGlobs (le);
02634       isSpec = uentry_isSpecified (le);
02635     }
02636   else /* not a function */
02637     {
02638       ctype ct = ctype_realType (uentry_getType (le));
02639       
02640       llassertprint (uentry_isVar (le) && ctype_isFunction (ct),
02641                      ("checkModGlobs: uentry not a function: %s", 
02642                       uentry_unparse (le)));
02643       
02644       params = ctype_argsFunction (ct);
02645     }
02646 
02647   /*
02648   ** check globals
02649   */
02650 
02651   setCodePoint ();
02652 
02653     
02654   globSet_allElements (usesGlobs, el)
02655     {
02656       if (sRef_isValid (el))
02657         {
02658           if (sRef_isInternalState (el) || sRef_isSystemState (el))
02659             {
02660               context_usedGlobal (el);
02661               exprNode_checkUse (f, el, f->loc);
02662 
02663               if (context_checkInternalUse ())
02664                 {
02665                   if (!context_globAccess (el))
02666                     {
02667                       if (sRef_isSystemState (el)
02668                           && !context_getFlag (FLG_MODFILESYSTEM))
02669                         {
02670                           ;
02671                         }
02672                       else
02673                         {
02674                           voptgenerror
02675                             (FLG_INTERNALGLOBS,
02676                              message 
02677                              ("Called procedure %s may access %q, but "
02678                               "globals list does not include globals %s",
02679                               exprNode_unparse (f),
02680                               sRef_unparse (el),
02681                               cstring_makeLiteralTemp (sRef_isInternalState (el)
02682                                                        ? "internalState"
02683                                                        : "fileSystem")),
02684                              f->loc);
02685                         }
02686                     }
02687                 }
02688             }
02689           else if (sRef_isNothing (el) || sRef_isSpecState (el))
02690             {
02691               ;
02692             }
02693           else
02694             {
02695               uentry gle = sRef_getUentry (el);
02696               sRef sr = sRef_updateSref (el);
02697               
02698               if (sRef_isUndefGlob (el))
02699                 {
02700                   sRef_setDefined (sr, f->loc);
02701                   exprNode_checkSet (f, sr);
02702                 }
02703               else
02704                 {
02705                   /*
02706                   ** check definition
02707                   */
02708                   
02709                   if (sRef_isAllocated (el))
02710                     {
02711                       exprNode_checkSet (f, sr);
02712                     }
02713                   else
02714                     {
02715                       if (sRef_isStateUndefined (sr))
02716                         {
02717                           voptgenerror 
02718                             (FLG_GLOBSTATE,
02719                              message
02720                              ("%s %q used by function undefined before call: %s",
02721                               sRef_getScopeName (sr),
02722                               sRef_unparse (sr),
02723                               exprNode_unparse (f)),
02724                              f->loc);
02725                           sRef_setDefined (sr, f->loc);
02726                         }
02727                       exprNode_checkUse (f, sr, f->loc);
02728                     }
02729                   
02730                   checkGlobUse (gle, TRUE, f);
02731                 }
02732           
02733               if (sRef_isKilledGlob (el))
02734                 {
02735                   sRef_kill (sr, f->loc);
02736                   context_usedGlobal (sr);
02737                 }
02738             }
02739         }
02740     } end_globSet_allElements;
02741   
02742   /*
02743   ** check modifies
02744   */
02745 
02746   if (context_hasMods () || context_getFlag (FLG_MODNOMODS))
02747     {
02748       sRefSet smods = sRefSet_undefined;
02749 
02750       /*
02751       ** NEED to check for modifies anything
02752       */
02753 
02754       /*
02755       ** check each sRef that called function modifies (ml), is
02756       ** modifiable by tl
02757       */
02758 
02759       setCodePoint ();
02760 
02761       sRefSet_allElements (mods, s) /* s is something which may be modified */
02762         {
02763           if (sRef_isKindSpecial (s))
02764             {
02765               if (sRef_isSpecInternalState (s))
02766                 {
02767                   if (context_getFlag (FLG_MODINTERNALSTRICT))
02768                     {
02769                       exprNode_checkCallModifyVal (s, args, f, ret);
02770                     }
02771                   else
02772                     {
02773                       sRefSet mmods = context_modList ();
02774 
02775                       sRefSet_allElements (mmods, el)
02776                         {
02777                           if (sRef_isInternalState (el))
02778                             {
02779                               sRef_setModified (el);
02780                             }
02781                         } end_sRefSet_allElements ;
02782                     }
02783                 }
02784               else
02785                 {
02786                   exprNode_checkCallModifyVal (s, args, f, ret);
02787                 }
02788             }
02789           else
02790             {
02791               sRef rb = sRef_getRootBase (s);
02792               
02793               if (sRef_isGlobal (rb))
02794                 {
02795                   context_usedGlobal (rb);
02796                 }
02797               
02798               if (sRef_isFileStatic (s)
02799                   && !fileId_equal (fileloc_fileId (f->loc), 
02800                                     fileloc_fileId (uentry_whereDefined (le))))
02801                 {
02802                   smods = sRefSet_insert (smods, s);
02803                 }
02804               else
02805                 {
02806                   exprNode_checkCallModifyVal (s, args, f, ret);
02807                 }
02808             }
02809         } end_sRefSet_allElements;
02810 
02811       setCodePoint ();
02812 
02813       /*
02814       ** Static elements in modifies set can have nasty consequences.
02815       ** (I think...have not been able to reproduce a possible bug.)
02816       */
02817 
02818       if (!sRefSet_isDefined (smods))
02819         {
02820           mods = sRefSet_newCopy (mods);
02821           freshMods = TRUE;
02822           
02823           sRefSet_allElements (smods, el)
02824             {
02825               bool res = sRefSet_delete (mods, el);
02826               
02827               llassert (res);
02828             } end_sRefSet_allElements;
02829 
02830           sRefSet_free (smods);
02831         /*@-branchstate@*/
02832         } 
02833       /*@=branchstate@*/
02834     }
02835   else if (sRefSet_isDefined (mods))
02836     { /* just check observers */
02837       setCodePoint ();
02838 
02839       sRefSet_allElements (mods, s) /* s is something which may be modified */
02840         {
02841           sRef rb = sRef_getRootBase (s);
02842 
02843           setCodePoint ();
02844 
02845           if (sRef_isParam (rb))
02846             {
02847               sRef b = sRef_fixBaseParam (s, args);
02848 
02849               if (sRef_isObserver (b))
02850                 {
02851                   exprNode e = exprNodeList_nth (args, sRef_getParam (rb));
02852                   
02853                   if (optgenerror 
02854                       (FLG_MODOBSERVER,
02855                        message ("Function call may modify observer%q: %s", 
02856                                 sRef_unparsePreOpt (b), exprNode_unparse (e)),
02857                        exprNode_loc (e)))
02858                     {
02859                       sRef_showExpInfo (b);
02860                     }
02861                 }
02862             }
02863         } end_sRefSet_allElements;
02864     }
02865   else 
02866     {
02867       if (!hasMods) /* no specified modifications */
02868         {
02869           if (context_getFlag (FLG_MODOBSERVERUNCON))
02870             {
02871               exprNodeList_elements (args, e)
02872                 {
02873                   if (exprNode_isDefined (e))
02874                     {
02875                       sRef s = exprNode_getSref (e);
02876                       
02877                       if (sRef_isObserver (s) 
02878                           && ctype_isMutable (sRef_getType (s)))
02879                         {
02880                           if (optgenerror 
02881                               (FLG_MODOBSERVERUNCON,
02882                                message
02883                                ("Call to unconstrained function %s may modify observer%q: %s", 
02884                                 exprNode_unparse (f),
02885                                 sRef_unparsePreOpt (s), exprNode_unparse (e)),
02886                                exprNode_loc (e)))
02887                             {
02888                               sRef_showExpInfo (s);
02889                             }
02890                         }
02891                     }
02892                 } end_exprNodeList_elements; 
02893             }
02894         }
02895     }
02896   
02897   checkAnyCall (f, fname, params, args, hasMods, mods, isSpec, specialArgs);
02898 
02899   ret->uses = sRefSet_union (ret->uses, f->uses);
02900   ret->sets = sRefSet_union (ret->sets, f->sets);
02901   ret->msets = sRefSet_union (ret->msets, f->msets);
02902 
02903   if (freshMods)
02904     {
02905       /*
02906       ** Spurious errors reported, because lclint can't tell
02907       ** mods must be fresh if freshMods is true.
02908       */
02909 
02910       /*@i@*/ sRefSet_free (mods);
02911     }
02912 
02913   setCodePoint ();
02914 }
02915 
02916 void checkGlobUse (uentry glob, bool isCall, /*@notnull@*/ exprNode e)
02917 {
02918   if (uentry_isVar (glob))
02919     {
02920       if (context_inFunctionLike ())
02921         {
02922           sRef sr = uentry_getSref (glob);
02923 
02924           context_usedGlobal (sr);
02925           
02926           if (context_checkGlobUse (glob))
02927             {
02928               if (!context_globAccess (sr))
02929                 {
02930                   if (isCall)
02931                     {
02932                       voptgenerror
02933                         (FLG_GLOBALS,
02934                          message ("Called procedure %s may access %s %q",
02935                                   exprNode_unparse (e), 
02936                                   sRef_unparseScope (sr),
02937                                   uentry_getName (glob)),
02938                          e->loc);
02939                     }
02940                   else
02941                     {
02942                       voptgenerror 
02943                         (FLG_GLOBALS,
02944                          message ("Undocumented use of %s %s", 
02945                                   sRef_unparseScope (sr),
02946                                   exprNode_unparse (e)),
02947                          e->loc);
02948                     }
02949                 }
02950             }
02951         }
02952     }
02953   else
02954     {
02955       llbug (message ("Global not variable: %q", uentry_unparse (glob)));
02956     }
02957 }  
02958 
02959 static /*@only@*/ exprNode
02960 functionCallSafe (/*@only@*/ /*@notnull@*/ exprNode f,
02961                   ctype t, /*@keep@*/ exprNodeList args)
02962 {
02963   /* requires f is a non-error exprNode, with type function */
02964   cstring fname = exprNode_unparse (f);
02965   uentry le = exprNode_getUentry (f);
02966   exprNode ret = exprNode_createPartialCopy (f);
02967   int special;
02968 
02969   setCodePoint ();
02970         
02971   ret->typ = ctype_returnValue (t);
02972   ret->kind = XPR_CALL;
02973 
02974   ret->edata = exprData_makeCall (f, args);
02975 
02976   /*
02977   ** Order of these steps is very important!  
02978   **
02979   ** Must check for argument dependencies before messing up uses and sets.
02980   */
02981 
02982   if (context_getFlag (FLG_EVALORDER))
02983     {
02984       exprNodeList_elements (args, current)
02985         {
02986           if (exprNode_isDefined (current))
02987             {
02988               exprNode_addUse (current, current->sref);
02989             }
02990         } end_exprNodeList_elements;
02991 
02992       if (context_maybeSet (FLG_EVALORDER) || context_maybeSet (FLG_EVALORDERUNCON))
02993         {
02994           checkSequencing (f, args); 
02995         }
02996       
02997       exprNodeList_elements (args, current)
02998         {
02999           if (exprNode_isDefined (current) && sRef_isMeaningful (current->sref))
03000             {
03001               exprNode_addUse (ret, sRef_makeDerived (current->sref));
03002             }
03003         } end_exprNodeList_elements ;
03004     }
03005 
03006   special = checkArgs (le, f, t, args, ret); 
03007   checkGlobMods (f, le, args, ret, special); 
03008 
03009   setCodePoint ();
03010 
03011   if (uentry_isValid (le)
03012       && (uentry_isFunction (le) 
03013           || (uentry_isVariable (le)
03014               && ctype_isFunction (uentry_getType (le)))))
03015     {
03016       exitkind exk = uentry_getExitCode (le);
03017 
03018       /* f->typ is already set to the return type */
03019 
03020       ret->sref = uentry_returnedRef (le, args);
03021 
03022       if (uentry_isFunction (le) && exprNodeList_size (args) >= 1)
03023         {
03024           qual nullPred = uentry_nullPred (le);
03025 
03026           if (qual_isTrueNull (nullPred))
03027             {
03028               exprNode arg = exprNodeList_head (args);
03029 
03030               if (exprNode_isDefined (arg))
03031                 {
03032                   ret->guards = guardSet_addFalseGuard (ret->guards, arg->sref);
03033                 }
03034             }
03035           else if (qual_isFalseNull (nullPred))
03036             {
03037               exprNode arg = exprNodeList_head (args);
03038               
03039               if (exprNode_isDefined (arg))
03040                 {
03041                   ret->guards = guardSet_addTrueGuard (ret->guards, arg->sref);
03042                 }
03043             }
03044           else
03045             {
03046               llassert (qual_isUnknown (nullPred));
03047             }
03048         }
03049       
03050       if (exitkind_isConditionalExit (exk))
03051         {
03052           /*
03053           ** True exit is: 
03054           **    if (arg0) then { exit! } else { ; }
03055           ** False exit is:
03056           **    if (arg0) then { ; } else { exit! }
03057           */
03058 
03059           exprNode firstArg;
03060 
03061           llassert (!exprNodeList_isEmpty (args));
03062           firstArg = exprNodeList_head (args);
03063 
03064           if (exprNode_isDefined (firstArg)
03065               && !guardSet_isEmpty (firstArg->guards))
03066             {
03067               usymtab_trueBranch (guardSet_undefined);
03068               usymtab_altBranch (guardSet_undefined);
03069               
03070               if (exitkind_isTrueExit (exk))
03071                 {
03072                   usymtab_popBranches (firstArg, 
03073                                        exprNode_makeMustExit (), 
03074                                        exprNode_undefined,
03075                                        TRUE, TRUEEXITCLAUSE);
03076                 }
03077               else
03078                 {
03079                   usymtab_popBranches (firstArg,
03080                                        exprNode_undefined,
03081                                        exprNode_makeMustExit (), 
03082                                        TRUE, FALSEEXITCLAUSE);
03083                 }
03084             }
03085 
03086           ret->exitCode = XK_MAYEXIT;
03087         }
03088       else if (exitkind_mustExit (exk))
03089         {
03090           ret->exitCode = XK_MUSTEXIT;
03091         }
03092       else if (exitkind_couldExit (exk))
03093         {
03094           ret->exitCode = XK_MAYEXIT;
03095         }
03096       else
03097         {
03098           ;
03099         }
03100       
03101       if (cstring_equalLit (fname, "exit"))
03102         {
03103           if (exprNodeList_size (args) == 1)
03104             {
03105               exprNode arg = exprNodeList_head (args);
03106               
03107               if (exprNode_isDefined (arg) && exprNode_knownIntValue (arg))
03108                 {
03109                   long int val = multiVal_forceInt (exprNode_getValue (arg));
03110                   
03111                   if (val != 0)
03112                     {
03113                       voptgenerror
03114                         (FLG_EXITARG,
03115                          message 
03116                          ("Argument to exit has implementation defined behavior: %s",
03117                           exprNode_unparse (arg)),
03118                          exprNode_loc (arg));
03119                     }
03120                 }
03121             }
03122         }
03123     }
03124   else
03125     {
03126       ret->sref = defref;
03127       exprNode_checkSetAny (ret, uentry_rawName (le));
03128     }
03129 
03130   return (ret);
03131 }
03132 
03133 /*
03134 ** this is yucky!  should keep the uentry as part of exprNode!
03135 */
03136 
03137 /*@observer@*/ uentry
03138 exprNode_getUentry (exprNode e)
03139 {
03140   if (exprNode_isError (e))
03141     {
03142       return uentry_undefined;
03143     }
03144   else
03145     {
03146       cstring s = exprNode_rootVarName (e);
03147       uentry ue = usymtab_lookupSafe (s);
03148 
03149       return ue;
03150     }
03151 }
03152 
03153 exprNode 
03154 exprNode_makeInitBlock (lltok brace, /*@only@*/ exprNodeList inits)
03155 {
03156   exprNode ret = exprNode_createPlain (ctype_unknown);
03157 
03158   ret->kind = XPR_INITBLOCK;
03159   ret->edata = exprData_makeCall (exprNode_undefined, inits);
03160   ret->loc = fileloc_update (ret->loc, lltok_getLoc (brace));
03161 
03162   return (ret);
03163 }
03164 
03165 exprNode
03166 exprNode_functionCall (/*@only@*/ exprNode f, /*@only@*/ exprNodeList args)
03167 {
03168   ctype t;
03169 
03170   setCodePoint ();
03171 
03172   if (exprNode_isUndefined (f))
03173     {
03174       exprNode_free (f);
03175       exprNodeList_free (args);
03176       return exprNode_undefined;
03177     }
03178 
03179   t = exprNode_getType (f);
03180 
03181   if (sRef_isLocalVar (f->sref))
03182     {
03183       exprNode_checkUse (f, f->sref, f->loc);
03184 
03185       if (sRef_possiblyNull (f->sref))
03186         {
03187           if (!usymtab_isGuarded (f->sref))
03188             {
03189               if (optgenerror (FLG_NULLDEREF,
03190                                message ("Function call using %s pointer %q", 
03191                                         sRef_nullMessage (f->sref),
03192                                         sRef_unparse (f->sref)),
03193                                f->loc))
03194                 {
03195                   sRef_showNullInfo (f->sref);
03196                   sRef_setNullError (f->sref);
03197                 }
03198             }
03199         }
03200     }
03201 
03202   setCodePoint ();
03203 
03204   if (ctype_isRealFunction (t))
03205     {
03206       exprNode ret = functionCallSafe (f, t, args);
03207       setCodePoint ();
03208       return ret;
03209     }
03210   else if (ctype_isUnknown (t))
03211     {
03212       exprNode ret = exprNode_createPartialCopy (f);
03213       cstring tstring;
03214 
03215       setCodePoint ();
03216       
03217       ret->typ = t;
03218       exprNodeList_elements (args, current)
03219         {
03220           if (exprNode_isDefined (current))
03221             {
03222               exprNode_checkUse (ret, current->sref, ret->loc);
03223 
03224               /* 
03225               ** also, anything derivable from current->sref may be used 
03226               */
03227 
03228               exprNode_addUse (ret, sRef_makeDerived (current->sref));
03229               exprNode_mergeUSs (ret, current);
03230             }
03231         } end_exprNodeList_elements;
03232 
03233       ret->edata = exprData_makeCall (f, args);
03234       ret->kind = XPR_CALL;
03235 
03236       tstring = cstring_copy (exprNode_unparse (f));
03237 
03238       cstring_markOwned (tstring);
03239       exprNode_checkSetAny (ret, tstring);
03240 
03241       return (ret);
03242     }
03243   else
03244     {
03245       voptgenerror (FLG_TYPE,
03246                     message ("Call to non-function (type %t): %s", t, 
03247                              exprNode_unparse (f)),
03248                     f->loc);
03249       exprNode_free (f);
03250       exprNodeList_free (args);
03251 
03252       return (exprNode_makeError ());
03253     }
03254 }
03255 
03256 exprNode
03257 exprNode_fieldAccess (/*@only@*/ exprNode s, /*@only@*/ cstring f)
03258 {
03259   exprNode ret = exprNode_createPartialCopy (s);
03260 
03261   ret->kind = XPR_FACCESS;
03262 
03263   if (exprNode_isError (s))
03264     {
03265       ret->edata = exprData_makeField (s, f);
03266       return ret;
03267     }
03268   else
03269     {
03270       ctype t = exprNode_getType (s);
03271       ctype tr = ctype_realType (t);
03272       
03273       checkMacroParen (s);
03274 
03275       ret->edata = exprData_makeField (s, f);
03276       
03277       if (ctype_isStructorUnion (tr))
03278         {
03279           uentry tf = uentryList_lookupField (ctype_getFields (tr), f);
03280 
03281           if (uentry_isUndefined (tf))
03282             {
03283               voptgenerror (FLG_TYPE,
03284                             message ("Access non-existent field %s of %t: %s", f, t, 
03285                                      exprNode_unparse (ret)),
03286                             s->loc);
03287               
03288               return (ret);
03289             }
03290           else
03291             {
03292               uentry_setUsed (tf, exprNode_loc (ret));
03293 
03294               ret->typ = uentry_getType (tf); 
03295               checkSafeUse (ret, s->sref);
03296               
03297               ret->sref = sRef_makeField (s->sref, uentry_rawName (tf));
03298               return (ret);
03299             }
03300         }
03301       else /* isStructorUnion */
03302         {
03303           if (ctype_isRealAbstract (tr))
03304             {
03305               voptgenerror
03306                 (FLG_ABSTRACT,
03307                  message ("Access field of abstract type (%t): %s.%s", 
03308                           t, exprNode_unparse (s), f),
03309                  s->loc);
03310               ret->typ = ctype_unknown;
03311             }
03312           else
03313             {
03314               if (ctype_isKnown (tr))
03315                 {
03316                   voptgenerror 
03317                     (FLG_TYPE,
03318                      message
03319                      ("Access field of non-struct or union (%t): %s.%s",
03320                       t, exprNode_unparse (s), f),
03321                      s->loc);
03322 
03323                   ret->typ = ctype_unknown;
03324                 }
03325               else
03326                 {
03327                   cstring sn = cstring_copy (f);
03328 
03329                   checkSafeUse (ret, s->sref);
03330                   cstring_markOwned (sn);
03331                   ret->sref = sRef_makeField (s->sref, sn);
03332 
03333                   return (ret);
03334                 }
03335             }
03336           return (ret);
03337         }
03338     }
03339   BADEXIT;
03340 }
03341 
03342 exprNode
03343 exprNode_addParens (/*@only@*/ lltok lpar, /*@only@*/ exprNode e)
03344 {
03345   exprNode ret = exprNode_createPartialCopy (e);
03346 
03347   ret->loc = fileloc_update (ret->loc, lltok_getLoc (lpar));
03348   ret->kind = XPR_PARENS;
03349   ret->edata = exprData_makeUop (e, lpar);
03350 
03351   if (!exprNode_isError (e))
03352     {
03353       ret->exitCode = e->exitCode;
03354       ret->canBreak = e->canBreak;
03355       ret->mustBreak = e->mustBreak;
03356       ret->isJumpPoint = e->isJumpPoint;
03357       ret->sref = e->sref;
03358     }
03359 
03360   return ret;
03361 }
03362 
03363 exprNode
03364 exprNode_arrowAccess (/*@only@*/ exprNode s, /*@only@*/ cstring f)
03365 {
03366   exprNode ret = exprNode_createPartialCopy (s);
03367 
03368   ret->edata = exprData_makeField (s, f);
03369   ret->kind = XPR_ARROW;
03370 
03371   if (exprNode_isError (s))
03372     {
03373       return (ret);
03374     }
03375   else
03376     {
03377        ctype t = exprNode_getType (s);
03378        ctype tr = ctype_realType (t);
03379 
03380        checkMacroParen (s);
03381 
03382        (void) ctype_fixArrayPtr (tr); /* REWRITE THIS */
03383 
03384        if (ctype_isRealPointer (tr)) 
03385          {
03386            ctype b = ctype_realType (ctype_baseArrayPtr (tr));
03387            
03388            if (ctype_isStructorUnion (b))
03389              {
03390                uentry fentry = uentryList_lookupField (ctype_getFields (b), f);
03391                
03392                if (sRef_isKnown (s->sref) && sRef_possiblyNull (s->sref))
03393                  {
03394                    if (!usymtab_isGuarded (s->sref) && !context_inProtectVars ())
03395                      {
03396                        if (optgenerror 
03397                            (FLG_NULLDEREF,
03398                             message ("Arrow access from %s pointer%q: %s", 
03399                                      sRef_nullMessage (s->sref),
03400                                      sRef_unparsePreOpt (s->sref),
03401                                      exprNode_unparse (ret)),
03402                             s->loc))
03403                          {
03404                            sRef_showNullInfo (s->sref);
03405                            sRef_setNullError (s->sref);
03406                          }
03407                      }
03408                  }
03409                
03410                if (uentry_isUndefined (fentry))
03411                  {
03412                    voptgenerror 
03413                      (FLG_TYPE,
03414                       message ("Access non-existent field %s of %t: %s", 
03415                                f, t, exprNode_unparse (ret)),
03416                       s->loc);
03417                    ret->typ = ctype_unknown;
03418                    
03419                    return (ret);
03420                  }
03421                else
03422                  {
03423                    /*
03424                    ** was safeUse: shouldn't be safe!
03425                    **
03426                    ** to do rec->field
03427                    ** rec must be defined,
03428                    ** *rec must be allocated
03429                    ** rec->field need only be defined it if is an rvalue
03430                    */
03431                    
03432                    uentry_setUsed (fentry, exprNode_loc (ret));
03433                    ret->typ = uentry_getType (fentry);
03434                    
03435                    exprNode_checkUse (ret, s->sref, s->loc);
03436                    
03437                    /* exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc); */
03438                    ret->sref = sRef_makeArrow (s->sref, uentry_rawName (fentry));
03439                    return (ret);
03440                  }
03441              }
03442            else /* Pointer to something that is not a struct or union*/
03443              {
03444                if (ctype_isRealAbstract (tr))
03445                  {
03446                    ctype xrt = ctype_forceRealType (tr);
03447                    
03448                    voptgenerror 
03449                      (FLG_ABSTRACT,
03450                       message ("Arrow access field of abstract type (%t): %s->%s", 
03451                                t, exprNode_unparse (s), f),
03452                       s->loc);
03453                    
03454                    /*
03455                    ** Set the state correctly, as if the abstraction is broken.
03456                    */
03457                    
03458                    if (ctype_isRealPointer (xrt) &&
03459                        (b = ctype_realType (ctype_baseArrayPtr (xrt)),
03460                         ctype_isStructorUnion (b)))
03461                      {
03462                        uentry fentry = uentryList_lookupField (ctype_getFields (b), f);
03463                        ret->typ = uentry_getType (fentry);
03464                        ret->sref = sRef_makeArrow (s->sref, uentry_rawName (fentry));
03465                      }
03466                    else
03467                      {
03468                        ret->typ = ctype_unknown;
03469                        ret->sref = sRef_undefined;
03470                      }
03471                  }
03472                else /* not a struct, union or abstract */
03473                  {
03474                    if (ctype_isUnknown (tr)) {
03475                      cstring sn = cstring_copy (f);
03476                      
03477                      DPRINTF (("Here: %s", exprNode_unparse (s)));
03478                      
03479                      exprNode_checkUse (ret, s->sref, s->loc);
03480                      exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc);
03481                      
03482                      cstring_markOwned (sn);
03483                      ret->sref = sRef_makeArrow (s->sref, sn);
03484                      
03485                      ret->kind = XPR_ARROW;
03486                      return (ret);
03487                    } else {
03488                      voptgenerror 
03489                        (FLG_TYPE,
03490                         message ("Arrow access field of non-struct or union "
03491                                  "pointer (%t): %s->%s",
03492                                  t, exprNode_unparse (s), f),
03493                         s->loc);
03494                      
03495                      ret->typ = ctype_unknown;
03496                      ret->sref = sRef_undefined;
03497                    }
03498                  }
03499              }
03500          }
03501        else /* its not a pointer */
03502          {
03503            if (!ctype_isUnknown (tr))
03504              {
03505                voptgenerror 
03506                  (FLG_TYPE,
03507                   message ("Arrow access of non-pointer (%t): %s->%s",
03508                            t, exprNode_unparse (s), f),
03509                   s->loc);
03510                
03511                ret->typ = ctype_unknown;
03512                ret->sref = sRef_undefined;
03513              }
03514            else
03515              {
03516                cstring sn = cstring_copy (f);
03517                
03518                DPRINTF (("Here: %s", exprNode_unparse (s)));
03519                
03520                exprNode_checkUse (ret, s->sref, s->loc);
03521                exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc);
03522                
03523                cstring_markOwned (sn);
03524                ret->sref = sRef_makeArrow (s->sref, sn);
03525                
03526                ret->kind = XPR_ARROW;
03527                return (ret);
03528              }
03529          }
03530 
03531       return (ret);
03532     }
03533   BADEXIT;
03534 }
03535 
03536 /*
03537 ** only postOp's in C: i++ and i--
03538 */
03539 
03540 exprNode
03541 exprNode_postOp (/*@only@*/ exprNode e, /*@only@*/ lltok op)
03542 {
03543   /* check modification also */
03544   /* cstring opname = lltok_unparse (op);*/
03545   ctype t;
03546   exprNode ret = exprNode_createPartialCopy (e);
03547 
03548   ret->loc = fileloc_update (ret->loc, lltok_getLoc (op));
03549   ret->kind = XPR_POSTOP;
03550   ret->edata = exprData_makeUop (e, op);
03551 
03552   if (!exprNode_isDefined (e))
03553     {
03554       return ret;
03555     }
03556 
03557   checkMacroParen (e);
03558 
03559   exprNode_checkUse (ret, e->sref, e->loc);
03560   exprNode_checkSet (ret, e->sref);
03561 
03562   t = exprNode_getType (e);
03563 
03564   if (sRef_isUnsafe (e->sref))
03565     {
03566       voptgenerror (FLG_MACROPARAMS,
03567                     message ("Operand of %s is macro parameter (non-functional): %s%s", 
03568                              lltok_unparse (op), exprNode_unparse (e), lltok_unparse (op)),
03569                     e->loc);
03570       sRef_makeSafe (e->sref);
03571       sRef_makeSafe (ret->sref);
03572     }
03573 
03574   if (ctype_isForceRealNumeric (&t) || ctype_isRealAP (t))
03575     {
03576       ret->typ = e->typ;
03577     }
03578   else
03579     {
03580       if (ctype_isRealAbstract (t))
03581         {
03582           voptgenerror 
03583             (FLG_ABSTRACT,
03584              message ("Operand of %s is abstract type (%t): %s",
03585                       lltok_unparse (op), t, exprNode_unparse (e)),
03586              e->loc);
03587         }
03588       else
03589         {
03590           voptgenerror 
03591             (FLG_TYPE,
03592              message ("Operand of %s is non-numeric (%t): %s",
03593                       lltok_unparse (op), t, exprNode_unparse (e)),
03594              e->loc);
03595         }
03596       ret->typ = ctype_unknown;
03597     }
03598 
03599   /* if (ctype_isZero (t)) e->typ = ctype_int; */
03600 
03601   exprNode_checkModify (e, ret);
03602 
03603   return ret;
03604 }
03605 
03606 exprNode
03607 exprNode_preOp (/*@only@*/ exprNode e, /*@only@*/ lltok op)
03608 {
03609   bool checkMod = FALSE;
03610   ctype te, tr;
03611   int opid = lltok_getTok (op);
03612   exprNode ret = exprNode_createSemiCopy (e);
03613 
03614   exprNode_copySets (ret, e);
03615 
03616   multiVal_free (ret->val);
03617   ret->val = multiVal_undefined;
03618   ret->loc = fileloc_update (ret->loc, lltok_getLoc (op));
03619   ret->kind = XPR_PREOP;  
03620   ret->edata = exprData_makeUop (e, op);
03621   
03622   if (exprNode_isError (e))
03623     {
03624       return ret;
03625     }
03626   
03627   checkMacroParen (e);
03628   
03629   te = exprNode_getType (e);
03630   tr = ctype_realType (te);
03631   
03632   if (opid != TAMPERSAND)
03633     {
03634       exprNode_checkUse (ret, e->sref, e->loc);
03635       
03636       if (ctype_isRealAbstract (tr)
03637           && (!(ctype_isRealBool (te) && (opid == TEXCL))))
03638         {
03639           if (optgenerror (FLG_ABSTRACT,
03640                            message ("Operand of %s is abstract type (%t): %s",
03641                                     lltok_unparse (op), tr,
03642                                     exprNode_unparse (ret)),
03643                            e->loc))
03644             {
03645               tr = te = ctype_unknown;
03646               ret->typ = ctype_unknown;
03647               sRef_setNullError (e->sref);
03648             }
03649         }
03650     }
03651   
03652   switch (opid)
03653     {
03654     case INC_OP:
03655     case DEC_OP:                /* should also check modification! */
03656       if (sRef_isMacroParamRef (e->sref))
03657         {
03658           voptgenerror 
03659             (FLG_MACROPARAMS,
03660              message ("Operand of %s is macro parameter (non-functional): %s", 
03661                       lltok_unparse (op), exprNode_unparse (ret)),
03662              e->loc);
03663         }
03664       else
03665         {
03666           exprNode_checkSet (ret, e->sref);
03667         }
03668       
03669       if (ctype_isForceRealNumeric (&tr) || ctype_isRealAP (tr))
03670         {
03671         }
03672       else
03673         {
03674           if (context_msgStrictOps ())
03675             {
03676               voptgenerror 
03677                 (FLG_STRICTOPS,
03678                  message ("Operand of %s is non-numeric (%t): %s",
03679                           lltok_unparse (op), te, exprNode_unparse (ret)),
03680                  e->loc);
03681             }
03682           ret->typ = ctype_int;
03683         }
03684       
03685       checkMod = TRUE;
03686       break;
03687       
03688     case TMINUS:
03689     case TPLUS:
03690       if (ctype_isForceRealNumeric (&tr))
03691         {
03692           if (opid == TMINUS)
03693             {
03694               ret->val = multiVal_invert (exprNode_getValue (e));
03695             }
03696           else
03697             {
03698               ret->val = multiVal_copy (exprNode_getValue (e));
03699             }
03700         }
03701       else
03702         {
03703           if (context_msgStrictOps ())
03704             {
03705               voptgenerror 
03706                 (FLG_STRICTOPS,
03707                  message ("Operand of %s is non-numeric (%t): %s",
03708                           lltok_unparse (op), te, exprNode_unparse (ret)),
03709                  e->loc);
03710             }
03711 
03712           ret->typ = ctype_int;
03713         }
03714       break;
03715       
03716     case TEXCL:         /* maybe this should be restricted */
03717       guardSet_flip (ret->guards);      
03718 
03719       if (ctype_isRealBool (te))
03720         {
03721          ;
03722         }
03723       else
03724         {
03725           if (ctype_isRealPointer (tr))
03726             {
03727               if (sRef_isKnown (e->sref))
03728                 {
03729                   ret->guards = guardSet_addFalseGuard (ret->guards, e->sref);
03730                 }
03731 
03732               voptgenerror2n
03733                 (FLG_BOOLOPS, FLG_PTRNEGATE,
03734                  message ("Operand of %s is non-boolean (%t): %s",
03735                           lltok_unparse (op), te, exprNode_unparse (ret)),
03736                  e->loc);
03737             }
03738           else
03739             {
03740               voptgenerror
03741                 (FLG_BOOLOPS,
03742                  message ("Operand of %s is non-boolean (%t): %s",
03743                           lltok_unparse (op), te, exprNode_unparse (ret)),
03744                  e->loc);
03745             }
03746           
03747           ret->typ = ctype_bool;
03748         }
03749       break;
03750       
03751     case TTILDE:
03752       if (ctype_isForceRealInt (&tr))
03753         {
03754         }
03755       else
03756         {
03757           if (context_msgStrictOps ())
03758             {
03759               voptgenerror 
03760                 (FLG_STRICTOPS,
03761                  message ("Operand of %s is non-integer (%t): %s",
03762                           lltok_unparse (op), te, exprNode_unparse (ret)), 
03763                  e->loc);
03764             }
03765 
03766           if (ctype_isInt (e->typ))
03767             {
03768               ret->typ = e->typ;
03769             }
03770           else
03771             {
03772               ret->typ = ctype_int;
03773             }
03774         }       
03775       break;
03776       
03777     case TAMPERSAND:
03778       ret->typ = ctype_makePointer (e->typ);
03779 
03780       if (sRef_isKnown (e->sref))
03781         {
03782           ret->sref = sRef_makeAddress (e->sref);
03783         }
03784       
03785       break;
03786       
03787     case TMULT:
03788       
03789       if (ctype_isAP (tr))
03790         {
03791           ret->typ = ctype_baseArrayPtr (e->typ);
03792         }
03793       else
03794         {
03795           if (ctype_isKnown (te))
03796             {
03797               if (ctype_isFunction (te))
03798                 {
03799                   ret->typ = e->typ;
03800 
03801                   voptgenerror
03802                     (FLG_FCNDEREF,
03803                      message ("Dereference of function type (%t): %s",
03804                               te, exprNode_unparse (ret)),
03805                      e->loc);
03806                 }
03807               else
03808                 {
03809                   voptgenerror (FLG_TYPE,
03810                                 message ("Dereference of non-pointer (%t): %s",
03811                                          te, exprNode_unparse (ret)),
03812                                 e->loc);
03813                   ret->typ = ctype_unknown;
03814                 }
03815             }
03816           else
03817             {
03818               ret->typ = ctype_unknown;
03819             }
03820           
03821         }
03822       
03823       if (sRef_isKnown (e->sref))
03824         {
03825           if (sRef_possiblyNull (e->sref))
03826             {
03827               if (!usymtab_isGuarded (e->sref) && !context_inProtectVars ())
03828                 {
03829                   if (optgenerror 
03830                       (FLG_NULLDEREF,
03831                        message ("Dereference of %s pointer %q: %s", 
03832                                 sRef_nullMessage (e->sref),
03833                                 sRef_unparse (e->sref),
03834                                 exprNode_unparse (ret)),
03835                        e->loc))
03836                     {
03837                       sRef_showNullInfo (e->sref);
03838                       sRef_setNotNull (e->sref, e->loc); /* suppress future messages */
03839                     }
03840                 }
03841             }
03842           
03843           ret->sref = sRef_makePointer (e->sref);
03844         }
03845       break;
03846       
03847     default:
03848       llbug (message ("exprNode_preOp: unhandled op: %s", lltok_unparse (op)));
03849     }
03850 
03851   if (checkMod)
03852     {
03853       exprNode_checkModify (e, ret);
03854     }
03855 
03856   return ret;
03857 }
03858 
03859 /*
03860 ** any reason to disallow sizeof (abstract type) ?
03861 */
03862 
03863 /*
03864 ** used by both sizeof
03865 */
03866 
03867 static
03868 ctype sizeof_resultType (void)
03869 {
03870   static ctype sizet = ctype_unknown;
03871 
03872   if (ctype_isUnknown (sizet))
03873     {
03874       if (usymtab_existsType (cstring_makeLiteralTemp ("size_t")))
03875         {
03876           sizet = uentry_getAbstractType (usymtab_lookup (cstring_makeLiteralTemp ("size_t")));
03877         }
03878       else
03879         {
03880                   sizet = ctype_ulint;
03881         }
03882     }
03883   return sizet;
03884 }
03885 
03886 exprNode
03887 exprNode_sizeofType (/*@only@*/ qtype qt)
03888 {
03889   exprNode ret = exprNode_create (sizeof_resultType ());
03890   ctype ct = qtype_getType (qt);
03891 
03892   ret->kind = XPR_SIZEOFT;
03893   ret->edata = exprData_makeSizeofType (qt);
03894 
03895   voptgenerror (FLG_SIZEOFTYPE,
03896                 message ("Parameter to sizeof is type %s: %s",
03897                          ctype_unparse (ct),
03898                          exprNode_unparse (ret)),
03899                 ret->loc);
03900   
03901   return (ret);
03902 }
03903 
03904 exprNode
03905 exprNode_alignofType (/*@only@*/ qtype qt)
03906 {
03907   exprNode ret = exprNode_create (sizeof_resultType ());
03908   ctype ct = qtype_getType (qt);
03909 
03910   ret->kind = XPR_ALIGNOFT;
03911   ret->edata = exprData_makeSizeofType (qt);
03912 
03913   voptgenerror (FLG_SIZEOFTYPE,
03914                 message ("Parameter to alignof is type %s: %s",
03915                          ctype_unparse (ct),
03916                          exprNode_unparse (ret)),
03917                 ret->loc);
03918   
03919   return (ret);
03920 }
03921 
03922 exprNode exprNode_offsetof (qtype qt, cstringList s)
03923 {
03924   exprNode ret = exprNode_create (sizeof_resultType ());
03925   ctype ct = qtype_getType (qt);
03926 
03927   ret->kind = XPR_OFFSETOF;
03928   ret->edata = exprData_makeOffsetof (qt, s);
03929 
03930   if (!ctype_isRealSU (ct))
03931     {
03932       voptgenerror (FLG_TYPE,
03933                     message ("First parameter to offsetof is not a "
03934                              "struct or union type (type %s): %s",
03935                              ctype_unparse (ct),
03936                              exprNode_unparse (ret)),
03937                     ret->loc);
03938     }
03939   else
03940     {
03941       ctype lt = ct;
03942 
03943       cstringList_elements (s, el) {
03944         uentryList fields;
03945         uentry fld;
03946 
03947         if (ctype_isUndefined (lt))
03948           {
03949             break;
03950           } 
03951         else if (!ctype_isRealSU (lt))
03952           {
03953             voptgenerror (FLG_TYPE,
03954                           message ("Inner offsetof type is not a "
03955                                    "struct or union type (type %s before field %s): %s",
03956                                    ctype_unparse (lt), el,
03957                                    exprNode_unparse (ret)),
03958                           ret->loc);
03959             break;
03960           }
03961         else 
03962           {
03963             fields = ctype_getFields (ctype_realType (lt));
03964             fld = uentryList_lookupField (fields, el);
03965             DPRINTF (("Try: %s / %s", ctype_unparse (lt), el));
03966             
03967             if (uentry_isUndefined (fld))
03968               {
03969                 if (ctype_equal (lt, ct)) {
03970                   voptgenerror (FLG_TYPE,
03971                                 message ("Field %s in offsetof is not the "
03972                                          "name of a field of %s: %s",
03973                                          el,
03974                                          ctype_unparse (ct),
03975                                          exprNode_unparse (ret)),
03976                                 ret->loc);
03977                 } else {
03978                   voptgenerror (FLG_TYPE,
03979                                 message ("Deep field %s in offsetof is not the "
03980                                          "name of a field of %s: %s",
03981                                          el,
03982                                          ctype_unparse (lt),
03983                                          exprNode_unparse (ret)),
03984                                 ret->loc);
03985                 }
03986               }
03987             else 
03988               {
03989                 lt = uentry_getType (fld);
03990               }
03991           }
03992       } end_cstringList_elements;
03993 
03994       /* Should report error if its a bit field - behavior is undefined! */
03995     }
03996   
03997   return (ret);
03998 }
03999 
04000 /*@only@*/ exprNode
04001 exprNode_sizeofExpr (/*@only@*/ exprNode e)
04002 {
04003   exprNode ret;
04004 
04005   if (exprNode_isUndefined (e))
04006     {
04007       ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
04008       ret->edata = exprData_makeSingle (e);
04009       ret->typ = sizeof_resultType ();
04010       ret->kind = XPR_SIZEOF;
04011     }
04012   else
04013     {
04014       uentry u = exprNode_getUentry (e);
04015 
04016       ret = exprNode_createPartialCopy (e);
04017       ret->edata = exprData_makeSingle (e);
04018 
04019       ret->typ = sizeof_resultType ();
04020       ret->kind = XPR_SIZEOF;
04021 
04022       if (uentry_isValid (u) 
04023           && uentry_isRefParam (u)
04024           && ctype_isRealArray (uentry_getType (u)))
04025         {
04026           voptgenerror
04027             (FLG_SIZEOFFORMALARRAY,
04028              message ("Parameter to sizeof is an array-type function parameter: %s",
04029                       exprNode_unparse (ret)),
04030              ret->loc);
04031         }
04032     }
04033 
04034   /*
04035   ** sizeof (x) doesn't "really" use x
04036   */
04037 
04038   return (ret);
04039 }
04040 
04041 /*@only@*/ exprNode
04042 exprNode_alignofExpr (/*@only@*/ exprNode e)
04043 {
04044   exprNode ret;
04045 
04046   if (exprNode_isUndefined (e))
04047     {
04048       ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
04049     }
04050   else
04051     {
04052       ret = exprNode_createPartialCopy (e);
04053     }
04054 
04055   ret->edata = exprData_makeSingle (e);
04056   ret->typ = sizeof_resultType ();
04057   ret->kind = XPR_ALIGNOF;
04058   
04059   /*
04060   ** sizeof (x) doesn't "really" use x
04061   */
04062 
04063   return (ret);
04064 }
04065 
04066 /*@only@*/ exprNode
04067 exprNode_cast (/*@only@*/ lltok tok, /*@only@*/ exprNode e, /*@only@*/ qtype q)
04068 {
04069   ctype c;
04070   ctype t;
04071   exprNode ret;
04072 
04073   if (exprNode_isError (e))
04074     {
04075       qtype_free (q);
04076       lltok_release (tok);
04077       return exprNode_undefined;
04078     }
04079 
04080   checkMacroParen (e);
04081 
04082   c = qtype_getType (q);
04083   t = exprNode_getType (e);
04084 
04085   ret = exprNode_createPartialCopy (e);
04086   
04087   ret->loc = fileloc_update (ret->loc, lltok_getLoc (tok));
04088   ret->typ = c;
04089   ret->kind = XPR_CAST;
04090   ret->edata = exprData_makeCast (tok, e, q);
04091 
04092   if (ctype_isRealSU (ctype_getBaseType (sRef_getType (e->sref))))
04093     {
04094       /* 
04095       ** This is a bit of a hack to avoid a problem
04096       ** when the code does,
04097       **          (some other struct) x
04098       **          ...
04099       **          x->field
04100       */
04101 
04102       ret->sref = sRef_copy (e->sref);
04103       usymtab_addForceMustAlias (ret->sref, e->sref);
04104       sRef_setTypeFull (ret->sref, c);
04105       DPRINTF (("Cast: %s -> %s", sRef_unparseFull (e->sref),
04106                 sRef_unparseFull (ret->sref)));
04107     }
04108   else
04109     {
04110       ret->sref = e->sref;
04111       sRef_setTypeFull (ret->sref, c);
04112       DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
04113     }
04114 
04115   /*
04116   ** we allow
04117   **       abstract  -> void
04118   **              0 <-> abstract * 
04119   **         void * <-> abstract *  (if FLG_ABSTVOIDP)
04120   **     abstract * <-> void *      (if FLG_ABSTVOIDP)
04121   */
04122 
04123   if (ctype_isVoid (c)) /* cast to void is always okay --- discard value */
04124     {
04125       ;
04126     }
04127   else if (ctype_isRealAP (c)) /* casting to array or pointer */
04128     {
04129       ctype bc = ctype_getBaseType (c);
04130       ctype bt = ctype_getBaseType (t);
04131       ctype rt = ctype_realType (t);
04132 
04133       if (ctype_isFunction (ctype_baseArrayPtr (ctype_realType (c)))
04134           && (ctype_isArrayPtr (rt)
04135               && !ctype_isFunction (ctype_realType (ctype_baseArrayPtr (rt)))))
04136         {
04137           voptgenerror
04138             (FLG_CASTFCNPTR,
04139              message ("Cast from function pointer type (%t) to "
04140                       "non-function pointer (%t): %s",
04141                       c, t, exprNode_unparse (ret)),
04142              e->loc);     
04143         }
04144 
04145       if (!ctype_isFunction (ctype_baseArrayPtr (c))
04146           && (ctype_isArrayPtr (rt)
04147               && ctype_isFunction (ctype_realType (ctype_baseArrayPtr (rt)))))
04148         {
04149           voptgenerror
04150             (FLG_CASTFCNPTR,
04151              message ("Cast from non-function pointer type (%t) to "
04152                       "function pointer (%t): %s",
04153                       c, t, exprNode_unparse (ret)),
04154              e->loc);     
04155         }
04156 
04157       if (exprNode_isZero (e) && context_getFlag (FLG_ZEROPTR) &&
04158           !(ctype_isRealAbstract (bc)
04159             && context_hasAccess (ctype_typeId (bc))))
04160         {
04161          ; /* okay to cast zero */
04162         }
04163       else
04164         {
04165           if (ctype_isRealAbstract (bc)
04166               && !context_hasAccess (ctype_typeId (bc)))
04167             {
04168               if (ctype_isVoidPointer (t) || ctype_isUnknown (t))
04169                 {
04170                   vnoptgenerror
04171                     (FLG_ABSTVOIDP,
04172                      message ("Cast to underlying abstract type %t: %s",
04173                               c, exprNode_unparse (ret)),
04174                      e->loc);
04175                 }
04176               else
04177                 {
04178                   voptgenerror
04179                     (FLG_ABSTRACT,
04180                      message ("Cast to underlying abstract type %t: %s",
04181                               c, exprNode_unparse (ret)),
04182                      e->loc);     
04183                 }
04184             }
04185 
04186           if (ctype_isRealAbstract (bt)
04187               && !context_hasAccess (ctype_typeId (bt)))
04188             {
04189               if (ctype_isUnknown (c) || ctype_isVoidPointer (c))
04190                 {
04191                   vnoptgenerror
04192                     (FLG_ABSTVOIDP,
04193                      message ("Cast from underlying abstract type %t: %s",
04194                               t, exprNode_unparse (ret)),
04195                      e->loc);
04196                 }
04197               else
04198                 {
04199                   voptgenerror
04200                     (FLG_ABSTRACT,
04201                      message ("Cast from underlying abstract type %t: %s",
04202                               t, exprNode_unparse (ret)),
04203                      e->loc);
04204                 }
04205             }
04206         }
04207     }
04208   else
04209     {
04210       ctype bt = ctype_realType (ctype_getBaseType (t));
04211       ctype bc = ctype_realType (ctype_getBaseType (c));
04212 
04213       if (ctype_isAbstract (bt) && !context_hasAccess (ctype_typeId (bt)))
04214         {
04215           if (ctype_match (c, t))
04216             {
04217               if (ctype_equal (c, t))
04218                 {
04219                   voptgenerror
04220                     (FLG_TYPE, 
04221                      message ("Redundant cast involving abstract type %t: %s",
04222                               bt, exprNode_unparse (ret)),
04223                      e->loc);
04224                 }
04225             }
04226           else
04227             {
04228               voptgenerror
04229                 (FLG_ABSTRACT,
04230                  message ("Cast from abstract type %t: %s", 
04231                           bt, exprNode_unparse (ret)),
04232                  e->loc);
04233             }
04234         }
04235       
04236       if (ctype_isAbstract (bc) 
04237           && !context_hasAccess (ctype_typeId (bc)))
04238         {
04239           if (ctype_match (c, t))
04240             {
04241              ;
04242             }
04243           else
04244             {
04245               voptgenerror 
04246                 (FLG_ABSTRACT,
04247                  message ("Cast to abstract type %t: %s", bc, 
04248                           exprNode_unparse (ret)),
04249                  e->loc);
04250             }
04251         }
04252     }
04253 
04254   if (ctype_isAbstract (c))
04255     {
04256       if (sRef_isExposed (e->sref) || sRef_isOnly (e->sref))
04257         {
04258           /* okay, cast exposed to abstract */
04259           sRef_clearExKindComplete (ret->sref, fileloc_undefined);
04260         }
04261       else 
04262         {
04263           if (ctype_isVisiblySharable (t) 
04264               && sRef_isExternallyVisible (e->sref)
04265               && !(ctype_isAbstract (t) 
04266                    && context_hasAccess (ctype_typeId (t))))
04267             {
04268               voptgenerror 
04269                 (FLG_CASTEXPOSE,
04270                  message ("Cast to abstract type from externally visible "
04271                           "mutable storage exposes rep of %s: %s",
04272                           ctype_unparse (c),
04273                           exprNode_unparse (e)),
04274                  e->loc);
04275             }
04276         }
04277     }
04278 
04279   return (ret);
04280 }
04281 
04282 static bool
04283 evaluationOrderUndefined (lltok op)
04284 {
04285   int opid = lltok_getTok (op);
04286 
04287   return (opid != AND_OP && opid != OR_OP);
04288 }
04289 
04290 static bool checkIntegral (/*@notnull@*/ exprNode e1, 
04291                            /*@notnull@*/ exprNode e2, 
04292                            /*@notnull@*/ exprNode ret, 
04293                            lltok op)
04294 {
04295   bool error = FALSE;
04296 
04297   ctype te1 = exprNode_getType (e1);
04298   ctype te2 = exprNode_getType (e2);
04299 
04300   ctype tr1 = ctype_realishType (te1);
04301   ctype tr2 = ctype_realishType (te2);
04302   
04303   if (ctype_isForceRealInt (&tr1) && ctype_isForceRealInt (&tr2))
04304     {
04305       ;
04306     }
04307   else
04308     {
04309       if (context_msgStrictOps ())
04310         {
04311           if (!ctype_isInt (tr1) && !ctype_isInt (tr2))
04312             {
04313               if (ctype_sameName (te1, te2))
04314                 {
04315                   error = optgenerror 
04316                     (FLG_STRICTOPS,
04317                      message ("Operands of %s are non-integer (%t): %s",
04318                               lltok_unparse (op), te1,
04319                               exprNode_unparse (ret)),
04320                      e1->loc);
04321                 }
04322               else
04323                 {
04324                   error = optgenerror 
04325                     (FLG_STRICTOPS,
04326                      message ("Operands of %s are non-integers (%t, %t): %s",
04327                               lltok_unparse (op), te1, te2,
04328                               exprNode_unparse (ret)),
04329                      e1->loc);
04330                 }
04331             }
04332           else if (!ctype_isInt (tr1))
04333             {
04334               error = optgenerror 
04335                 (FLG_STRICTOPS,
04336                  message ("Left operand of %s is non-integer (%t): %s",
04337                           lltok_unparse (op), te1, exprNode_unparse (ret)),
04338                  e1->loc);
04339             }
04340           else
04341             /* !ctype_isInt (te2) */
04342             {
04343               error = optgenerror 
04344                 (FLG_STRICTOPS,
04345                  message ("Right operand of %s is non-integer (%t): %s",
04346                           lltok_unparse (op), te2, exprNode_unparse (ret)),
04347                  e2->loc);
04348             }
04349         }
04350     }
04351 
04352   return !error;
04353 }
04354 
04355 /*
04356 ** returns exprNode representing e1 op e2
04357 **
04358 ** uses msg if there are errors
04359 ** can be used for both assignment ops and regular ops
04360 **
04361 ** modifies e1
04362 */
04363 
04364 static /*@only@*/ /*@notnull@*/ exprNode
04365 exprNode_makeOp (/*@keep@*/ exprNode e1, /*@keep@*/ exprNode e2, 
04366                  /*@keep@*/ lltok op)
04367 {
04368   ctype te1, te2, tr1, tr2, tret;
04369   int opid = lltok_getTok (op);
04370   bool hasError = FALSE;
04371   exprNode ret;
04372 
04373   if (exprNode_isError (e1))
04374     {
04375       ret = exprNode_createPartialNVCopy (e2);
04376     }
04377   else
04378     {
04379       ret = exprNode_createPartialNVCopy (e1);    
04380     }
04381 
04382   ret->val = multiVal_undefined;
04383   ret->kind = XPR_OP;
04384   ret->edata = exprData_makeOp (e1, e2, op);
04385 
04386   if (exprNode_isError (e1) || exprNode_isError (e2))
04387     {
04388       if (opid == TLT || opid == TGT || opid == LE_OP || opid == GE_OP
04389           || opid == EQ_OP || opid == NE_OP 
04390           || opid == AND_OP || opid == OR_OP)
04391         {
04392           ret->typ = ctype_bool;
04393         }
04394 
04395       if (exprNode_isDefined (e1))
04396         {
04397           exprNode_checkUse (ret, e1->sref, e1->loc);  
04398         }
04399 
04400       if (exprNode_isDefined (e2))
04401         {
04402           exprNode_mergeUSs (ret, e2);
04403           exprNode_checkUse (ret, e2->sref, e2->loc);  
04404         }
04405 
04406       return ret;
04407     }
04408 
04409   tret = ctype_unknown;
04410   te1 = exprNode_getType (e1);
04411   DPRINTF (("te1 = %s / %s", exprNode_unparse (e1), ctype_unparse (te1)));
04412 
04413   te2 = exprNode_getType (e2);
04414 
04415   tr1 = ctype_realishType (te1);
04416   tr2 = ctype_realishType (te2);
04417 
04418   if (opid == OR_OP)
04419     {
04420       ret->guards = guardSet_or (ret->guards, e2->guards);
04421     }
04422   else if (opid == AND_OP)
04423     {
04424       ret->guards = guardSet_and (ret->guards, e2->guards);
04425     }
04426   else
04427     {
04428       /* no guards */
04429     }
04430 
04431   if (opid == EQ_OP || opid == NE_OP)
04432     {
04433       exprNode temp1 = e1, temp2 = e2;
04434 
04435       /* could do NULL == x */
04436       
04437       if (exprNode_isNullValue (e1) || exprNode_isUnknownConstant (e1))
04438         {
04439           temp1 = e2; temp2 = e1;
04440         }
04441 
04442       if (exprNode_isNullValue (temp2) || exprNode_isUnknownConstant (temp2))
04443         {
04444           reflectNullTest (temp1, (opid == NE_OP));
04445           guardSet_free (ret->guards);
04446           ret->guards = guardSet_copy (temp1->guards);
04447         }
04448     }
04449 
04450   if (opid == TLT || opid == TGT || opid == LE_OP || opid == GE_OP
04451       || opid == EQ_OP || opid == NE_OP || opid == AND_OP || opid == OR_OP)
04452     {
04453       tret = ctype_bool; 
04454     }
04455   
04456   if (anyAbstract (tr1, tr2) &&
04457       (!((ctype_isRealBool (te1) || ctype_isRealBool (te2)) && 
04458          (opid == AND_OP || opid == OR_OP 
04459           || opid == EQ_OP || opid == NE_OP))))
04460     {
04461       abstractOpError (tr1, tr2, op, e1, e2, e1->loc, e2->loc);
04462     }
04463   else if (ctype_isUnknown (te1) || ctype_isUnknown (te2))
04464     {
04465       /* unknown types, no comparisons possible */
04466     }
04467   else
04468     {
04469       switch (opid)
04470         {
04471         case TMULT:             /* multiplication and division:           */
04472         case TDIV:              /*                                        */
04473         case MUL_ASSIGN:        /*    numeric, numeric -> numeric         */
04474         case DIV_ASSIGN:        /*                                        */
04475           
04476           tret = checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
04477           break;
04478           
04479         case TPLUS:             /* addition and subtraction:               */
04480         case TMINUS:            /*    pointer, int     -> pointer          */
04481         case SUB_ASSIGN:        /*    int, pointer     -> pointer          */
04482         case ADD_ASSIGN:        /*    numeric, numeric -> numeric          */
04483           
04484           tr1 = ctype_fixArrayPtr (tr1);
04485 
04486           if ((ctype_isRealPointer (tr1) && !exprNode_isNullValue (e1))
04487               && (!ctype_isRealPointer (tr2) && ctype_isRealInt (tr2)))
04488             {
04489               /* pointer + int */
04490 
04491               if (context_msgPointerArith ())
04492                 {
04493                   voptgenerror
04494                     (FLG_POINTERARITH,
04495                      message ("Pointer arithmetic (%t, %t): %s", 
04496                               te1, te2, exprNode_unparse (ret)),
04497                      e1->loc);
04498                 }
04499 
04500               if (sRef_possiblyNull (e1->sref)
04501                   && !usymtab_isGuarded (e1->sref))
04502                 {
04503                   voptgenerror
04504                     (FLG_NULLPOINTERARITH,
04505                      message ("Pointer arithmetic involving possibly "
04506                               "null pointer %s: %s", 
04507                               exprNode_unparse (e1), 
04508                               exprNode_unparse (ret)),
04509                      e1->loc);
04510                 }
04511 
04512               ret->sref = sRef_copy (e1->sref);
04513 
04514               sRef_setNullError (ret->sref);
04515 
04516               /*
04517               ** Fixed for 2.2c: the alias state of ptr + int is dependent,
04518               ** since is points to storage that should not be deallocated
04519               ** through this pointer.
04520               */
04521 
04522               if (sRef_isOnly (ret->sref) 
04523                   || sRef_isFresh (ret->sref)) 
04524                 {
04525                   sRef_setAliasKind (ret->sref, AK_DEPENDENT, exprNode_loc (ret));
04526                 }
04527               
04528               tret = e1->typ;
04529             }
04530           else if ((!ctype_isRealPointer(tr1) && ctype_isRealInt (tr1)) 
04531                    && (ctype_isRealPointer (tr2) && !exprNode_isNullValue (e2)))
04532             {
04533               if (context_msgPointerArith ())
04534                 {
04535                   voptgenerror 
04536                     (FLG_POINTERARITH,
04537                      message ("Pointer arithmetic (%t, %t): %s", 
04538                               te1, te2, exprNode_unparse (ret)),
04539                      e1->loc);
04540                 }
04541 
04542               if (sRef_possiblyNull (e1->sref)
04543                   && !usymtab_isGuarded (e1->sref))
04544                 {
04545                   voptgenerror
04546                     (FLG_NULLPOINTERARITH,
04547                      message ("Pointer arithmetic involving possibly "
04548                               "null pointer %s: %s", 
04549                               exprNode_unparse (e2), 
04550                               exprNode_unparse (ret)),
04551                      e2->loc);
04552                 }
04553 
04554               ret->sref = sRef_copy (e2->sref);
04555 
04556               sRef_setNullError (ret->sref);
04557 
04558               /*
04559               ** Fixed for 2.2c: the alias state of ptr + int is dependent,
04560               ** since is points to storage that should not be deallocated
04561               ** through this pointer.
04562               */
04563 
04564               if (sRef_isOnly (ret->sref) 
04565                   || sRef_isFresh (ret->sref)) {
04566                 sRef_setAliasKind (ret->sref, AK_DEPENDENT, exprNode_loc (ret));
04567               }
04568 
04569               tret = e2->typ;
04570               ret->sref = e2->sref;
04571             }
04572           else
04573             {
04574               tret = checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
04575             }
04576           
04577           break;
04578 
04579         case LEFT_ASSIGN:   /* Shifts: should be unsigned values */
04580         case RIGHT_ASSIGN:
04581         case LEFT_OP:
04582         case RIGHT_OP:
04583         case TAMPERSAND:    /* bitwise & */
04584         case AND_ASSIGN:       
04585         case TCIRC:         /* ^ (XOR) */
04586         case TBAR:
04587         case XOR_ASSIGN:
04588         case OR_ASSIGN:
04589           {
04590             bool reported = FALSE;
04591             flagcode code = FLG_BITWISEOPS;
04592             
04593             if (opid == LEFT_OP || opid == LEFT_ASSIGN
04594                 || opid == RIGHT_OP || opid == RIGHT_ASSIGN) {
04595               code = FLG_SHIFTSIGNED;
04596             }
04597 
04598             if (!ctype_isUnsigned (tr1)) 
04599               {
04600                 if (exprNode_isNonNegative (e1)) {
04601                   ;
04602                 } else {
04603                   reported = optgenerror 
04604                     (code,
04605                      message ("Left operand of %s is not unsigned value (%t): %s",
04606                               lltok_unparse (op), te1,
04607                               exprNode_unparse (ret)),
04608                      e1->loc);
04609                   
04610                   if (reported) {
04611                     te1 = ctype_uint;
04612                   }
04613                 }
04614               }
04615             else 
04616               {
04617                 /* right need not be signed for shifts */
04618                 if (code != FLG_SHIFTSIGNED 
04619                     && !ctype_isUnsigned (tr2)) 
04620                   {
04621                     if (!exprNode_isNonNegative (e2)) {
04622                       reported = optgenerror 
04623                         (code,
04624                          message ("Right operand of %s is not unsigned value (%t): %s",
04625                                   lltok_unparse (op), te2,
04626                                   exprNode_unparse (ret)),
04627                          e2->loc);
04628                     }
04629                   }
04630               }
04631             
04632             if (!reported) 
04633               {
04634                 if (!checkIntegral (e1, e2, ret, op)) {
04635                   te1 = ctype_unknown;
04636                 }
04637               }
04638             
04639             DPRINTF (("Set: %s", ctype_unparse (te1)));     
04640 
04641             /*
04642             ** tret is the widest type of te1 and te2 
04643             */
04644 
04645             tret = ctype_widest (te1, te2);
04646             break;
04647           }
04648         case MOD_ASSIGN:
04649         case TPERCENT:          
04650           if (checkIntegral (e1, e2, ret, op)) {
04651             tret = te1;
04652           } else {
04653             tret = ctype_unknown;
04654           }
04655           break;
04656         case EQ_OP: 
04657         case NE_OP:
04658         case TLT:               /* comparisons                           */
04659         case TGT:               /*    numeric, numeric -> bool           */
04660           if ((ctype_isReal (tr1) && !ctype_isInt (tr1))
04661               || (ctype_isReal (tr2) && !ctype_isInt (tr2)))
04662             {
04663               ctype rtype = tr1;
04664               bool fepsilon = FALSE;
04665 
04666               if (!ctype_isReal (rtype) || ctype_isInt (rtype))
04667                 {
04668                   rtype = tr2;
04669                 }
04670               
04671               if (opid == TLT || opid == TGT)
04672                 {
04673                   uentry ue1 = exprNode_getUentry (e1);
04674                   uentry ue2 = exprNode_getUentry (e2);
04675 
04676                   /*
04677                   ** FLT_EPSILON, etc. really is a variable, not
04678                   ** a constant.
04679                   */
04680 
04681                   if (uentry_isVariable (ue1))
04682                     {
04683                       cstring uname = uentry_rawName (ue1);
04684 
04685                       if (cstring_equalLit (uname, "FLT_EPSILON")
04686                           || cstring_equalLit (uname, "DBL_EPSILON")
04687                           || cstring_equalLit (uname, "LDBL_EPSILON"))
04688                         {
04689                           fepsilon = TRUE;
04690                         }
04691                     }
04692 
04693                   if (uentry_isVariable (ue2))
04694                     {
04695                       cstring uname = uentry_rawName (ue2);
04696 
04697                       if (cstring_equalLit (uname, "FLT_EPSILON")
04698                           || cstring_equalLit (uname, "DBL_EPSILON")
04699                           || cstring_equalLit (uname, "LDBL_EPSILON"))
04700                         {
04701                           fepsilon = TRUE;
04702                         }
04703                     }
04704                 }
04705 
04706               if (fepsilon)
04707                 {
04708                   ; /* Don't complain. */
04709                 }
04710               else
04711                 {
04712                   voptgenerror
04713                     (FLG_REALCOMPARE,
04714                      message ("Dangerous comparison involving %s types: %s",
04715                               ctype_unparse (rtype),
04716                               exprNode_unparse (ret)),
04717                      ret->loc);
04718                 }
04719             }
04720           /*@fallthrough@*/
04721         case LE_OP:
04722         case GE_OP:
04723 
04724           /*
04725           ** Types should match.
04726           */
04727 
04728           if (!exprNode_matchTypes (e1, e2))
04729             {
04730               hasError = gentypeerror 
04731                 (te1, e1, te2, e2,
04732                  message ("Operands of %s have incompatible types (%t, %t): %s",
04733                           lltok_unparse (op), te1, te2, exprNode_unparse (ret)),
04734                  e1->loc);
04735               
04736             }
04737 
04738           if (hasError 
04739               || (ctype_isForceRealNumeric (&tr1)
04740                   && ctype_isForceRealNumeric (&tr2)) ||
04741               (ctype_isRealPointer (tr1) && ctype_isRealPointer (tr2)))
04742             {
04743               ; /* okay */
04744             }
04745           else
04746             {
04747               if ((ctype_isRealNumeric (tr1) && ctype_isRealPointer (tr2)) ||
04748                   (ctype_isRealPointer (tr1) && ctype_isRealNumeric (tr2)))
04749                 {
04750                   voptgenerror 
04751                     (FLG_PTRNUMCOMPARE,
04752                      message ("Comparison of pointer and numeric (%t, %t): %s",
04753                               te1, te2, exprNode_unparse (ret)),
04754                      e1->loc);
04755                 }
04756               else
04757                 {
04758                   (void) checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
04759                 }
04760               tret = ctype_bool;
04761             }
04762 
04763           /* EQ_OP should NOT be used with booleans (unless one is FALSE) */
04764           
04765           if ((opid == EQ_OP || opid == NE_OP) && 
04766               ctype_isDirectBool (tr1) && ctype_isDirectBool (tr2))
04767             {
04768               /*
04769               ** is one a variable?
04770               */
04771 
04772               if (uentry_isVariable (exprNode_getUentry (e1))
04773                   || uentry_isVariable (exprNode_getUentry (e2)))
04774                 {
04775                   /*
04776                   ** comparisons with FALSE are okay
04777                   */
04778 
04779                   if (exprNode_isFalseConstant (e1)
04780                       || exprNode_isFalseConstant (e2))
04781                     {
04782                       ;
04783                     }
04784                   else
04785                     {
04786                       voptgenerror
04787                         (FLG_BOOLCOMPARE,
04788                          message 
04789                          ("Use of %q with %s variables (risks inconsistency because "
04790                           "of multiple true values): %s",
04791                           cstring_makeLiteral ((opid == EQ_OP) ? "==" : "!="),
04792                           context_printBoolName (), exprNode_unparse (ret)),
04793                          e1->loc);
04794                     }
04795                 }
04796             }
04797           break;
04798           
04799         case AND_OP:            /* bool, bool -> bool */
04800         case OR_OP:
04801 
04802           if (ctype_isForceRealBool (&tr1) && ctype_isForceRealBool (&tr2))
04803             {
04804               ; 
04805             }
04806           else
04807             {
04808               if (context_maybeSet (FLG_BOOLOPS))
04809                 {
04810                   if (!ctype_isRealBool (te1) && !ctype_isRealBool (te2))
04811                     {
04812                       if (ctype_sameName (te1, te2))
04813                         {
04814                           voptgenerror 
04815                             (FLG_BOOLOPS,
04816                              message ("Operands of %s are non-boolean (%t): %s",
04817                                       lltok_unparse (op), te1,
04818                                       exprNode_unparse (ret)),
04819                              e1->loc);
04820                         }
04821                       else
04822                         {
04823                           voptgenerror 
04824                             (FLG_BOOLOPS,
04825                              message
04826                              ("Operands of %s are non-booleans (%t, %t): %s",
04827                               lltok_unparse (op), te1, te2, exprNode_unparse (ret)),
04828                              e1->loc);
04829                         }
04830                     }
04831                   else if (!ctype_isRealBool (te1))
04832                     {
04833                       voptgenerror 
04834                         (FLG_BOOLOPS,
04835                          message ("Left operand of %s is non-boolean (%t): %s",
04836                                   lltok_unparse (op), te1, exprNode_unparse (ret)),
04837                          e1->loc);
04838                     }
04839                   else if (!ctype_isRealBool (te2))
04840                     {
04841                       voptgenerror
04842                         (FLG_BOOLOPS,
04843                          message ("Right operand of %s is non-boolean (%t): %s",
04844                                   lltok_unparse (op), te2, exprNode_unparse (ret)),
04845                          e2->loc);
04846                     }
04847                   else
04848                     {
04849                       ;
04850                     }
04851                 }
04852               tret = ctype_bool;
04853             }
04854           break;
04855         default: {
04856             TPRINTF (("opid = %d", opid));
04857             llfatalbug 
04858               (cstring_makeLiteral 
04859                ("There has been a problem in the parser. This is due to a bug "
04860                 "in either lclint, bison or gcc version 2.95 optimizations, "
04861                 "but it has not been confirmed.  Please try rebuidling LCLint "
04862                 "without the -O<n> option."));
04863           }
04864         }
04865     }
04866 
04867   DPRINTF (("Return type: %s", ctype_unparse (tret)));
04868   ret->typ = tret;
04869 
04870   exprNode_checkUse (ret, e1->sref, e1->loc);  
04871   exprNode_mergeUSs (ret, e2);
04872   exprNode_checkUse (ret, e2->sref, e2->loc);  
04873 
04874   return ret;
04875 }
04876 
04877 /*@only@*/ exprNode
04878 exprNode_op (/*@only@*/ exprNode e1, /*@keep@*/ exprNode e2,
04879              /*@only@*/ lltok op)
04880 {
04881   exprNode ret;
04882 
04883   checkMacroParen (e1);
04884   checkMacroParen (e2);
04885 
04886   if (evaluationOrderUndefined (op) && context_maybeSet (FLG_EVALORDER))
04887     {
04888       checkExpressionDefined (e1, e2, op);
04889     }
04890 
04891   ret = exprNode_makeOp (e1, e2, op);
04892   return (ret);
04893 }
04894 
04895 static
04896 void exprNode_checkAssignMod (exprNode e1, exprNode ret)
04897 {
04898   /*
04899   ** This is somewhat bogus!
04900   **
04901   ** Assigning to a nested observer in a non-observer datatype
04902   ** should not produce an error.
04903   */
04904 
04905   sRef ref = exprNode_getSref (e1);
04906 
04907   DPRINTF (("Check assign mod: %s",
04908             sRef_unparseFull (ref)));
04909 
04910   if (sRef_isObserver (ref) 
04911       || ((sRef_isFileStatic (ref) || sRef_isGlobal (ref))
04912           && ctype_isArray (ctype_realType (sRef_getType (ref)))))
04913     {
04914       sRef base = sRef_getBase (ref);
04915 
04916       if (sRef_isValid (base) && sRef_isObserver (base))
04917         {
04918           exprNode_checkModify (e1, ret);
04919         }
04920       else
04921         {
04922           exprNode_checkModifyVal (e1, ret);
04923         }
04924     }
04925   else
04926     {
04927       exprNode_checkModify (e1, ret);
04928     }
04929 }
04930 
04931 exprNode
04932 exprNode_assign (/*@only@*/ exprNode e1,
04933                  /*@only@*/ exprNode e2, /*@only@*/ lltok op)
04934 {
04935   bool isalloc = FALSE;
04936   bool isjustalloc = FALSE;
04937   exprNode ret;
04938 
04939   DPRINTF (("%s [%s] <- %s [%s]",
04940             exprNode_unparse (e1),
04941             ctype_unparse (e1->typ),
04942             exprNode_unparse (e2),
04943             ctype_unparse (e2->typ)));
04944 
04945   if (lltok_getTok (op) != TASSIGN) 
04946     {
04947       ret = exprNode_makeOp (e1, e2, op);
04948     } 
04949   else 
04950     {
04951       ret = exprNode_createPartialCopy (e1);
04952       ret->kind = XPR_ASSIGN;
04953       ret->edata = exprData_makeOp (e1, e2, op);
04954 
04955       if (!exprNode_isError (e2)) 
04956         {
04957           ret->sets = sRefSet_union (ret->sets, e2->sets);
04958           ret->msets = sRefSet_union (ret->msets, e2->msets);
04959           ret->uses = sRefSet_union (ret->uses, e2->uses);
04960         }
04961     }
04962 
04963   checkExpressionDefined (e1, e2, op);
04964 
04965   if (exprNode_isError (e1))
04966     {
04967       if (!exprNode_isError (e2)) 
04968         {
04969           ret->loc = fileloc_update (ret->loc, e2->loc);
04970         }
04971       else
04972         {
04973           ret->loc = fileloc_update (ret->loc, g_currentloc);
04974         }
04975     }
04976 
04977   if (!exprNode_isError (e2))
04978     {
04979       checkMacroParen (e2);
04980     }
04981 
04982   if (exprNode_isDefined (e1))
04983     {
04984       if (sRef_isMacroParamRef (e1->sref))
04985         {
04986           if (context_inIterDef ())
04987             {
04988               uentry ue = sRef_getUentry (e1->sref);
04989               
04990               if (uentry_isYield (ue))
04991                 {
04992                   ;
04993                 }
04994               else
04995                 {
04996                   if (fileloc_isDefined (e1->loc))
04997                     {
04998                       voptgenerror
04999                         (FLG_MACROPARAMS,
05000                          message ("Assignment to non-yield iter parameter: %q", 
05001                                   sRef_unparse (e1->sref)),
05002                          e1->loc);
05003                     }
05004                   else
05005                     {
05006                       voptgenerror 
05007                         (FLG_MACROPARAMS,
05008                          message ("Assignment to non-yield iter parameter: %q", 
05009                                   sRef_unparse (e1->sref)),
05010                          g_currentloc);
05011                     }
05012                 }
05013             }
05014           else
05015             {
05016               if (fileloc_isDefined (e1->loc))
05017                 {
05018                   voptgenerror
05019                     (FLG_MACROASSIGN,
05020                      message ("Assignment to macro parameter: %q", 
05021                               sRef_unparse (e1->sref)),
05022                      e1->loc);
05023                 }
05024               else
05025                 {
05026                   voptgenerror 
05027                     (FLG_MACROASSIGN,
05028                      message ("Assignment to macro parameter: %q", 
05029                               sRef_unparse (e1->sref)),
05030                      g_currentloc);
05031                 }
05032             }
05033         }
05034       else
05035         {
05036           exprNode_checkAssignMod (e1, ret);
05037         }
05038 
05039       if (exprNode_isDefined (e2))
05040         {
05041           if (lltok_getTok (op) == TASSIGN) 
05042             {
05043               ctype te1 = exprNode_getType (e1);
05044               ctype te2 = exprNode_getType (e2);
05045               
05046               if (!ctype_forceMatch (te1, te2))
05047                 {
05048                   if (exprNode_matchLiteral (te1, e2))
05049                     {
05050                       ;
05051                     }
05052                   else
05053                     {
05054                       (void) gentypeerror 
05055                         (te2, e2, te1, e1,
05056                          message ("Assignment of %t to %t: %s %s %s", 
05057                                   te2, te1, exprNode_unparse (e1),
05058                                   lltok_unparse (op), 
05059                                   exprNode_unparse (e2)),
05060                          e1->loc);
05061                     }
05062                 }
05063             }
05064          
05065           exprNode_mergeUSs (ret, e2);
05066           exprNode_checkUse (ret, e2->sref, e2->loc);
05067           
05068           doAssign (e1, e2, FALSE); 
05069           ret->sref = e1->sref;
05070         }
05071       else
05072         {
05073           if (exprNode_isDefined (e2))
05074             {
05075               exprNode_mergeUSs (ret, e2);
05076                       exprNode_checkUse (ret, e2->sref, e2->loc);
05077             }
05078         }
05079 
05080       if (sRef_isPointer (e1->sref) && !sRef_isMacroParamRef (e1->sref))
05081         {
05082           exprNode_checkUse (ret, sRef_getBase (e1->sref), e1->loc);
05083         }
05084 
05085       isjustalloc = sRef_isJustAllocated (e1->sref);
05086       isalloc = sRef_isAllocated (e1->sref);
05087 
05088       if (sRef_isField (e1->sref))
05089         {
05090           sRef root = sRef_getRootBase (sRef_getBase (e1->sref));
05091           
05092           if (!sRef_isAllocated (root) && !sRef_isMacroParamRef (root))
05093             {
05094               exprNode_checkUse (ret, root, e1->loc);
05095             }
05096           
05097         }
05098   
05099       /*
05100       ** be careful!  this defines e1->sref.
05101       */
05102    
05103       if (!sRef_isMacroParamRef (e1->sref))
05104         {
05105           exprNode_checkSet (ret, e1->sref);
05106         }
05107       
05108       if (isjustalloc) 
05109         {
05110           sRef_setAllocatedComplete (e1->sref, exprNode_isDefined (e2)
05111                                      ? e2->loc : e1->loc);
05112         }
05113       else 
05114         {
05115           if (isalloc)
05116             {
05117               sRef_setAllocatedShallowComplete (e1->sref, exprNode_loc (e2));
05118             }
05119         }
05120     }
05121   
05122   return ret;
05123 }
05124 
05125 exprNode
05126 exprNode_cond (/*@keep@*/ exprNode pred, /*@keep@*/ exprNode ifclause, 
05127                /*@keep@*/ exprNode elseclause)
05128 {
05129   exprNode ret;
05130 
05131   if (!exprNode_isError (pred))
05132     {
05133       ret = exprNode_createPartialCopy (pred);
05134       checkMacroParen (pred);
05135       exprNode_checkPred (cstring_makeLiteralTemp ("conditional"), pred);
05136       
05137       if (!exprNode_isError (ifclause))
05138         {
05139           checkMacroParen (ifclause);   /* update macro counts! */
05140 
05141           if (!exprNode_isError (elseclause))
05142             {
05143               checkMacroParen (elseclause);
05144               
05145               if (!exprNode_matchTypes (ifclause, elseclause))
05146                 {
05147                   if (gentypeerror 
05148                       (exprNode_getType (ifclause),
05149                        ifclause,
05150                        exprNode_getType (elseclause),
05151                        elseclause,
05152                        message ("Conditional clauses are not of same type: "
05153                                 "%s (%t), %s (%t)", 
05154                                 exprNode_unparse (ifclause), 
05155                                 exprNode_getType (ifclause),
05156                                 exprNode_unparse (elseclause), 
05157                                 exprNode_getType (elseclause)),
05158                        ifclause->loc))
05159                     {
05160                       ret->sref = sRef_undefined;
05161                       ret->typ = ctype_unknown;
05162                     }
05163                 }
05164               else
05165                 {
05166                   /* for now...should merge the states */
05167                   ret->sref = ifclause->sref;
05168                   ret->typ = ifclause->typ;
05169 
05170                   if (exprNode_isNullValue (ifclause))
05171                     {
05172                       ret->typ = elseclause->typ;
05173                     }
05174                 }
05175               
05176               exprNode_checkUse (ret, pred->sref, pred->loc);
05177               exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
05178               exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
05179 
05180               exprNode_mergeCondUSs (ret, ifclause, elseclause);
05181 
05182             }
05183           else
05184             {
05185               ret->typ = ifclause->typ;
05186               
05187               exprNode_checkUse (pred, pred->sref, pred->loc);
05188               exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
05189               
05190               exprNode_mergeCondUSs (ret, ifclause, exprNode_undefined);
05191             }
05192         }
05193       else 
05194         {
05195           if (!exprNode_isError (elseclause))
05196             {
05197               ret->typ = elseclause->typ;
05198               
05199               exprNode_checkUse (pred, pred->sref, pred->loc);
05200               exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
05201               
05202               exprNode_mergeCondUSs (ret, exprNode_undefined, elseclause);
05203             }
05204         }
05205     }
05206   else /* pred is error */
05207     {
05208       if (!exprNode_isError (ifclause))
05209         {
05210           ret = exprNode_createSemiCopy (ifclause);
05211 
05212           checkMacroParen (ifclause);   /* update macro counts! */
05213           
05214           if (!exprNode_isError (elseclause))
05215             {
05216               checkMacroParen (elseclause);
05217               
05218               ret->typ = ifclause->typ;
05219                       
05220               if (!ctype_forceMatch (ifclause->typ, elseclause->typ))
05221                 {
05222                   if (gentypeerror 
05223                       (exprNode_getType (ifclause),
05224                        ifclause,
05225                        exprNode_getType (elseclause),
05226                        elseclause,
05227                        message ("Conditional clauses are not of same type: "
05228                                 "%s (%t), %s (%t)", 
05229                                 exprNode_unparse (ifclause), 
05230                                 exprNode_getType (ifclause),
05231                                 exprNode_unparse (elseclause), 
05232                                 exprNode_getType (elseclause)),
05233                        ifclause->loc))
05234                     {
05235                       ret->typ = ctype_unknown;
05236                     }
05237                 }
05238                       
05239               exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
05240               exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
05241               
05242               exprNode_mergeCondUSs (ret, ifclause, elseclause);
05243             }
05244         }
05245       else if (!exprNode_isError (elseclause)) /* pred, if errors */
05246         {
05247           ret = exprNode_createSemiCopy (ifclause);
05248 
05249           ret->typ = elseclause->typ;
05250           checkMacroParen (elseclause);
05251           
05252           exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
05253           exprNode_mergeCondUSs (ret, exprNode_undefined, elseclause);
05254         }
05255       else /* all errors! */
05256         {
05257           ret = exprNode_createLoc (ctype_unknown, g_currentloc);
05258         }
05259     }
05260   
05261   ret->kind = XPR_COND;
05262   ret->edata = exprData_makeCond (pred, ifclause, elseclause);  
05263 
05264   if (exprNode_isDefined (ifclause) && exprNode_isDefined (elseclause))
05265     {
05266       exprNode_combineControl (ret, ifclause, elseclause);
05267     }
05268 
05269   return (ret);
05270 }
05271 
05272 exprNode
05273 exprNode_vaArg (/*@only@*/ lltok tok, /*@only@*/ exprNode arg, /*@only@*/ qtype qt)
05274 {
05275   ctype totype = qtype_getType (qt);
05276   exprNode ret =
05277     exprNode_createPartialLocCopy (arg, fileloc_copy (lltok_getLoc (tok)));
05278   ctype targ;
05279 
05280   /*
05281   ** check use of va_arg : <valist>, type -> type
05282   */
05283 
05284   if (exprNode_isError (arg))
05285     {
05286     }
05287   else
05288     {
05289       targ = exprNode_getType (arg);
05290 
05291       /*
05292       ** arg should have be a pointer
05293       */
05294 
05295       if (!ctype_isUA (targ) ||
05296           (!usymId_equal (ctype_typeId (targ), 
05297                          usymtab_getTypeId (cstring_makeLiteralTemp ("va_list")))))
05298         {
05299           voptgenerror
05300             (FLG_TYPE,
05301              message ("First argument to va_arg is not a va_list (type %t): %s",
05302                       targ, exprNode_unparse (arg)),
05303              arg->loc);
05304         }
05305 
05306       exprNode_checkSet (ret, arg->sref);
05307     }
05308   
05309   /*
05310   ** return type is totype
05311   */
05312 
05313   ret->typ = totype;
05314   ret->kind = XPR_VAARG;
05315   ret->edata = exprData_makeCast (tok, arg, qt);
05316 
05317   return (ret);
05318 }
05319 
05320 exprNode exprNode_labelMarker (/*@only@*/ cstring label)
05321 {
05322   exprNode ret = exprNode_createPlain (ctype_undefined);
05323   ret->kind = XPR_LABEL;
05324   ret->edata = exprData_makeLiteral (label);
05325   ret->isJumpPoint = TRUE;
05326 
05327   return (ret); /* for now, ignore label */
05328 }
05329 
05330 exprNode exprNode_notReached (/*@returned@*/ exprNode stmt)
05331 {
05332   if (exprNode_isDefined (stmt))
05333     {
05334       stmt->isJumpPoint = TRUE;
05335 
05336       /* This prevent stray no return path errors, etc. */
05337       stmt->exitCode = XK_MUSTEXIT;
05338     }
05339 
05340   return (stmt); 
05341 }
05342 
05343 bool exprNode_isDefaultMarker (exprNode e) 
05344 {
05345   if (exprNode_isDefined (e))
05346     {
05347       return (e->kind == XPR_DEFAULT || e->kind == XPR_FTDEFAULT);
05348     }
05349 
05350   return FALSE;
05351 }
05352 
05353 bool exprNode_isCaseMarker (exprNode e) 
05354 {
05355   if (exprNode_isDefined (e))
05356     {
05357       return (e->kind == XPR_FTCASE || e->kind == XPR_CASE);
05358     }
05359 
05360   return FALSE;
05361 }
05362 
05363 bool exprNode_isLabelMarker (exprNode e) 
05364 {
05365   if (exprNode_isDefined (e))
05366     {
05367       return (e->kind == XPR_LABEL);
05368     }
05369 
05370   return FALSE;
05371 }
05372 
05373 exprNode exprNode_caseMarker (/*@only@*/ exprNode test, bool fallThrough) 
05374 {
05375   exprNode ret = exprNode_createPartialCopy (test);
05376 
05377   ret->kind = fallThrough ? XPR_FTCASE : XPR_CASE;
05378 
05379   if (exprNode_isError (test)) {
05380     return ret;
05381   }
05382 
05383   exprNode_checkUse (ret, test->sref, test->loc);
05384   
05385   usymtab_setExitCode (ret->exitCode);
05386   
05387   if (ret->mustBreak)
05388     {
05389       usymtab_setMustBreak ();
05390     }
05391 
05392   ret->edata = exprData_makeSingle (test);
05393   ret->isJumpPoint = TRUE;
05394   
05395   return ret;
05396 }
05397 
05398 # if 0
05399 exprNode exprNode_caseStatement (/*@only@*/ exprNode test, /*@only@*/ exprNode stmt, bool fallThrough)
05400 {
05401   exprNode ret = exprNode_createPartialCopy (test);
05402 
05403   ret->kind = fallThrough ? XPR_FTCASE : XPR_CASE;
05404   ret->edata = exprData_makePair (test, stmt);
05405   ret->isJumpPoint = TRUE;
05406 
05407   if (exprNode_isError (test))
05408     {
05409       return ret;
05410     }
05411 
05412   exprNode_checkUse (ret, test->sref, test->loc);
05413   
05414   if (exprNode_isError (stmt))
05415     {
05416       return ret;
05417     }
05418   
05419   exprNode_mergeUSs (ret, stmt);
05420   
05421   ret->exitCode = stmt->exitCode;
05422   ret->mustBreak = stmt->mustBreak;
05423   ret->canBreak = stmt->canBreak;
05424 
05425   usymtab_setExitCode (ret->exitCode);
05426   
05427   if (ret->mustBreak)
05428     {
05429       usymtab_setMustBreak ();
05430     }
05431   
05432   return ret;
05433 }
05434 # endif
05435 
05436 /*@notnull@*/ /*@only@*/ exprNode 
05437 exprNode_defaultMarker (/*@only@*/ lltok def, bool fallThrough)
05438 {
05439   exprNode ret = exprNode_createTok (def);
05440   
05441   ret->isJumpPoint = TRUE;
05442   ret->kind = fallThrough ? XPR_FTDEFAULT : XPR_DEFAULT;
05443   return (ret);
05444 }
05445 
05446 bool
05447 exprNode_mayEscape (exprNode e)
05448 {
05449   if (exprNode_isDefined (e))
05450     {
05451       return exitkind_couldEscape (e->exitCode);
05452     }
05453   return FALSE;
05454 }
05455 
05456 static bool
05457 exprNode_mustBreak (exprNode e)
05458 {
05459   if (exprNode_isDefined (e))
05460     {
05461       return e->mustBreak;
05462     }
05463   return FALSE;
05464 }
05465 
05466 bool
05467 exprNode_mustEscape (exprNode e)
05468 {
05469   if (exprNode_isDefined (e))
05470     {
05471       return exitkind_mustEscape (e->exitCode) || exprNode_mustBreak (e);
05472     }
05473 
05474   return FALSE;
05475 }
05476 
05477 bool
05478 exprNode_errorEscape (exprNode e)
05479 {
05480   if (exprNode_isDefined (e))
05481     {
05482       return exitkind_isError (e->exitCode);
05483     }
05484 
05485   return FALSE;
05486 }
05487 
05488 exprNode exprNode_concat (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
05489 {
05490   exprNode ret = exprNode_createPartialCopy (e1);
05491 
05492   ret->edata = exprData_makePair (e1, e2);
05493   ret->kind = XPR_STMTLIST;
05494 
05495   if (exprNode_isDefined (e1))
05496     {
05497       ret->isJumpPoint = e1->isJumpPoint;
05498       ret->canBreak = e1->canBreak;
05499     }
05500   else
05501     {
05502       if (exprNode_isDefined (e2))
05503         {
05504           ret->loc = fileloc_update (ret->loc, e2->loc);
05505         }
05506     }
05507 
05508   if (exprNode_isDefined (e2))
05509     {
05510       ret->exitCode = e2->exitCode;
05511       ret->mustBreak = e2->mustBreak;
05512       if (e2->canBreak) ret->canBreak = TRUE;
05513     }
05514 
05515   /* 
05516   ** if e1 must return, then e2 is unreachable!
05517   */
05518 
05519   if (exprNode_isDefined (e1) && exprNode_isDefined (e2))
05520     {
05521       if ((exprNode_mustEscape (e1) || exprNode_mustBreak (e1)) 
05522           && !(e2->isJumpPoint))
05523         {
05524           if (context_getFlag (FLG_UNREACHABLE))
05525             {
05526               exprNode nr = e2;
05527 
05528               if (e2->kind == XPR_STMT)
05529                 {
05530                   nr = exprData_getSingle (e2->edata);
05531                 }
05532 
05533               if ((nr->kind == XPR_TOK 
05534                    && lltok_isSemi (exprData_getTok (nr->edata))))
05535                 {
05536                   /* okay to have unreachable ";" */
05537                   ret->exitCode = XK_MUSTEXIT;
05538                   ret->canBreak = TRUE;
05539                 }
05540               else
05541                 {
05542                   if (optgenerror (FLG_UNREACHABLE,
05543                                    message ("Unreachable code: %s", 
05544                                             exprNode_unparseFirst (nr)),
05545                                    exprNode_loc (nr)))
05546                     {
05547                       ret->isJumpPoint = TRUE;                
05548                       ret->mustBreak = FALSE;
05549                       ret->exitCode = XK_ERROR;
05550                       DPRINTF (("Jump point: %s", exprNode_unparse (ret)));
05551                     }
05552                   else
05553                     {
05554                       ret->exitCode = XK_MUSTEXIT;
05555                       ret->canBreak = TRUE;
05556                     }
05557 
05558                 }
05559             }
05560         }
05561       else
05562         {
05563           if ((e2->kind == XPR_CASE || e2->kind == XPR_DEFAULT))
05564             {
05565               /*
05566               ** We want a warning anytime we have:
05567               **         case xxx: ...  
05568               **                   yyy;  <<<- no break or return
05569               **         case zzz: ...
05570               */
05571               
05572               exprNode lastStmt = exprNode_lastStatement (e1);
05573               
05574               if (exprNode_isDefined (lastStmt) 
05575                   && !exprNode_mustEscape (lastStmt)
05576                   && !exprNode_mustBreak (lastStmt)
05577                   && !exprNode_isCaseMarker (lastStmt)
05578                   && !exprNode_isDefaultMarker (lastStmt)
05579                   && !exprNode_isLabelMarker (lastStmt))
05580                 {
05581                   voptgenerror (FLG_CASEBREAK,
05582                                 cstring_makeLiteral 
05583                                 ("Fall through case (no preceeding break)"),
05584                                 e2->loc);
05585                 }
05586             }
05587         }
05588     }
05589 
05590   exprNode_mergeUSs (ret, e2);
05591   
05592   usymtab_setExitCode (ret->exitCode);
05593   
05594   if (ret->mustBreak)
05595     {
05596       usymtab_setMustBreak ();
05597     }
05598 
05599   return ret;
05600 }
05601 
05602 exprNode exprNode_createTok (/*@only@*/ lltok t)
05603 {
05604   exprNode ret = exprNode_create (ctype_unknown);
05605   ret->kind = XPR_TOK;
05606   ret->edata = exprData_makeTok (t);
05607   return ret;
05608 }
05609 
05610 exprNode exprNode_statement (/*@only@*/ exprNode e)
05611 {
05612   if (!exprNode_isError (e))
05613     {
05614       exprNode_checkStatement(e);
05615     }
05616 
05617   return (exprNode_statementError (e));
05618 }
05619 
05620 static exprNode exprNode_statementError (/*@only@*/ exprNode e)
05621 {
05622   exprNode ret = exprNode_createPartialCopy (e);
05623 
05624   if (!exprNode_isError (e))
05625     {
05626       if (e->kind != XPR_ASSIGN)
05627         {
05628           exprNode_checkUse (ret, e->sref, e->loc);
05629         }
05630 
05631       ret->exitCode = e->exitCode;
05632       ret->canBreak = e->canBreak;
05633       ret->mustBreak = e->mustBreak;
05634     }
05635   
05636   ret->edata = exprData_makeSingle (e);
05637   ret->kind = XPR_STMT;
05638 
05639   return ret;
05640 }
05641 
05642 exprNode exprNode_checkExpr (/*@returned@*/ exprNode e)
05643 {
05644   if (!exprNode_isError (e))
05645     {
05646       if (e->kind != XPR_ASSIGN)
05647         {
05648           exprNode_checkUse (e, e->sref, e->loc);
05649         }
05650     }
05651 
05652   return e;
05653 }
05654 
05655 void exprNode_produceGuards (exprNode pred)
05656 {
05657   if (!exprNode_isError (pred))
05658     {
05659       if (ctype_isRealPointer (pred->typ))
05660         {
05661           pred->guards = guardSet_addTrueGuard (pred->guards, pred->sref);
05662         }
05663       
05664       exprNode_checkUse (pred, pred->sref, pred->loc);
05665       exprNode_resetSref (pred);
05666     }
05667 }
05668 
05669 exprNode exprNode_makeBlock (/*@only@*/ exprNode e)
05670 {
05671   exprNode ret = exprNode_createPartialCopy (e);
05672 
05673   if (!exprNode_isError (e))
05674     {
05675       ret->exitCode = e->exitCode;
05676       ret->canBreak = e->canBreak;
05677       ret->mustBreak = e->mustBreak;
05678     }
05679   
05680   ret->edata = exprData_makeSingle (e);
05681   ret->kind = XPR_BLOCK;
05682   return ret;
05683 }
05684 
05685 bool exprNode_isBlock (exprNode e)
05686 {
05687   return (exprNode_isDefined (e) 
05688           && ((e)->kind == XPR_BLOCK));
05689 }
05690  
05691 bool exprNode_isAssign (exprNode e)
05692 {
05693   if (exprNode_isDefined (e))
05694     {
05695       return (e->kind == XPR_ASSIGN);
05696     }
05697 
05698   return FALSE;
05699 }
05700 
05701 bool exprNode_isEmptyStatement (exprNode e)
05702 {
05703   return (exprNode_isDefined (e) 
05704           && (e->kind == XPR_TOK)
05705           && (lltok_isSemi (exprData_getTok (e->edata))));
05706 }
05707 
05708 exprNode exprNode_if (/*@only@*/ exprNode pred, /*@only@*/ exprNode tclause)
05709 {
05710   exprNode ret;
05711   bool emptyErr = FALSE;
05712 
05713   if (context_maybeSet (FLG_IFEMPTY))
05714     {
05715       if (exprNode_isEmptyStatement (tclause))
05716         {
05717           emptyErr = optgenerror (FLG_IFEMPTY,
05718                                   cstring_makeLiteral
05719                                   ("Body of if statement is empty"),
05720                                   exprNode_loc (tclause));
05721         }
05722     }
05723 
05724   if (!emptyErr && context_maybeSet (FLG_IFBLOCK))
05725     {
05726       if (exprNode_isDefined (tclause)
05727           && !exprNode_isBlock (tclause))
05728         {
05729           voptgenerror (FLG_IFBLOCK,
05730                         message
05731                         ("Body of if statement is not a block: %s",
05732                          exprNode_unparse (tclause)),
05733                         exprNode_loc (tclause));
05734         }
05735     }
05736 
05737   if (exprNode_isError (pred))
05738     {
05739       if (exprNode_isError (tclause))
05740         {
05741           ret = exprNode_createLoc (ctype_unknown, g_currentloc);
05742         }
05743       else
05744         {
05745           ret = exprNode_createPartialCopy (tclause);
05746         }
05747     }
05748   else
05749     {
05750       if (exprNode_mustEscape (pred))
05751         {
05752           voptgenerror 
05753             (FLG_UNREACHABLE,
05754              message ("Predicate always exits: %s", exprNode_unparse (pred)),
05755              exprNode_loc (pred));
05756         }
05757 
05758       exprNode_checkPred (cstring_makeLiteralTemp ("if"), pred);
05759       exprNode_checkUse (pred, pred->sref, pred->loc);
05760       
05761       if (!exprNode_isError (tclause))
05762         {
05763           exprNode_mergeCondUSs (pred, tclause, exprNode_undefined);
05764         }
05765       
05766       ret = exprNode_createPartialCopy (pred);
05767     }
05768 
05769   ret->kind = XPR_IF;
05770   ret->edata = exprData_makePair (pred, tclause);
05771 
05772   ret->exitCode = XK_UNKNOWN;
05773 
05774   if (exprNode_isDefined (tclause))
05775     {
05776       ret->exitCode = exitkind_makeConditional (tclause->exitCode);
05777       ret->canBreak = tclause->canBreak;
05778       ret->sets = sRefSet_union (ret->sets, tclause->sets);
05779       ret->msets = sRefSet_union (ret->msets, tclause->msets);
05780       ret->uses = sRefSet_union (ret->uses, tclause->uses);
05781     }
05782 
05783   ret->mustBreak = FALSE;
05784 
05785   return ret;
05786 }
05787 
05788 exprNode exprNode_ifelse (/*@only@*/ exprNode pred,
05789                           /*@only@*/ exprNode tclause, 
05790                           /*@only@*/ exprNode eclause)
05791 {
05792   exprNode ret;
05793   bool tEmptyErr = FALSE;
05794   bool eEmptyErr = FALSE;
05795 
05796   if (context_maybeSet (FLG_IFEMPTY))
05797     {
05798       if (exprNode_isEmptyStatement (tclause))
05799         {
05800           tEmptyErr = optgenerror 
05801             (FLG_IFEMPTY,
05802              cstring_makeLiteral
05803              ("Body of if clause of if statement is empty"),
05804              exprNode_loc (tclause));
05805         }
05806 
05807       if (exprNode_isEmptyStatement (eclause))
05808         {
05809           eEmptyErr = optgenerror 
05810             (FLG_IFEMPTY,
05811              cstring_makeLiteral
05812              ("Body of else clause of if statement is empty"),
05813              exprNode_loc (eclause));
05814         }
05815     }
05816 
05817   if (context_maybeSet (FLG_IFBLOCK))
05818     {
05819       if (!tEmptyErr
05820           && exprNode_isDefined (tclause)
05821           && !exprNode_isBlock (tclause))
05822         {
05823           voptgenerror (FLG_IFBLOCK,
05824                         message
05825                         ("Body of if clause of if statement is not a block: %s",
05826                          exprNode_unparse (tclause)),
05827                         exprNode_loc (tclause));
05828         }
05829 
05830       if (!eEmptyErr
05831           && exprNode_isDefined (eclause)
05832           && !exprNode_isBlock (eclause)
05833           && !(eclause->kind == XPR_IF)
05834           && !(eclause->kind == XPR_IFELSE))
05835         {
05836           voptgenerror
05837             (FLG_IFBLOCK,
05838              message
05839              ("Body of else clause of if statement is not a block: %s",
05840               exprNode_unparse (eclause)),
05841              exprNode_loc (eclause));
05842         }
05843     }
05844 
05845   if (context_maybeSet (FLG_ELSEIFCOMPLETE))
05846     {
05847       if (exprNode_isDefined (eclause)
05848           && (eclause->kind == XPR_IF))
05849         {
05850           voptgenerror (FLG_ELSEIFCOMPLETE,
05851                         message ("Incomplete else if logic (no final else): %s",
05852                                  exprNode_unparse (eclause)),
05853                         exprNode_loc (eclause));
05854         }
05855     }
05856 
05857   if (exprNode_isError (pred))
05858     {
05859       if (exprNode_isError (tclause))
05860         {
05861           if (exprNode_isError (eclause))
05862             {
05863               ret = exprNode_createLoc (ctype_unknown, g_currentloc);
05864             }
05865           else
05866             {
05867               ret = exprNode_createPartialCopy (eclause);
05868             }
05869         }
05870       else 
05871         {
05872           ret = exprNode_createPartialCopy (tclause);
05873         }
05874     }
05875   else /* pred is okay */
05876     {
05877       ret = exprNode_createPartialCopy (pred);
05878 
05879       if (exprNode_mustEscape (pred))
05880         {
05881           voptgenerror
05882             (FLG_UNREACHABLE,
05883              message ("Predicate always exits: %s", exprNode_unparse (pred)),
05884              exprNode_loc (pred));
05885         }
05886       
05887       exprNode_checkPred (cstring_makeLiteralTemp ("if"), pred);
05888       exprNode_checkUse (ret, pred->sref, pred->loc);
05889       
05890       exprNode_mergeCondUSs (ret, tclause, eclause);
05891     }
05892 
05893   ret->kind = XPR_IFELSE;
05894   ret->edata = exprData_makeCond (pred, tclause, eclause);
05895 
05896   if (exprNode_isDefined (tclause) && exprNode_isDefined (eclause))
05897     {
05898       exprNode_combineControl (ret, tclause, eclause);
05899       ret->loc = fileloc_update (ret->loc, eclause->loc);
05900     }
05901 
05902   return ret;
05903 }
05904 
05905 /*
05906 ** *allpaths <- TRUE iff all executions paths must go through the switch
05907 */
05908 
05909 static bool
05910 checkSwitchExpr (exprNode test, /*@dependent@*/ exprNode e, /*@out@*/ bool *allpaths)
05911 {
05912   exprNodeSList el = exprNode_flatten (e);
05913   bool mustReturn = TRUE; /* find a branch that doesn't */
05914   bool thisReturn = FALSE;
05915   bool hasDefault = FALSE;
05916   bool hasAllMembers = FALSE;
05917   bool inSwitch = FALSE;
05918   bool isEnumSwitch = FALSE;
05919   bool canBreak = FALSE;
05920   bool fallThrough = FALSE;
05921   ctype ct = ctype_unknown;
05922   enumNameSList usedEnums;
05923   enumNameList enums;
05924 
05925   if (exprNode_isDefined (test))
05926     {
05927       ctype ttype;
05928 
05929       ct = test->typ;
05930       ttype = ctype_realType (ct);
05931 
05932       if (ctype_isEnum (ttype))
05933         {
05934           isEnumSwitch = TRUE;
05935           enums = ctype_elist (ttype);
05936           usedEnums = enumNameSList_new ();
05937         }
05938     }
05939 
05940   exprNodeSList_elements (el, current)
05941     {
05942       if (exprNode_isDefined (current))
05943         {
05944           switch (current->kind)
05945             {
05946             case XPR_FTDEFAULT:
05947             case XPR_DEFAULT:
05948               if (hasDefault)
05949                 {
05950                   voptgenerror 
05951                     (FLG_CONTROL,
05952                      message ("Duplicate default cases in switch"),
05953                      exprNode_loc (current));
05954                 }          
05955             /*@fallthrough@*/
05956             case XPR_FTCASE:
05957             case XPR_CASE: 
05958               if (current->kind == XPR_DEFAULT || current->kind == XPR_FTDEFAULT)
05959                 {
05960                   hasDefault = TRUE; 
05961                 }
05962               else
05963                 {
05964                   if (isEnumSwitch)
05965                     {
05966                       exprNode st = exprData_getSingle (current->edata);
05967                       uentry ue = exprNode_getUentry (st);
05968                       
05969                       if (uentry_isValid (ue))
05970                         {
05971                           cstring cname = uentry_rawName (ue);
05972                           
05973                           if (enumNameList_member (/*@-usedef@*/enums/*@=usedef@*/, cname))
05974                             {
05975                               if (enumNameSList_member
05976                                   (/*@-usedef@*/usedEnums/*@=usedef@*/, cname))
05977                                 {
05978                                   voptgenerror
05979                                     (FLG_CONTROL,
05980                                      message ("Duplicate case in switch: %s", 
05981                                               cname),
05982                                      current->loc);
05983                                 }
05984                               else
05985                                 {
05986                                   enumNameSList_addh (usedEnums, cname);
05987                                 }
05988                             }
05989                           else
05990                             {
05991                               voptgenerror 
05992                                 (FLG_TYPE,
05993                                  message ("Case in switch not %s member: %s", 
05994                                           ctype_unparse (ct), cname),
05995                                  current->loc);
05996                             }
05997                         }
05998                     }
05999                 }
06000               
06001               if (inSwitch && !fallThrough)
06002                 {
06003                   if (!thisReturn || canBreak) 
06004                     {
06005                       mustReturn = FALSE;
06006                     }
06007                 }
06008               
06009               fallThrough = TRUE;
06010               inSwitch = TRUE;
06011               thisReturn = FALSE;
06012               canBreak = FALSE;
06013               /*@switchbreak@*/ break;
06014             default:
06015               thisReturn = thisReturn || exprNode_mustEscape (current);
06016               canBreak = canBreak || current->canBreak;
06017               if (canBreak) fallThrough = FALSE;
06018             }
06019         }
06020     } end_exprNodeSList_elements;
06021 
06022   if (inSwitch) /* check the last one! */
06023     {
06024       if (!thisReturn || canBreak) 
06025         {
06026           mustReturn = FALSE;
06027         }
06028     }
06029   
06030   if (isEnumSwitch)
06031     {
06032       if (!hasDefault 
06033           && (enumNameSList_size (/*@-usedef@*/usedEnums/*@=usedef@*/) != 
06034               enumNameList_size (/*@-usedef@*/enums/*@=usedef@*/)))
06035         {
06036           enumNameSList unused = enumNameSList_subtract (enums, usedEnums);
06037           
06038           voptgenerror (FLG_MISSCASE,
06039                         message ("Missing case%s in switch: %q",
06040                                  cstring_makeLiteralTemp 
06041                                  ((enumNameSList_size (unused) > 1) ? "s" : ""),
06042                                  enumNameSList_unparse (unused)),
06043                         g_currentloc);
06044 
06045           enumNameSList_free (unused);
06046         }
06047       else
06048         {
06049           hasAllMembers = TRUE;
06050           *allpaths = TRUE;
06051         }
06052 
06053       enumNameSList_free (usedEnums);
06054     }
06055   else
06056     {
06057       *allpaths = hasDefault;
06058     }
06059 
06060   exprNodeSList_free (el);
06061   return ((hasDefault || hasAllMembers) && mustReturn);  
06062 }
06063     
06064 exprNode exprNode_switch (/*@only@*/ exprNode e, /*@only@*/ exprNode s)
06065 {
06066   exprNode ret = exprNode_createPartialCopy (e);
06067   bool allpaths;
06068 
06069   DPRINTF (("Switch: %s", exprNode_unparse (s)));
06070 
06071   ret->kind = XPR_SWITCH;
06072   ret->edata = exprData_makePair (e, s);
06073   
06074   if (!exprNode_isError (s))
06075     {
06076       exprNode fs = exprNode_firstStatement (s);
06077       ret->loc = fileloc_update (ret->loc, s->loc);
06078 
06079       if (exprNode_isUndefined (fs) 
06080           || exprNode_isCaseMarker (fs) || exprNode_isLabelMarker (fs)
06081           || exprNode_isDefaultMarker (fs)) {
06082         ;
06083       } else {
06084         voptgenerror (FLG_FIRSTCASE,
06085                       message
06086                       ("Statement after switch is not a case: %s", exprNode_unparse (fs)),
06087                       fs->loc);
06088       }
06089     }
06090 
06091   if (!exprNode_isError (e)) 
06092     {
06093       if (checkSwitchExpr (e, s, &allpaths))
06094         {
06095           ret->exitCode = XK_MUSTRETURN;
06096         }
06097       else
06098         {
06099           ret->exitCode = e->exitCode;
06100         }
06101 
06102       ret->canBreak = e->canBreak;
06103       ret->mustBreak = e->mustBreak;
06104     }
06105   /*
06106   ** forgot this!
06107   **   exprNode.c:3883,32: Variable allpaths used before definition
06108   */
06109   else 
06110     {
06111       allpaths = FALSE;
06112     }
06113   
06114   DPRINTF (("Context exit switch!"));
06115   context_exitSwitch (ret, allpaths);
06116   DPRINTF (("Context exit switch done!"));
06117 
06118   return ret;
06119 }
06120 
06121 static void checkInfiniteLoop (/*@notnull@*/ exprNode test,
06122                                /*@notnull@*/ exprNode body)
06123 {
06124   sRefSet tuses = test->uses;
06125   
06126   if (!sRefSet_isEmpty (test->uses))
06127     {
06128       sRefSet sets = sRefSet_newCopy (body->sets);
06129       bool hasError = TRUE;
06130       bool innerState = FALSE;
06131       sRefSet tuncon = sRefSet_undefined;
06132       
06133       sets = sRefSet_union (sets, test->sets);
06134       sets = sRefSet_union (sets, body->msets);
06135       sets = sRefSet_union (sets, test->msets);
06136 
06137       sRefSet_allElements (tuses, el)
06138         {
06139           if (sRef_isUnconstrained (el))
06140             {
06141               tuncon = sRefSet_insert (tuncon, el);
06142             }
06143           else
06144             {
06145               if (sRefSet_member (sets, el))
06146                 {
06147                   hasError = FALSE;
06148                   break;
06149                 }
06150             }
06151 
06152           if (sRef_isInternalState (el)
06153               || sRef_isFileStatic (sRef_getRootBase (el)))
06154             {
06155               innerState = TRUE;
06156             }
06157         } end_sRefSet_allElements ;
06158 
06159       if (hasError)
06160         {
06161           sRefSet suncon = sRefSet_undefined;
06162           bool sinner = FALSE;
06163 
06164           sRefSet_allElements (sets, el)
06165             {
06166               if (sRef_isUnconstrained (el))
06167                 {
06168                   suncon = sRefSet_insert (suncon, el);
06169                 }
06170               else if (sRef_isInternalState (el))
06171                 {
06172                   sinner = TRUE;
06173                 }
06174               else
06175                 {
06176                   ;
06177                 }
06178             } end_sRefSet_allElements ;
06179 
06180           if (sinner && innerState)
06181             {
06182               ; 
06183             }
06184           else if (sRefSet_isEmpty (tuncon)
06185                    && sRefSet_isEmpty (suncon))
06186             {
06187               voptgenerror 
06188                 (FLG_INFLOOPS,
06189                  message
06190                  ("Suspected infinite loop.  No value used in loop test (%q) "
06191                   "is modified by test or loop body.",
06192                   sRefSet_unparsePlain (tuses)), 
06193                  test->loc);
06194             }
06195           else
06196             {
06197               if (sRefSet_isEmpty (tuncon))
06198                 {
06199                   voptgenerror 
06200                     (FLG_INFLOOPSUNCON,
06201                      message ("Suspected infinite loop.  No condition values "
06202                               "modified.  Modification possible through "
06203                               "unconstrained calls: %q",
06204                               sRefSet_unparsePlain (suncon)), 
06205                      test->loc);
06206                 }
06207               else
06208                 {
06209                   voptgenerror 
06210                     (FLG_INFLOOPSUNCON,
06211                      message ("Suspected infinite loop.  No condition values "
06212                               "modified.  Possible undetected dependency through "
06213                               "unconstrained calls in loop test: %q",
06214                               sRefSet_unparsePlain (tuncon)), 
06215                      test->loc);
06216                 }
06217             }
06218         }
06219 
06220       sRefSet_free (sets);
06221     }
06222 }
06223 
06224 exprNode exprNode_while (/*@keep@*/ exprNode t, /*@keep@*/ exprNode b)
06225 {
06226   exprNode ret;
06227   bool emptyErr = FALSE;
06228   
06229   if (context_maybeSet (FLG_WHILEEMPTY))
06230     {
06231       if (exprNode_isEmptyStatement (b))
06232         {
06233           emptyErr = optgenerror 
06234             (FLG_WHILEEMPTY,
06235              cstring_makeLiteral
06236              ("Body of while statement is empty"),
06237              exprNode_loc (b));
06238         }
06239     }
06240 
06241   if (!emptyErr && context_maybeSet (FLG_WHILEBLOCK))
06242     {
06243       if (exprNode_isDefined (b)
06244           && !exprNode_isBlock (b))
06245         {
06246           if (context_inIterDef ()
06247               && (b->kind == XPR_STMTLIST
06248                   || b->kind == XPR_TOK))
06249             {
06250               ; /* no error */
06251             }
06252           else
06253             {
06254               voptgenerror (FLG_WHILEBLOCK,
06255                             message
06256                             ("Body of while statement is not a block: %s",
06257                              exprNode_unparse (b)),
06258                             exprNode_loc (b));
06259             }
06260         }
06261     }
06262   
06263   if (exprNode_isError (t))
06264     {
06265       if (exprNode_isError (b))
06266         {
06267           ret = exprNode_createLoc (ctype_unknown, g_currentloc);
06268         }
06269       else
06270         {
06271           ret = exprNode_createPartialCopy (b);
06272         }
06273     }
06274   else
06275     {
06276       exprNode test;
06277 
06278       ret = exprNode_createPartialCopy (t);
06279       
06280       llassert (t->kind == XPR_WHILEPRED);
06281 
06282       test = exprData_getSingle (t->edata);
06283 
06284       if (!exprNode_isError (b) && exprNode_isDefined (test))
06285         {
06286           if (context_maybeSet (FLG_INFLOOPS)
06287               || context_maybeSet (FLG_INFLOOPSUNCON))
06288             {
06289               /*
06290               ** check that some variable in the predicate is set by the body
06291               ** if the predicate uses any variables
06292               */
06293               
06294               checkInfiniteLoop (test, b);
06295             }
06296 
06297           exprNode_mergeUSs (ret, b);
06298 
06299           if (exprNode_isDefined (b))
06300             {
06301               ret->exitCode = exitkind_makeConditional (b->exitCode);
06302             }
06303         }
06304     }
06305   
06306   ret->edata = exprData_makePair (t, b);
06307   ret->kind = XPR_WHILE;
06308 
06309   if (exprNode_isDefined (t) && exprNode_mustEscape (t))
06310     {
06311       voptgenerror
06312         (FLG_CONTROL,
06313          message ("Predicate always exits: %s", exprNode_unparse (t)),
06314          exprNode_loc (t));
06315     }
06316 
06317   ret->exitCode = XK_NEVERESCAPE;
06318 
06319   /*
06320   ** If loop is infinite, and there is no break inside, 
06321   ** exit code is never reach. 
06322   */
06323 
06324   if (exprNode_knownIntValue (t))
06325     {
06326       if (!exprNode_isZero (t)) 
06327         {
06328           if (exprNode_isDefined (b)) 
06329             {
06330               if (!b->canBreak) 
06331                 {
06332                   /* Really, it means never reached. */
06333                   ret->exitCode = XK_MUSTEXIT;
06334                 }
06335             }
06336         }
06337     } 
06338   else 
06339     {
06340       ;
06341     }
06342 
06343   ret->canBreak = FALSE;
06344   ret->mustBreak = FALSE;
06345 
06346   return ret; 
06347 }
06348 
06349 /*
06350 ** do { b } while (t);
06351 ** 
06352 ** note: body passed as first argument 
06353 */
06354 
06355 exprNode exprNode_doWhile (/*@only@*/ exprNode b, /*@only@*/ exprNode t)
06356 {
06357   exprNode ret;
06358   
06359   if (exprNode_isError (t))
06360     {
06361       if (exprNode_isError (b))
06362         {
06363           ret = exprNode_createLoc (ctype_unknown, g_currentloc);
06364         }
06365       else
06366         {
06367           ret = exprNode_createPartialCopy (b);
06368 
06369           ret->exitCode = exitkind_makeConditional (b->exitCode);
06370           exprNode_checkUse (ret, b->sref, b->loc);
06371           ret->exitCode = b->exitCode;
06372           ret->canBreak = b->canBreak;
06373           ret->mustBreak = b->mustBreak;
06374         }
06375     }
06376   else
06377     {
06378       ret = exprNode_createPartialCopy (t);
06379       exprNode_checkPred (cstring_makeLiteralTemp ("while"), t);
06380       
06381       if (!exprNode_isError (b)) 
06382         {
06383           /*
06384           ** forgot the copy's --- why wasn't this detected??
06385           */
06386 
06387           ret->sets = sRefSet_copy (ret->sets, b->sets);
06388           ret->msets = sRefSet_copy (ret->msets, b->msets);
06389           ret->uses = sRefSet_copy (ret->uses, b->uses);  
06390 
06391           /* left this out --- causes and aliasing bug (infinite loop)
06392              should be detected?? */
06393 
06394           exprNode_checkUse (ret, b->sref, b->loc);
06395           exprNode_mergeUSs (ret, t);
06396           exprNode_checkUse (ret, t->sref, t->loc);
06397 
06398           ret->exitCode = b->exitCode;
06399           ret->canBreak = b->canBreak;
06400           ret->mustBreak = b->mustBreak;
06401         }
06402     }
06403   
06404   context_exitDoWhileClause (t);
06405 
06406   ret->kind = XPR_DOWHILE;
06407   ret->edata = exprData_makePair (t, b);
06408     return ret;
06409 }
06410 
06411 exprNode exprNode_for (/*@keep@*/ exprNode inc, /*@keep@*/ exprNode body)
06412 {
06413   exprNode ret;
06414   bool emptyErr = FALSE;
06415 
06416   if (context_maybeSet (FLG_FOREMPTY))
06417     {
06418       if (exprNode_isEmptyStatement (body))
06419         {
06420           emptyErr = optgenerror 
06421             (FLG_FOREMPTY,
06422              cstring_makeLiteral
06423              ("Body of for statement is empty"),
06424              exprNode_loc (body));
06425         }
06426     }
06427 
06428   if (!emptyErr && context_maybeSet (FLG_FORBLOCK))
06429     {
06430       if (exprNode_isDefined (body)
06431           && !exprNode_isBlock (body))
06432         {
06433           if (context_inIterDef ()
06434               && (body->kind == XPR_STMTLIST
06435                   || body->kind == XPR_TOK))
06436             {
06437               ; /* no error */
06438             }
06439           else
06440             {
06441               voptgenerror (FLG_FORBLOCK,
06442                             message
06443                             ("Body of for statement is not a block: %s",
06444                              exprNode_unparse (body)),
06445                             exprNode_loc (body));
06446             }
06447         }
06448     }
06449 
06450   /*
06451   ** for ud purposes:  (alreadly) init -> test -> (now) LOOP: body + inc + test
06452   */
06453 
06454   if (exprNode_isError (body))
06455     {
06456       ret = exprNode_createPartialCopy (inc);
06457     }
06458   else
06459     {
06460       ret = exprNode_createPartialCopy (body);
06461       
06462       ret->exitCode = exitkind_makeConditional (body->exitCode);
06463 
06464             exprNode_mergeUSs (inc, body);
06465       
06466       if (exprNode_isDefined (inc))
06467         {
06468           exprNode tmp;
06469 
06470           context_setMessageAnnote (cstring_makeLiteral ("in post loop increment"));
06471      
06472           
06473           tmp = exprNode_effect (exprData_getTripleInc (inc->edata));
06474           exprNode_freeShallow (tmp); 
06475 
06476           context_clearMessageAnnote ();
06477           context_setMessageAnnote (cstring_makeLiteral ("in post loop test"));
06478 
06479           tmp = exprNode_effect (exprData_getTripleTest (inc->edata));
06480           exprNode_freeShallow (tmp);
06481 
06482           context_clearMessageAnnote ();
06483 
06484           ret->uses = sRefSet_copy (ret->uses, inc->uses);
06485           ret->sets = sRefSet_copy (ret->sets, inc->sets);
06486           ret->msets = sRefSet_copy (ret->msets, inc->msets);
06487         }
06488     }
06489 
06490   ret->kind = XPR_FOR;
06491   ret->edata = exprData_makePair (inc, body);
06492 
06493   if (exprNode_isDefined (inc)) {
06494     exprNode test = exprData_getTripleTest (inc->edata);
06495 
06496     if (exprNode_isUndefined (test)) {
06497       if (exprNode_isDefined (body)) {
06498         if (!body->canBreak) {
06499           /* Really, it means never reached. */
06500           ret->exitCode = XK_MUSTEXIT;
06501         }
06502       }
06503     }
06504   }
06505 
06506   return (ret);
06507 }
06508 
06509 /*
06510 ** for (init; test; inc)
06511 ** ==>
06512 ** init;
06513 ** while (test) { body; inc; } 
06514 **
06515 ** Now: check use of init (may set vars for test)
06516 **      check use of test
06517 **      no checks on inc
06518 _*/
06519 
06520 /*@observer@*/ guardSet exprNode_getForGuards (exprNode pred)
06521 {
06522   exprNode test;
06523 
06524   if (exprNode_isError (pred)) return guardSet_undefined;
06525 
06526   llassert (pred->kind == XPR_FORPRED);
06527 
06528   test = exprData_getTripleTest (pred->edata);
06529 
06530   if (!exprNode_isError (test))
06531     {
06532       return (test->guards);
06533     }
06534 
06535   return guardSet_undefined;
06536 }
06537 
06538 exprNode exprNode_whilePred (/*@only@*/ exprNode test)
06539 {
06540   exprNode ret = exprNode_createSemiCopy (test);
06541 
06542   if (exprNode_isDefined (test))
06543     {
06544       exprNode_copySets (ret, test);
06545       exprNode_checkPred (cstring_makeLiteralTemp ("while"), test);
06546       exprNode_checkUse (ret, test->sref, test->loc);
06547       
06548       exprNode_produceGuards (test);
06549       
06550       ret->guards = guardSet_copy (test->guards);
06551     }
06552 
06553   ret->edata = exprData_makeSingle (test);
06554   ret->kind = XPR_WHILEPRED;
06555   return ret;
06556 }
06557 
06558 exprNode exprNode_forPred (/*@only@*/ exprNode init, /*@only@*/ exprNode test, 
06559                            /*@only@*/ exprNode inc)
06560 {
06561   exprNode ret;
06562   
06563   /*
06564   ** for ud purposes:  init -> test -> LOOP: [ body, inc ]
06565   */
06566   
06567   exprNode_checkPred (cstring_makeLiteralTemp ("for"), test);
06568 
06569   if (!exprNode_isError (inc)) 
06570     {
06571       ret = exprNode_createPartialCopy (inc);
06572     }
06573   else 
06574     {
06575       if (!exprNode_isError (init)) 
06576         {
06577           ret = exprNode_createPartialCopy (init);
06578         }
06579       else if (!exprNode_isError (test)) 
06580         {
06581           ret = exprNode_createPartialCopy (test);
06582         }
06583       else 
06584         {
06585           ret = exprNode_createUnknown ();
06586         }
06587     }
06588 
06589   exprNode_mergeUSs (ret, init);
06590 
06591   if (exprNode_isDefined (init))
06592     {
06593       exprNode_checkUse (ret, init->sref, init->loc);
06594     }
06595 
06596   exprNode_mergeUSs (ret, test);
06597 
06598   if (exprNode_isDefined (test))
06599     {
06600       exprNode_checkUse (ret, test->sref, test->loc);
06601     }
06602 
06603   ret->kind = XPR_FORPRED;
06604   ret->edata = exprData_makeFor (init, test, inc); 
06605   return (ret);
06606 }
06607 
06608 /*@notnull@*/ /*@only@*/ exprNode exprNode_goto (/*@only@*/ cstring label)
06609 {
06610   exprNode ret = exprNode_createUnknown ();
06611 
06612   if (context_inMacro ())
06613     {
06614       voptgenerror (FLG_MACROSTMT,
06615                     message ("Macro %s uses goto (not functional)", 
06616                              context_inFunctionName ()),
06617                     g_currentloc);
06618     }
06619   
06620   ret->kind = XPR_GOTO;
06621   ret->edata = exprData_makeLiteral (label);
06622   ret->mustBreak = TRUE;
06623   ret->exitCode = XK_GOTO;
06624   ret->canBreak = TRUE;
06625   return ret;
06626 }
06627 
06628 exprNode exprNode_continue (/*@only@*/ lltok l, int qcontinue)
06629 {
06630   exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (lltok_getLoc (l)));
06631 
06632   ret->kind = XPR_CONTINUE;
06633   ret->edata = exprData_makeTok (l);
06634   ret->canBreak = TRUE;
06635   ret->mustBreak = TRUE;
06636 
06637   if (qcontinue == QSAFEBREAK)
06638     {
06639       ; /* no checking */
06640     }
06641   else if (qcontinue == QINNERCONTINUE)
06642     {
06643       if (!context_inDeepLoop ())
06644         {
06645           voptgenerror 
06646             (FLG_LOOPLOOPCONTINUE,
06647              cstring_makeLiteral ("Continue statement marked with innercontinue "
06648                                   "is not inside a nested loop"),
06649              exprNode_loc (ret));
06650         }
06651     }
06652   else if (qcontinue == BADTOK)
06653     {
06654       if (context_inDeepLoop ())
06655         {
06656           voptgenerror 
06657             (FLG_LOOPLOOPCONTINUE,
06658              cstring_makeLiteral ("Continue statement in nested loop"),
06659              exprNode_loc (ret));
06660         }
06661     }
06662   else
06663     {
06664       llbuglit ("exprNode_continue: bad qcontinue");
06665     }
06666 
06667   return ret;
06668 }
06669 
06670 exprNode exprNode_break (/*@only@*/ lltok l, int bqual)
06671 {
06672   exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (lltok_getLoc (l)));
06673   clause breakClause = context_breakClause ();
06674   
06675   ret->kind = XPR_BREAK;
06676   ret->edata = exprData_makeTok (l);
06677   ret->canBreak = TRUE;
06678   ret->mustBreak = TRUE;
06679   
06680   if (breakClause == NOCLAUSE)
06681     {
06682       voptgenerror 
06683         (FLG_SYNTAX,
06684          cstring_makeLiteral ("Break not inside while, for or switch statement"),
06685          exprNode_loc (ret));
06686     }
06687   else
06688     {
06689       if (bqual != BADTOK)
06690         {
06691           switch (bqual)
06692             {
06693             case QSAFEBREAK:
06694               break;
06695             case QINNERBREAK:
06696               if (breakClause == SWITCHCLAUSE)
06697                 {
06698                   if (!context_inDeepSwitch ())
06699                     {
06700                       voptgenerror (FLG_SYNTAX,
06701                                     cstring_makeLiteral 
06702                                     ("Break preceded by innerbreak is not in a deep switch"),
06703                                     exprNode_loc (ret));
06704                     }
06705                 }
06706               else 
06707                 {
06708                   if (!context_inDeepLoop ())
06709                     {
06710                       voptgenerror (FLG_SYNTAX,
06711                                     cstring_makeLiteral 
06712                                     ("Break preceded by innerbreak is not in a deep loop"),
06713                                     exprNode_loc (ret));
06714                     }
06715                 }
06716               break;
06717             case QLOOPBREAK:
06718               if (breakClause == SWITCHCLAUSE)
06719                 {
06720                   voptgenerror (FLG_SYNTAX,
06721                                 cstring_makeLiteral 
06722                                 ("Break preceded by loopbreak is breaking a switch"),
06723                                 exprNode_loc (ret));
06724                 }
06725               break;
06726             case QSWITCHBREAK:
06727               if (breakClause != SWITCHCLAUSE)
06728                 {
06729                   voptgenerror 
06730                     (FLG_SYNTAX,
06731                      message ("Break preceded by switchbreak is breaking %s",
06732                               cstring_makeLiteralTemp 
06733                               ((breakClause == WHILECLAUSE
06734                                 || breakClause == DOWHILECLAUSE) ? "a while loop"
06735                                : (breakClause == FORCLAUSE) ? "a for loop"
06736                                : (breakClause == ITERCLAUSE) ? "an iterator"
06737                                : "<error loop>")),
06738                      exprNode_loc (ret));
06739                 }
06740               break;
06741             BADDEFAULT;
06742             }
06743         }
06744       else
06745         {
06746           if (breakClause == SWITCHCLAUSE)
06747             {
06748               clause nextBreakClause = context_nextBreakClause ();
06749 
06750               switch (nextBreakClause)
06751                 {
06752                 case NOCLAUSE: break;
06753                 case WHILECLAUSE:
06754                 case DOWHILECLAUSE:
06755                 case FORCLAUSE:
06756                 case ITERCLAUSE:
06757                   voptgenerror 
06758                     (FLG_LOOPSWITCHBREAK,
06759                      cstring_makeLiteral ("Break statement in switch inside loop"),
06760                      exprNode_loc (ret));
06761                   break;
06762                 case SWITCHCLAUSE:
06763                   voptgenerror 
06764                     (FLG_SWITCHSWITCHBREAK,
06765                      cstring_makeLiteral ("Break statement in switch inside switch"),
06766                      exprNode_loc (ret));
06767                   break;
06768                 BADDEFAULT;
06769                 }
06770             }
06771           else
06772             {
06773               if (context_inDeepLoop ())
06774                 {
06775                   voptgenerror 
06776                     (FLG_LOOPLOOPBREAK,
06777                      cstring_makeLiteral ("Break statement in nested loop"),
06778                      exprNode_loc (ret));
06779                 }
06780               else 
06781                 {
06782                   if (context_inDeepLoopSwitch ())
06783                     {
06784                       voptgenerror 
06785                         (FLG_SWITCHLOOPBREAK,
06786                          cstring_makeLiteral ("Break statement in loop inside switch"),
06787                          exprNode_loc (ret));
06788                     }
06789                 }
06790             }
06791         }
06792     }
06793 
06794   return ret;
06795 }
06796 
06797 exprNode exprNode_nullReturn (/*@only@*/ lltok t)
06798 {
06799   fileloc loc = lltok_getLoc (t);
06800   exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (loc));
06801   
06802   context_returnFunction ();
06803   exprChecks_checkNullReturn (loc);
06804 
06805   ret->kind = XPR_NULLRETURN;
06806   ret->edata = exprData_makeTok (t);
06807   ret->exitCode = XK_MUSTRETURN;
06808   return ret;
06809 }
06810 
06811 exprNode exprNode_return (/*@only@*/ exprNode e)
06812 {
06813   exprNode ret;
06814   
06815   if (exprNode_isError (e))
06816     {
06817       ret = exprNode_createUnknown ();
06818     }
06819   else
06820     {
06821       ret = exprNode_createLoc (ctype_unknown, fileloc_copy (e->loc));
06822 
06823       exprNode_checkUse (ret, e->sref, e->loc);
06824       exprNode_checkReturn (e);
06825     }
06826 
06827   context_returnFunction ();
06828   ret->kind = XPR_RETURN;
06829   ret->edata = exprData_makeSingle (e);
06830   ret->exitCode = XK_MUSTRETURN;
06831 
06832   return (ret);
06833 }
06834 
06835 exprNode exprNode_comma (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
06836 {
06837   exprNode ret;
06838 
06839   if (exprNode_isError (e1)) 
06840     {
06841       if (exprNode_isError (e2))
06842         {
06843           ret = exprNode_createLoc (ctype_unknown, g_currentloc);
06844         }
06845       else
06846         {
06847           ret = exprNode_createPartialCopy (e2);
06848           exprNode_checkUse (ret, e2->sref, e2->loc);
06849           ret->sref = e2->sref;
06850         }
06851     }
06852   else
06853     {
06854       ret = exprNode_createPartialCopy (e1);
06855 
06856       exprNode_checkUse (ret, e1->sref, e1->loc);
06857 
06858       if (!exprNode_isError (e2))
06859         {
06860           exprNode_mergeUSs (ret, e2);
06861           exprNode_checkUse (ret, e2->sref, e2->loc);
06862           ret->sref = e2->sref;
06863         }
06864     }
06865 
06866   ret->kind = XPR_COMMA;
06867   ret->edata = exprData_makePair (e1, e2);
06868   
06869   if (exprNode_isDefined (e1))
06870     {
06871       if (exprNode_isDefined (e2))
06872         {
06873           ret->typ = e2->typ; 
06874 
06875           if (exprNode_mustEscape (e1) || e1->mustBreak)
06876             {
06877               voptgenerror 
06878                 (FLG_UNREACHABLE,
06879                  message ("Second clause of comma expression is unreachable: %s",
06880                           exprNode_unparse (e2)), 
06881                  exprNode_loc (e2));
06882             }
06883           
06884           ret->exitCode = exitkind_combine (e1->exitCode, e2->exitCode);
06885           ret->mustBreak = e1->mustBreak || e2->mustBreak;
06886           ret->canBreak = e1->canBreak || e2->canBreak;
06887         }
06888       else
06889         {
06890           if (exprNode_mustEscape (e1) || e1->mustBreak)
06891             {
06892               voptgenerror 
06893                 (FLG_UNREACHABLE,
06894                  message ("Second clause of comma expression is unreachable: %s",
06895                           exprNode_unparse (e2)), 
06896                  exprNode_loc (e2));
06897             }
06898           
06899           ret->exitCode = e1->exitCode;
06900           ret->canBreak = e1->canBreak;
06901         }
06902     }
06903   else
06904     {
06905       if (exprNode_isDefined (e2))
06906         {
06907           ret->exitCode = e2->exitCode;
06908           ret->mustBreak = e2->mustBreak;
06909           ret->canBreak = e2->canBreak;
06910         }
06911     }
06912 
06913   return (ret);
06914 }
06915 
06916 static bool exprNode_checkOneInit (/*@notnull@*/ exprNode el, exprNode val)
06917 {
06918   ctype t1 = exprNode_getType (el);
06919   ctype t2 = exprNode_getType (val);
06920   bool hasError = FALSE;
06921   
06922   if (ctype_isUnknown (t1))
06923     {
06924       voptgenerror (FLG_IMPTYPE,
06925                     message ("Variable has unknown (implicitly int) type: %s",
06926                              exprNode_unparse (el)),
06927                     el->loc);
06928       
06929       t1 = ctype_int;
06930       el->typ = ctype_int;
06931     }
06932 
06933   if (exprNode_isDefined (val) && val->kind == XPR_INITBLOCK)
06934     {
06935       exprNodeList vals = exprData_getArgs (val->edata);
06936 
06937       if (ctype_isRealAP (t1))
06938         {
06939           int i = 0;
06940           int nerrors = 0;
06941 
06942           exprNodeList_elements (vals, oneval)
06943             {
06944               cstring istring = message ("%d", i);
06945               exprNode newel =
06946                 exprNode_arrayFetch 
06947                   (exprNode_fakeCopy (el),
06948                    exprNode_numLiteral (ctype_int, istring,
06949                                         fileloc_copy (el->loc), i));
06950               
06951               if (exprNode_isDefined (newel))
06952                 {
06953                   if (exprNodeList_size (vals) == 1
06954                       && ctype_isString (exprNode_getType (oneval))
06955                       && ctype_isChar (exprNode_getType (newel)))
06956                     {
06957                       exprNode_freeIniter (newel);
06958                     }
06959                   else
06960                     {
06961                       if (exprNode_checkOneInit (newel, oneval))
06962                         {
06963                           hasError = TRUE;
06964                           nerrors++;
06965                           
06966                           if (nerrors > 3 && exprNodeList_size (vals) > 6)
06967                             {
06968                               llgenmsg 
06969                                 (message ("Additional initialization errors "
06970                                           "for %s not reported",
06971                                           exprNode_unparse (el)),
06972                                  exprNode_loc (el));
06973                               exprNode_freeIniter (newel);
06974                               break;
06975                             }
06976                           else
06977                             {
06978                               exprNode_freeIniter (newel);
06979                             }
06980                         }
06981                       else
06982                         {
06983                           exprNode_freeIniter (newel);
06984                         }
06985                     }
06986                 }
06987 
06988               cstring_free (istring);
06989               i++;
06990               /*@-branchstate@*/ 
06991             } end_exprNodeList_elements;
06992           /*@=branchstate@*/
06993         }
06994       else if (ctype_isStruct (ctype_realType (t1)))
06995         {
06996           uentryList fields = ctype_getFields (t1);
06997           int i = 0;
06998 
06999           if (uentryList_size (fields) != exprNodeList_size (vals))
07000             {
07001               if (uentryList_size (fields) > exprNodeList_size (vals))
07002                 {
07003                   hasError = optgenerror 
07004                     (FLG_FULLINITBLOCK,
07005                      message ("Initializer block for "
07006                               "%s has %d field%p, but %s has %d field%p: %q",
07007                               exprNode_unparse (el),
07008                               exprNodeList_size (vals),
07009                               ctype_unparse (t1),
07010                               uentryList_size (fields),
07011                               exprNodeList_unparse (vals)),
07012                      val->loc);   
07013                 }
07014               else
07015                 {
07016                   hasError = optgenerror 
07017                     (FLG_TYPE,
07018                      message ("Initializer block for "
07019                               "%s has %d field%p, but %s has %d field%p: %q",
07020                               exprNode_unparse (el),
07021                               exprNodeList_size (vals),
07022                               ctype_unparse (t1),
07023                               uentryList_size (fields),
07024                               exprNodeList_unparse (vals)),
07025                      val->loc);   
07026                 }
07027             }
07028           else
07029             {
07030               exprNodeList_elements (vals, oneval)
07031                 {
07032                   uentry thisfield = uentryList_getN (fields, i);
07033                   exprNode newel =
07034                     exprNode_fieldAccess (exprNode_fakeCopy (el),
07035                                           uentry_getName (thisfield));
07036 
07037                   if (exprNode_isDefined (newel))
07038                     {
07039                       if (exprNode_checkOneInit (newel, oneval))
07040                         {
07041                           hasError = TRUE;
07042                         }
07043 
07044                       exprNode_freeIniter (newel);
07045                     }
07046 
07047                   i++;
07048                 } end_exprNodeList_elements;
07049             }
07050         }
07051       else
07052         {
07053           hasError = optgenerror 
07054             (FLG_TYPE,
07055              message ("Initializer block used for "
07056                       "%s where %t is expected: %s",
07057                       exprNode_unparse (el), t1, exprNode_unparse (val)),
07058              val->loc);   
07059         }
07060     }
07061   else
07062     {
07063       if (exprNode_isDefined (val))
07064         {
07065           doAssign (el, val, TRUE);
07066           
07067           if (!exprNode_matchType (t1, val))
07068             {
07069               hasError = gentypeerror 
07070                 (t1, val, t2, el,
07071                  message ("Initial value of %s is type %t, "
07072                           "expects %t: %s",
07073                           exprNode_unparse (el),
07074                           t2, t1, exprNode_unparse (val)),
07075                  val->loc);
07076             }
07077         }
07078     }
07079 
07080   return hasError;
07081 }
07082 
07083 exprNode exprNode_makeInitialization (/*@only@*/ idDecl t,
07084                                       /*@only@*/ exprNode e)
07085 {
07086   uentry ue = usymtab_lookup (idDecl_observeId (t));
07087   bool isUsed = uentry_isUsed (ue);
07088   exprNode ret = exprNode_fromIdentifierAux (ue);
07089   ctype ct = ctype_realishType (ret->typ);
07090   fileloc loc;
07091   
07092   if (ctype_isUnknown (ct)) 
07093     {
07094       voptgenerror (FLG_IMPTYPE,
07095                     message ("Variable has unknown (implicitly int) type: %s",
07096                              idDecl_getName (t)),
07097                     exprNode_isDefined (e) ? exprNode_loc (e) : g_currentloc);
07098       
07099       ct = ctype_int;
07100     }
07101 
07102   if (exprNode_isError (e)) 
07103     {
07104       e = exprNode_createUnknown ();
07105       loc = g_currentloc;
07106 
07107       /* error: assume initializer is defined */
07108       sRef_setDefined (ret->sref, loc);
07109     }
07110   else
07111     {
07112       loc = exprNode_loc (e);
07113       
07114       /*
07115       ** evs - 9 Apr 1995
07116       **
07117       ** was addSafeUse --- what's the problem?
07118       **
07119       **   int x = 3, y = x ?
07120       */
07121 
07122       exprNode_checkUse (ret, e->sref, e->loc);
07123       
07124       if (ctype_isUnknown (e->typ) && uentry_isValid (ue))
07125         {
07126           exprNode lhs = exprNode_createId (ue);
07127 
07128           /*
07129           ** static storage should be undefined before initializing
07130           */
07131 
07132           if (uentry_isStatic (ue))
07133             {
07134               sRef_setDefState (lhs->sref, SS_PARTIAL, fileloc_undefined);
07135             }
07136 
07137           (void) exprNode_checkOneInit (lhs, e);
07138 
07139           if (uentry_isStatic (ue))
07140             {
07141               sRef_setDefState (lhs->sref, SS_DEFINED, fileloc_undefined);
07142             }
07143 
07144           exprNode_free (lhs);
07145         }
07146       else
07147         {
07148           if (!exprNode_matchType (ct, e))
07149             {
07150               if (exprNode_isZero (e) && ctype_isArrayPtr (ct)) 
07151                 {
07152                   ;
07153                 }
07154               else
07155                 {
07156                   (void) gentypeerror 
07157                     (exprNode_getType (e), e, exprNode_getType (ret), ret,
07158                      message 
07159                      ("Variable %s initialized to type %t, expects %t: %s",
07160                       exprNode_unparse (ret), exprNode_getType (e), 
07161                       exprNode_getType (ret),
07162                       exprNode_unparse (e)),
07163                      e->loc);
07164                 }
07165             }
07166         }
07167       
07168       if (uentry_isStatic (ue))
07169         {
07170           sRef_setDefState (ret->sref, SS_PARTIAL, fileloc_undefined);
07171         }
07172 
07173       doAssign (ret, e, TRUE);
07174 
07175       if (uentry_isStatic (ue))
07176         {
07177           sRef_setDefState (ret->sref, SS_DEFINED, fileloc_undefined);
07178         }
07179     }
07180 
07181   if (context_inIterDef ())
07182     {
07183       /* should check if it is yield */
07184       uentry_setUsed (ue, loc);
07185     }
07186   else
07187     {
07188       if (!isUsed) /* could be @unused@-qualified variable */
07189         {
07190           uentry_setNotUsed (ue);  
07191         }
07192     }
07193 
07194   ret->exitCode = XK_NEVERESCAPE;
07195   ret->mustBreak = FALSE;
07196 
07197   /*
07198   ** Must be before new kind is assigned!
07199   */
07200 
07201   exprData_free (ret->edata, ret->kind); 
07202 
07203   ret->kind = XPR_INIT;
07204   ret->edata = exprData_makeInit (t, e);
07205   exprNode_mergeUSs (ret, e);
07206   return ret;
07207 }
07208   
07209 exprNode exprNode_iter (/*@observer@*/ uentry name,
07210                         /*@only@*/ exprNodeList alist, 
07211                         /*@only@*/ exprNode body,
07212                         /*@observer@*/ uentry end)
07213 {
07214   exprNode ret;
07215   cstring iname;
07216 
07217   llassert (uentry_isValid (name));
07218 
07219   uentry_setUsed (name, exprNode_loc (body));
07220 
07221   ret = exprNode_createPartialCopy (body);
07222   iname = uentry_getName (name);
07223 
07224   if (uentry_isInvalid (end))
07225     {
07226       llerror (FLG_ITER,
07227                message ("Iter %s not balanced with end_%s", iname, iname));
07228     }
07229   else
07230     {
07231       cstring ename = uentry_getName (end);
07232 
07233       if (!cstring_equalPrefix (ename, "end_"))
07234         {
07235           llerror (FLG_ITER, message ("Iter %s not balanced with end_%s: %s", 
07236                                       iname, iname, ename));
07237         }
07238       else
07239         {
07240           if (!cstring_equal (iname, cstring_suffix (ename, 4)))
07241             {
07242               llerror (FLG_ITER, 
07243                        message ("Iter %s not balanced with end_%s: %s", 
07244                                 iname, iname, ename));
07245             }
07246         }
07247 
07248       cstring_free (ename);
07249     }
07250 
07251   context_exitIterClause (body);
07252   
07253   ret->kind = XPR_ITER;
07254   ret->edata = exprData_makeIter (name, alist, body, end);
07255 
07256   if (uentry_isIter (name))
07257     {
07258       (void) checkArgsReal (name, body, 
07259                             uentry_getParams (name), alist, TRUE, ret);
07260     }
07261 
07262   cstring_free (iname);
07263 
07264   return ret;
07265 }
07266 
07267 exprNode
07268 exprNode_iterNewId (/*@only@*/ cstring s)
07269 {
07270   exprNode e = exprNode_new ();
07271   uentry ue = uentryList_getN (uentry_getParams (getCurrentIter ()), iterParamNo ());
07272 
07273   llassert (processingIterVars ());
07274 
07275   e->loc = context_getSaveLocation ();
07276 
07277   if (fileloc_isUndefined (e->loc))
07278     {
07279       fileloc_free (e->loc);
07280       e->loc = fileloc_copy (g_currentloc);
07281     }
07282 
07283   e->uses = sRefSet_new ();
07284   e->sets = sRefSet_new ();
07285   e->msets = sRefSet_new ();
07286   e->kind = XPR_VAR;
07287   e->val = multiVal_unknown ();
07288   e->guards = guardSet_new ();
07289   e->sref = defref;
07290   e->isJumpPoint = FALSE;
07291   e->exitCode = XK_NEVERESCAPE;
07292 
07293   /*> missing fields, detected by lclint <*/
07294   e->canBreak = FALSE;
07295   e->mustBreak = FALSE;
07296   e->etext = cstring_undefined;
07297 
07298   if (uentry_isYield (ue))
07299     {
07300       uentry uue = uentry_makeVariable (s, uentry_getType (ue), 
07301                                         fileloc_copy (e->loc), 
07302                                         FALSE);
07303       sRef sr;
07304 
07305       uue = usymtab_supEntrySrefReturn (uue);
07306 
07307       sr = uentry_getSref (uue);
07308       sRef_mergeStateQuiet (sr, uentry_getSref (ue));
07309       sr = uentry_getSref (uue);
07310       sRef_setDefined (sr, e->loc);
07311 
07312       e->typ = uentry_getType (uue);      
07313       e->sref = sr;
07314       e->edata = exprData_makeId (uue);
07315       uentry_setUsed (uue, g_currentloc);
07316     }
07317   else
07318     {
07319       uentry uue;
07320 
07321       sRef_setGlobalScope ();
07322       uue = uentry_makeVariableLoc (s, ctype_unknown);
07323 
07324       e->typ = ctype_unknown;
07325       e->edata = exprData_makeId (uue);
07326 
07327       uentry_setUsed (uue, e->loc);
07328       uentry_setHasNameError (uue); 
07329 
07330       if (context_getFlag (FLG_REPEATUNRECOG))
07331         {
07332           uentry_markOwned (uue);
07333         }
07334       else
07335         {
07336           usymtab_supGlobalEntry (uue);      
07337         }
07338 
07339       sRef_clearGlobalScope ();
07340 
07341       voptgenerror (FLG_UNRECOG, message ("Unrecognized identifier: %s", s),
07342                     e->loc);
07343     }
07344 
07345 
07346   cstring_free (s);
07347   return (e);
07348 }
07349 
07350 exprNode
07351 exprNode_iterExpr (/*@returned@*/ exprNode e)
07352 {
07353   if (!processingIterVars ())
07354     {
07355       llcontbuglit ("checkIterParam: not in iter");
07356       return e;
07357     }
07358   
07359   if (uentry_isYield (uentryList_getN (uentry_getParams (getCurrentIter ()), 
07360                                        iterParamNo ())))
07361     {
07362       if (exprNode_isDefined (e))
07363         {
07364           if (fileloc_isDefined (e->loc))
07365             {
07366               voptgenerror
07367                 (FLG_ITER,
07368                  message ("Yield parameter is not simple identifier: %s", 
07369                           exprNode_unparse (e)),
07370                  e->loc);
07371             }
07372           else
07373             {
07374               voptgenerror
07375                 (FLG_ITER,
07376                  message ("Yield parameter is not simple identifier: %s",
07377                           exprNode_unparse (e)),
07378                  g_currentloc);
07379               
07380             }
07381         }
07382     }
07383   return e;
07384 }
07385 
07386 exprNode
07387 exprNode_iterId (/*@observer@*/ uentry c)
07388 {
07389   uentry ue;
07390 
07391   llassert (processingIterVars ());
07392 
07393   ue = uentryList_getN (uentry_getParams (getCurrentIter ()), 
07394                         iterParamNo ());
07395 
07396   if (uentry_isYield (ue))
07397     {
07398       ctype ct = uentry_getType (ue);
07399       exprNode e = exprNode_createPlain (ct);
07400       cstring name = uentry_getName (c);
07401       uentry le = uentry_makeVariable (name, ct, fileloc_undefined, FALSE);
07402 
07403       uentry_setUsed (ue, g_currentloc);
07404       uentry_setHasNameError (ue); 
07405       
07406       cstring_free (name);
07407       
07408       e->kind = XPR_VAR;
07409       e->edata = exprData_makeId (le);
07410       e->loc = context_getSaveLocation ();
07411       e->sref = uentry_getSref (le);
07412 
07413       usymtab_supEntrySref (le);
07414 
07415       if (!context_inHeader ())
07416         {
07417           if (optgenerror
07418               (FLG_ITER,
07419                message ("Yield parameter shadows local declaration: %q",
07420                         uentry_getName (c)),
07421                fileloc_isDefined (e->loc) ? e->loc : g_currentloc))
07422             {
07423               uentry_showWhereDeclared (c);
07424             }
07425         }
07426 
07427       return e;
07428     }
07429 
07430   return (exprNode_fromIdentifierAux (c));
07431 }
07432 
07433 exprNode exprNode_iterStart (/*@observer@*/ uentry name, /*@only@*/ exprNodeList alist)
07434 {
07435   exprNode ret = exprNode_create (ctype_unknown);
07436 
07437   ret->kind = XPR_ITERCALL;
07438   ret->edata = exprData_makeIterCall (name, alist);
07439   
07440   if (uentry_isIter (name))
07441     {
07442       uentryList params = uentry_getParams (name);
07443 
07444       if (context_inIterDef () 
07445           && uentryList_size (params) == exprNodeList_size (alist))
07446         {
07447           int i = 0;
07448           
07449           exprNodeList_elements (alist, arg)
07450             {
07451               uentry parg = uentryList_getN (params, i);
07452 
07453               if (uentry_isYield (parg))
07454                 {
07455                   uentry ue = exprNode_getUentry (arg);
07456 
07457                   if (uentry_isValid (ue))
07458                     {
07459                       ;
07460                     }
07461                 }
07462 
07463               i++;
07464             } end_exprNodeList_elements;
07465         }
07466 
07467       (void) checkArgsReal (name, ret, params, alist, TRUE, ret);
07468       checkUnspecCall (ret, params, alist);
07469     }
07470 
07471   return ret;
07472 }
07473 
07474 /*@exposed@*/ sRef exprNode_getSref (exprNode e)
07475 {
07476   if (exprNode_isDefined (e))
07477     {
07478       /*@access sRef@*/
07479       if (e->sref == defref) /*@noaccess sRef@*/
07480         {
07481           /*@-mods@*/
07482           e->sref = sRef_makeUnknown (); 
07483           sRef_setAliasKind (e->sref, AK_ERROR, fileloc_undefined);
07484           /*@=mods@*/
07485           return e->sref;
07486         }
07487       else
07488         {
07489           return e->sref;
07490         }
07491     }
07492   else
07493     {
07494       return sRef_undefined;
07495     }
07496 }
07497 
07498 /*@observer@*/ cstring
07499 exprNode_unparseFirst (exprNode e)
07500 {
07501   if (exprNode_isDefined (e))
07502     {
07503       cstring ret;
07504 
07505       if (e->kind == XPR_STMTLIST
07506           || e->kind == XPR_COMMA || e->kind == XPR_COND)
07507         {
07508           exprNode first = exprData_getPairA (e->edata);
07509 
07510           if (exprNode_isDefined (first))
07511             {
07512               return (exprNode_unparseFirst (exprData_getPairA (e->edata)));
07513             }
07514           else
07515             {
07516               return (cstring_makeLiteralTemp ("..."));
07517             }
07518         }
07519 
07520       ret = cstring_elide (exprNode_unparse (e), 20);
07521       cstring_markOwned (ret);
07522       
07523       return (ret);
07524     }
07525   else
07526     {
07527       return cstring_makeLiteralTemp ("<error>");
07528     }
07529 }
07530 
07531 /*@observer@*/ cstring
07532 exprNode_unparse (exprNode e)
07533 {
07534   if (exprNode_isError (e))
07535     {
07536       return cstring_makeLiteralTemp ("<error>");
07537     }
07538 
07539   if (cstring_isDefined (e->etext))
07540     {
07541       return e->etext;
07542     }
07543   else
07544     {
07545       cstring ret = exprNode_doUnparse (e);
07546 
07547       /*@-modifies@*/ /* benevolent */
07548       e->etext = ret; 
07549       /*@=modifies@*/
07550       return ret;
07551     }
07552 }
07553 
07554 /*@observer@*/ fileloc
07555 exprNode_loc (exprNode e)
07556 {
07557   if (exprNode_isError (e))
07558     {
07559       return (g_currentloc);
07560     }
07561   else
07562     {
07563       return (e->loc);
07564     }
07565 }
07566 
07567 /*
07568 ** executes exprNode e
07569 **    recursively rexecutes as though in original parse using
07570 **    information in e->edata
07571 */
07572 
07573 static /*@only@*/ exprNodeList exprNodeList_effect (exprNodeList e)
07574 {
07575   exprNodeList ret = exprNodeList_new ();
07576 
07577   exprNodeList_elements (e, current)
07578     {
07579       exprNodeList_addh (ret, exprNode_effect (current));
07580     } end_exprNodeList_elements;
07581 
07582   return ret;
07583 }
07584 
07585 static /*@only@*/ exprNode exprNode_effect (exprNode e) 
07586    /*@globals internalState@*/
07587 {
07588   bool innerEffect = inEffect;
07589   exprNode ret;
07590   exprData data;
07591 
07592   inEffect = TRUE;
07593 
07594   context_clearJustPopped ();
07595 
07596   if (exprNode_isError (e))
07597     {
07598       ret = exprNode_undefined;
07599     }
07600   else
07601     {
07602       /*
07603       ** Turn off expose and dependent transfer checking.
07604       ** Need to pass exposed internal nodes,
07605       ** [ copying would be a waste! ]
07606       ** [ Actually, I think I wasted a lot more time than its worth ]
07607       ** [ trying to do this. ]
07608       */
07609 
07610       /*@-exposetrans@*/
07611       /*@-observertrans@*/
07612       /*@-dependenttrans@*/
07613       
07614       data = e->edata;
07615       
07616       switch (e->kind)
07617         {
07618         case XPR_PARENS: 
07619           ret = exprNode_addParens (exprData_getUopTok (data), 
07620                                     exprNode_effect (exprData_getUopNode (data)));
07621           break;
07622         case XPR_ASSIGN:
07623           ret = exprNode_assign (exprNode_effect (exprData_getOpA (data)), 
07624                                  exprNode_effect (exprData_getOpB (data)), 
07625                                  exprData_getOpTok (data));
07626           break;
07627         case XPR_INITBLOCK:
07628           ret = exprNode_undefined;
07629           break;
07630         case XPR_CALL:
07631           ret = exprNode_functionCall (exprNode_effect (exprData_getFcn (data)),
07632                                        exprNodeList_effect (exprData_getArgs (data)));
07633           break;
07634         case XPR_EMPTY:
07635           ret = e;
07636           break;
07637 
07638         case XPR_LABEL:
07639           ret = e;
07640           break;
07641 
07642         case XPR_CONST:
07643         case XPR_VAR:
07644           {
07645             cstring id = exprData_getId (data);
07646             uentry ue = usymtab_lookupSafe (id);
07647 
07648             ret = exprNode_fromIdentifierAux (ue);
07649             ret->loc = fileloc_update (ret->loc, e->loc);
07650             break;
07651           }
07652         case XPR_BODY:
07653           ret = e;
07654           break;
07655         case XPR_FETCH:
07656           ret = exprNode_arrayFetch (exprNode_effect (exprData_getPairA (data)), 
07657                                      exprNode_effect (exprData_getPairB (data)));
07658           break;
07659         case XPR_OP:
07660           ret = exprNode_op (exprNode_effect (exprData_getOpA (data)), 
07661                              exprNode_effect (exprData_getOpB (data)), 
07662                              exprData_getOpTok (data));
07663           break;
07664           
07665         case XPR_POSTOP:
07666           ret = exprNode_postOp (exprNode_effect (exprData_getUopNode (data)), 
07667                                  exprData_getUopTok (data));
07668           break;
07669         case XPR_PREOP:
07670           ret = exprNode_preOp (exprNode_effect (exprData_getUopNode (data)), 
07671                                 exprData_getUopTok (data));
07672           break;
07673 
07674         case XPR_OFFSETOF:
07675         case XPR_SIZEOFT:
07676         case XPR_SIZEOF:
07677         case XPR_ALIGNOFT:
07678         case XPR_ALIGNOF:
07679           ret = e;
07680           break;
07681           
07682         case XPR_VAARG:
07683           ret = exprNode_vaArg (exprData_getCastTok (data),
07684                                 exprNode_effect (exprData_getCastNode (data)),
07685                                 exprData_getCastType (data));
07686           break;
07687           
07688         case XPR_CAST:
07689           ret = exprNode_cast (exprData_getCastTok (data), 
07690                                exprNode_effect (exprData_getCastNode (data)), 
07691                                exprData_getCastType (data));
07692           break;
07693         case XPR_ITERCALL:
07694           ret = exprNode_iterStart (exprData_getIterCallIter (data),
07695                                     exprNodeList_effect 
07696                                     (exprData_getIterCallArgs (data)));
07697           break;
07698           
07699         case XPR_ITER:
07700           ret = exprNode_iter (exprData_getIterSname (data),
07701                                exprNodeList_effect (exprData_getIterAlist (data)),
07702                                exprNode_effect (exprData_getIterBody (data)),
07703                                exprData_getIterEname (data));
07704           break;
07705           
07706         case XPR_FOR:
07707           ret = exprNode_for (exprNode_effect (exprData_getPairA (data)), 
07708                               exprNode_effect (exprData_getPairB (data)));
07709           break;
07710           
07711         case XPR_FORPRED:
07712           ret = exprNode_forPred (exprNode_effect (exprData_getTripleInit (data)),
07713                                   exprNode_effect (exprData_getTripleTest (data)),
07714                                   exprNode_effect (exprData_getTripleInc (data)));
07715           break;
07716           
07717         case XPR_TOK:
07718           ret = exprNode_createTok (exprData_getTok (data));
07719           break;
07720           
07721         case XPR_GOTO:
07722           ret = exprNode_goto (exprData_getLiteral (data));
07723           ret->loc = fileloc_update (ret->loc, e->loc);
07724           break;
07725           
07726         case XPR_CONTINUE:
07727           ret = exprNode_continue (exprData_getTok (data), QSAFEBREAK);
07728           break;
07729           
07730         case XPR_BREAK:
07731           ret = exprNode_break (exprData_getTok (data), QSAFEBREAK);
07732           break;
07733           
07734         case XPR_RETURN:
07735           ret = exprNode_return (exprNode_effect (exprData_getSingle (data)));
07736           break;
07737           
07738         case XPR_NULLRETURN:
07739           ret = exprNode_nullReturn (exprData_getTok (data));
07740           break;
07741           
07742         case XPR_COMMA:
07743           ret = exprNode_comma (exprNode_effect (exprData_getPairA (data)),
07744                                 exprNode_effect (exprData_getPairB (data)));
07745           break;
07746           
07747         case XPR_COND:
07748           ret = exprNode_cond (exprNode_effect (exprData_getTriplePred (data)),
07749                                exprNode_effect (exprData_getTripleTrue (data)),
07750                                exprNode_effect (exprData_getTripleFalse (data)));
07751           break;
07752         case XPR_IF:
07753           ret = exprNode_if (exprNode_effect (exprData_getPairA (data)),
07754                              exprNode_effect (exprData_getPairB (data)));
07755           break;
07756           
07757         case XPR_IFELSE:
07758           ret = exprNode_ifelse (exprNode_effect (exprData_getTriplePred (data)),
07759                                  exprNode_effect (exprData_getTripleTrue (data)),
07760                                  exprNode_effect (exprData_getTripleFalse (data)));
07761           break;
07762         case XPR_WHILEPRED:
07763           ret = exprNode_whilePred (exprData_getSingle (data));
07764           break;
07765           
07766         case XPR_WHILE:
07767           ret = exprNode_while (exprNode_effect (exprData_getPairA (data)),
07768                                 exprNode_effect (exprData_getPairB (data)));
07769           break;
07770           
07771         case XPR_DOWHILE:
07772           ret = exprNode_doWhile (exprNode_effect (exprData_getPairA (data)),
07773                                   exprNode_effect (exprData_getPairB (data)));
07774           break;
07775 
07776         case XPR_BLOCK:
07777           ret = exprNode_makeBlock (exprNode_effect (exprData_getSingle (data)));
07778           break;          
07779 
07780         case XPR_STMT:
07781           ret = exprNode_statement (exprNode_effect (exprData_getSingle (data)));
07782           break;
07783           
07784         case XPR_STMTLIST:
07785           ret = exprNode_concat (exprNode_effect (exprData_getPairA (data)),
07786                                  exprNode_effect (exprData_getPairB (data)));
07787           break;
07788           
07789         case XPR_FTCASE:
07790         case XPR_CASE:
07791           ret = exprNode_caseMarker 
07792             (exprNode_effect (exprData_getSingle (data)),
07793              TRUE);
07794           break;
07795           
07796         case XPR_FTDEFAULT:
07797         case XPR_DEFAULT:
07798           ret = exprNode_createTok (exprData_getTok (data));
07799           break;
07800           
07801         case XPR_SWITCH:
07802           ret = exprNode_switch (exprNode_effect (exprData_getPairA (data)),
07803                                  exprNode_effect (exprData_getPairB (data)));
07804           break;
07805           
07806         case XPR_INIT:
07807           ret = exprNode_makeInitialization
07808             (exprData_getInitId (data),
07809              exprNode_effect (exprData_getInitNode (data)));
07810           break;
07811           
07812         case XPR_FACCESS:
07813           ret = exprNode_fieldAccess (exprNode_effect (exprData_getFieldNode (data)),
07814                                       cstring_copy (exprData_getFieldName (data)));
07815           break;
07816           
07817         case XPR_ARROW:
07818           ret = exprNode_arrowAccess (exprNode_effect (exprData_getFieldNode (data)),
07819                                       cstring_copy (exprData_getFieldName (data)));
07820           break;
07821           
07822         case XPR_STRINGLITERAL:
07823           ret = e;
07824           break;
07825           
07826         case XPR_NUMLIT:
07827           ret = e;
07828           break;
07829 
07830         case XPR_NODE:
07831           ret = e;
07832           break;
07833           /*@-branchstate@*/ 
07834         } 
07835       /*@=branchstate@*/
07836       /*@=observertrans@*/
07837       /*@=exposetrans@*/
07838       /*@=dependenttrans@*/
07839     }
07840 
07841   if (!innerEffect) 
07842     {
07843       inEffect = FALSE;
07844     }
07845 
07846   return ret;
07847 }
07848 
07849 static /*@observer@*/ cstring exprNode_rootVarName (exprNode e)
07850 {
07851   cstring ret;
07852   exprData data;
07853 
07854   if (exprNode_isError (e))
07855     {
07856       return cstring_undefined;
07857     }
07858 
07859   data = e->edata;
07860 
07861   switch (e->kind)
07862     {
07863     case XPR_PARENS: 
07864       ret = exprNode_rootVarName (exprData_getUopNode (data));
07865       break;
07866     case XPR_ASSIGN:
07867       ret = exprNode_rootVarName (exprData_getOpA (data));
07868       break;
07869     case XPR_CONST:
07870     case XPR_VAR:
07871       ret = exprData_getId (data);
07872       break;
07873     case XPR_LABEL:
07874     case XPR_TOK:
07875     case XPR_ITERCALL:
07876     case XPR_EMPTY:
07877     case XPR_CALL:
07878     case XPR_INITBLOCK:
07879     case XPR_BODY:
07880     case XPR_FETCH:
07881     case XPR_OP:
07882     case XPR_POSTOP:
07883     case XPR_PREOP:
07884     case XPR_OFFSETOF:
07885     case XPR_ALIGNOFT:
07886     case XPR_ALIGNOF:
07887     case XPR_SIZEOFT:
07888     case XPR_SIZEOF:
07889     case XPR_VAARG:
07890     case XPR_CAST:
07891     case XPR_ITER:
07892     case XPR_FOR:
07893     case XPR_FORPRED:
07894     case XPR_BREAK:
07895     case XPR_RETURN:
07896     case XPR_NULLRETURN:
07897     case XPR_COMMA:
07898     case XPR_COND:
07899     case XPR_IF:
07900     case XPR_IFELSE:
07901     case XPR_WHILE:
07902     case XPR_WHILEPRED:
07903     case XPR_DOWHILE:
07904     case XPR_GOTO:
07905     case XPR_CONTINUE:
07906     case XPR_FTDEFAULT:
07907     case XPR_DEFAULT:
07908     case XPR_SWITCH:
07909     case XPR_FTCASE:
07910     case XPR_CASE:
07911     case XPR_BLOCK:
07912     case XPR_STMT:
07913     case XPR_STMTLIST:
07914     case XPR_INIT:
07915     case XPR_FACCESS:
07916     case XPR_ARROW:
07917     case XPR_NODE:
07918     case XPR_NUMLIT:
07919     case XPR_STRINGLITERAL:
07920       ret = cstring_undefined;
07921       break;
07922     }
07923 
07924   return ret;
07925 }
07926 
07927 static /*@only@*/ cstring exprNode_doUnparse (exprNode e)
07928 {
07929   cstring ret;
07930   exprData data;
07931 
07932   if (exprNode_isError (e))
07933     {
07934       static /*@only@*/ cstring error = cstring_undefined;
07935 
07936       if (!cstring_isDefined (error))
07937         {
07938           error = cstring_makeLiteral ("<error>");
07939         }
07940       
07941       return error;
07942     }
07943 
07944   data = e->edata;
07945 
07946   switch (e->kind)
07947     {
07948     case XPR_PARENS: 
07949       ret = message ("(%s)", exprNode_unparse (exprData_getUopNode (e->edata)));
07950       break;
07951     case XPR_ASSIGN:
07952       ret = message ("%s %s %s",
07953                      exprNode_unparse (exprData_getOpA (data)), 
07954                      lltok_unparse (exprData_getOpTok (data)),
07955                      exprNode_unparse (exprData_getOpB (data)));
07956       break;
07957     case XPR_CALL:
07958       ret = message ("%s(%q)",
07959                      exprNode_unparse (exprData_getFcn (data)), 
07960                      exprNodeList_unparse (exprData_getArgs (data)));
07961       break;
07962     case XPR_INITBLOCK:
07963       ret = message ("{ %q }", exprNodeList_unparse (exprData_getArgs (data)));
07964       break;
07965     case XPR_EMPTY:
07966       ret = cstring_undefined;
07967       break;
07968     case XPR_LABEL:
07969       ret = message ("%s:", exprData_getId (data));
07970       break;
07971     case XPR_CONST:
07972     case XPR_VAR:
07973       ret = cstring_copy (exprData_getId (data));
07974       break;
07975     case XPR_FETCH:
07976       ret = message ("%s[%s]", exprNode_unparse (exprData_getPairA (data)),
07977                      exprNode_unparse (exprData_getPairB (data)));
07978       break;
07979     case XPR_BODY:
07980       ret = message ("<body>");
07981       break;
07982     case XPR_OP:
07983       ret = message ("%s %s %s",
07984                      exprNode_unparse (exprData_getOpA (data)), 
07985                      lltok_unparse (exprData_getOpTok (data)),
07986                      exprNode_unparse (exprData_getOpB (data))); 
07987       break;
07988       
07989     case XPR_PREOP: 
07990       ret = message ("%s%s",
07991                      lltok_unparse (exprData_getUopTok (data)),
07992                      exprNode_unparse (exprData_getUopNode (data))); 
07993       break;
07994 
07995     case XPR_POSTOP:
07996       ret = message ("%s%s",
07997                      exprNode_unparse (exprData_getUopNode (data)),
07998                      lltok_unparse (exprData_getUopTok (data))); 
07999       break;
08000       
08001     case XPR_OFFSETOF:
08002       ret = message ("offsetof(%s,%q)", 
08003                      ctype_unparse (qtype_getType (exprData_getOffsetType (data))),
08004                      cstringList_unparseSep (exprData_getOffsetName (data), cstring_makeLiteralTemp (".")));
08005       break;
08006 
08007     case XPR_SIZEOFT:
08008       ret = message ("sizeof(%s)", ctype_unparse (qtype_getType (exprData_getType (data))));
08009       break;
08010       
08011     case XPR_SIZEOF:
08012       ret = message ("sizeof(%s)", exprNode_unparse (exprData_getSingle (data)));
08013       break;
08014 
08015     case XPR_ALIGNOFT:
08016       ret = message ("alignof(%s)", ctype_unparse (qtype_getType (exprData_getType (data))));
08017       break;
08018       
08019     case XPR_ALIGNOF:
08020       ret = message ("alignof(%s)", exprNode_unparse (exprData_getSingle (data)));
08021       break;
08022       
08023     case XPR_VAARG:
08024       ret = message ("va_arg(%s, %q)", 
08025                      exprNode_unparse (exprData_getCastNode (data)),
08026                      qtype_unparse (exprData_getCastType (data)));
08027       break;
08028       
08029     case XPR_ITERCALL:
08030       ret = message ("%q(%q)", 
08031                      uentry_getName (exprData_getIterCallIter (data)),
08032                      exprNodeList_unparse (exprData_getIterCallArgs (data)));
08033       break;
08034     case XPR_ITER:
08035       ret = message ("%q(%q) %s %q",
08036                      uentry_getName (exprData_getIterSname (data)),
08037                      exprNodeList_unparse (exprData_getIterAlist (data)),
08038                      exprNode_unparse (exprData_getIterBody (data)),
08039                      uentry_getName (exprData_getIterEname (data)));
08040       break;
08041     case XPR_CAST:
08042       ret = message ("(%q)%s", 
08043                      qtype_unparse (exprData_getCastType (data)),
08044                      exprNode_unparse (exprData_getCastNode (data)));
08045       break;
08046       
08047     case XPR_FOR:
08048       ret = message ("%s %s", 
08049                      exprNode_unparse (exprData_getPairA (data)), 
08050                      exprNode_unparse (exprData_getPairB (data)));
08051       break;
08052 
08053     case XPR_FORPRED:
08054             ret = message ("for (%s; %s; %s)",
08055                      exprNode_unparse (exprData_getTripleInit (data)),
08056                      exprNode_unparse (exprData_getTripleTest (data)),
08057                      exprNode_unparse (exprData_getTripleInc (data)));
08058       break;
08059       
08060     case XPR_GOTO:
08061       ret = message ("goto %s", exprData_getLiteral (data));
08062       break;
08063 
08064     case XPR_CONTINUE:
08065       ret = cstring_makeLiteral ("continue");
08066       break;
08067 
08068     case XPR_BREAK:
08069       ret = cstring_makeLiteral ("break");
08070       break;
08071 
08072     case XPR_RETURN:
08073       ret = message ("return %s", exprNode_unparse (exprData_getSingle (data)));
08074       break;
08075 
08076     case XPR_NULLRETURN:
08077       ret = cstring_makeLiteral ("return");
08078       break;
08079 
08080     case XPR_COMMA:
08081       ret = message ("%s, %s", 
08082                      exprNode_unparse (exprData_getPairA (data)),
08083                      exprNode_unparse (exprData_getPairB (data)));
08084       break;
08085       
08086     case XPR_COND:
08087       ret = message ("%s ? %s : %s",
08088                      exprNode_unparse (exprData_getTriplePred (data)),
08089                      exprNode_unparse (exprData_getTripleTrue (data)),
08090                      exprNode_unparse (exprData_getTripleFalse (data)));
08091       break;
08092     case XPR_IF:
08093       ret = message ("if (%s) %s", 
08094                      exprNode_unparse (exprData_getPairA (data)),
08095                      exprNode_unparse (exprData_getPairB (data)));
08096       break;
08097       
08098     case XPR_IFELSE:
08099       ret = message ("if (%s) %s else %s",
08100                      exprNode_unparse (exprData_getTriplePred (data)),
08101                      exprNode_unparse (exprData_getTripleTrue (data)),
08102                      exprNode_unparse (exprData_getTripleFalse (data)));
08103       break;
08104     case XPR_WHILE:
08105       ret = message ("while (%s) %s",
08106                      exprNode_unparse (exprData_getPairA (data)),
08107                      exprNode_unparse (exprData_getPairB (data)));
08108       break;
08109 
08110     case XPR_WHILEPRED:
08111       ret = cstring_copy (exprNode_unparse (exprData_getSingle (data)));
08112       break;
08113 
08114     case XPR_TOK:
08115       ret = cstring_copy (lltok_unparse (exprData_getTok (data)));
08116       break;
08117 
08118     case XPR_DOWHILE:
08119       ret = message ("do { %s } while (%s)",
08120                      exprNode_unparse (exprData_getPairB (data)),
08121                      exprNode_unparse (exprData_getPairA (data)));
08122       break;
08123       
08124     case XPR_BLOCK:
08125       ret = message ("{ %s }", exprNode_unparseFirst (exprData_getSingle (data)));
08126       break;
08127 
08128     case XPR_STMT:
08129       ret = cstring_copy (exprNode_unparse (exprData_getSingle (data)));
08130       break;
08131 
08132     case XPR_STMTLIST:
08133       ret = message ("%s; %s", 
08134                      exprNode_unparse (exprData_getPairA (data)),
08135                      exprNode_unparse (exprData_getPairB (data)));
08136       break;
08137       
08138     case XPR_FTDEFAULT:
08139     case XPR_DEFAULT:
08140       ret = cstring_makeLiteral ("default:");
08141       break;
08142 
08143     case XPR_SWITCH:
08144       ret = message ("switch (%s) %s", 
08145                      exprNode_unparse (exprData_getPairA (data)),
08146                      exprNode_unparse (exprData_getPairB (data)));
08147       break;
08148 
08149     case XPR_FTCASE:
08150     case XPR_CASE:
08151       ret = message ("case %s:", 
08152                      exprNode_unparse (exprData_getSingle (data)));
08153       break;
08154       
08155     case XPR_INIT:
08156       ret = message ("%s = %s",
08157                      idDecl_getName (exprData_getInitId (data)),
08158                      exprNode_unparse (exprData_getInitNode (data)));
08159       break;
08160       
08161     case XPR_FACCESS:
08162       ret = message ("%s.%s",
08163                      exprNode_unparse (exprData_getFieldNode (data)),
08164                      exprData_getFieldName (data));
08165       break;
08166       
08167     case XPR_ARROW:
08168             ret = message ("%s->%s",
08169                      exprNode_unparse (exprData_getFieldNode (data)),
08170                      exprData_getFieldName (data));
08171       break;
08172 
08173     case XPR_STRINGLITERAL:
08174       ret = cstring_copy (exprData_getLiteral (data));
08175       break;
08176 
08177     case XPR_NUMLIT:
08178       ret = cstring_copy (exprData_getLiteral (data));
08179       break;
08180 
08181     case XPR_NODE:
08182       ret = cstring_makeLiteral ("<node>");
08183       break;
08184     }
08185 
08186   return ret;
08187 }
08188 
08189 bool 
08190 exprNode_isCharLit (exprNode e)
08191 {
08192   if (exprNode_isDefined (e))
08193     {
08194       return (multiVal_isChar (exprNode_getValue (e)));
08195     }
08196   else
08197     {
08198       return FALSE;
08199     }
08200 }
08201 
08202 bool
08203 exprNode_isNumLit (exprNode e)
08204 {
08205   if (exprNode_isDefined (e))
08206     {
08207       return (multiVal_isInt (exprNode_getValue (e)));
08208     }
08209   else
08210     {
08211       return FALSE;
08212     }
08213 }
08214 
08215 static bool
08216 exprNode_isFalseConstant (exprNode e)
08217 {
08218   if (exprNode_isDefined (e))
08219     {
08220       cstring s = exprNode_rootVarName (e);
08221 
08222       if (cstring_equal (s, context_getFalseName ()))
08223         {
08224           return TRUE;
08225         }
08226     }
08227 
08228   return FALSE;
08229 }
08230 
08231 bool
08232 exprNode_matchLiteral (ctype expected, exprNode e)
08233 {
08234   if (exprNode_isDefined (e))
08235     {
08236       multiVal m = exprNode_getValue (e);
08237       
08238       if (multiVal_isDefined (m))
08239         {
08240           if (multiVal_isInt (m))
08241             {
08242               long int val = multiVal_forceInt (m);
08243               
08244               if (ctype_isDirectBool (ctype_realishType (expected)))
08245                 {
08246                   if (val == 0) 
08247                     {
08248                       return FALSE; /* really?! return TRUE; allow use of 0 for FALSE */
08249                     }
08250                   else 
08251                     {
08252                       return FALSE;
08253                     }
08254                 }
08255               
08256               if (ctype_isRealInt (expected))
08257                 {
08258                   /*
08259                   ** unsigned <- [ constant >= 0 is okay ]
08260                   */
08261                   
08262                   if (ctype_isUnsigned (expected))
08263                     {
08264                       if (val < 0)
08265                         {
08266                           return FALSE;
08267                         }
08268                     }
08269                   
08270                   /*
08271                   ** No checks on sizes of integers...maybe add
08272                   ** these later.
08273                   */
08274 
08275                   DPRINTF (("Here: %s => %s", exprNode_unparse (e), ctype_unparse (expected)));
08276                   DPRINTF (("Type: %s / %s", ctype_unparse (exprNode_getType (e)),
08277                             bool_unparse (ctype_isInt (exprNode_getType (e)))));
08278 
08279                   if (context_getFlag (FLG_NUMLITERAL) 
08280                       && (ctype_isRegularInt (exprNode_getType (e)) || val == 0)) {
08281                     return TRUE;
08282                   } else {
08283                     if (val == 0) {
08284                       return TRUE;
08285                     } else {
08286                       return FALSE; /* evs 2000-05-17: previously, always returned TRUE */
08287                     }
08288                   }
08289                 }
08290               else if (ctype_isChar (expected))
08291                 {
08292                   return FALSE;
08293                 }
08294               else if (ctype_isArrayPtr (expected))
08295                 {
08296                   return (val == 0);
08297                 }
08298               else if (ctype_isAnyFloat (expected))
08299                 {
08300                   return (context_getFlag (FLG_NUMLITERAL));
08301                 }
08302               else
08303                 {
08304                   return FALSE;
08305                 }
08306             }
08307           else if (multiVal_isDouble (m))
08308             {
08309               if (ctype_isAnyFloat (expected))
08310                 {
08311                   return TRUE;
08312                 }
08313             }
08314           else if (multiVal_isChar (m))
08315             {
08316               char val = multiVal_forceChar (m);          
08317               
08318               if (ctype_isChar (expected))
08319                 {
08320                   if (ctype_isUnsigned (expected) && ((int)val) < 0)
08321                     {
08322                       return FALSE;
08323                     }
08324                   else
08325                     {
08326                       return TRUE;
08327                     }
08328                 }
08329             }
08330           else
08331             {
08332               return FALSE;
08333             }
08334         }
08335     }
08336   
08337   return FALSE;
08338 }
08339 
08340 bool
08341 exprNode_matchType (ctype expected, exprNode e)
08342 {
08343   ctype actual;
08344   
08345   if (!exprNode_isDefined (e)) return TRUE;
08346 
08347   actual = ctype_realishType (exprNode_getType (e));
08348 
08349   if (ctype_match (ctype_realishType (expected), actual))
08350     {
08351       return TRUE;
08352     }
08353 
08354   llassert (!exprNode_isError (e));
08355   return (exprNode_matchLiteral (expected, e));
08356 }
08357 
08358 static bool
08359 exprNode_matchTypes (exprNode e1, exprNode e2)
08360 {
08361   ctype t1;
08362   ctype t2;
08363  
08364   if (!exprNode_isDefined (e1)) return TRUE;
08365   if (!exprNode_isDefined (e2)) return TRUE;
08366 
08367   /*
08368   ** realish type --- keep bools, bools 
08369   */ 
08370 
08371   t1 = ctype_realishType (exprNode_getType (e1));
08372   t2 = ctype_realishType (exprNode_getType (e2));
08373 
08374   if (ctype_match (t1, t2)) 
08375     {
08376       return TRUE;
08377     }
08378 
08379   return (exprNode_matchLiteral (t1, e2) || exprNode_matchLiteral (t2, e1));
08380 }
08381 
08382 /*
08383 ** pass e as ct
08384 */
08385 
08386 static bool
08387   exprNode_matchArgType (ctype ct, exprNode e)
08388 {
08389   ctype et;
08390 
08391   if (!exprNode_isDefined (e))
08392     {
08393       return TRUE;
08394     }
08395 
08396   et = ctype_realType (exprNode_getType (e));
08397 
08398   if (ctype_matchArg (ct, et)) return TRUE;
08399   
08400   llassert (!exprNode_isError (e));
08401   return (exprNode_matchLiteral (ct, e));
08402 }
08403 
08404 static /*@only@*/ exprNodeSList
08405   exprNode_flatten (/*@dependent@*/ exprNode e) /*@*/
08406 {
08407   if (exprNode_isDefined (e))
08408     {
08409       if (e->kind == XPR_STMTLIST)
08410         {
08411           return (exprNodeSList_append
08412                   (exprNode_flatten (exprData_getPairA (e->edata)),
08413                    exprNode_flatten (exprData_getPairB (e->edata))));
08414         }
08415       else if (e->kind == XPR_BLOCK)
08416         {
08417           return (exprNode_flatten (exprData_getSingle (e->edata)));
08418         }
08419       else
08420         {
08421           return (exprNodeSList_singleton (e));
08422         }
08423     }
08424 
08425   return exprNodeSList_new ();
08426 }
08427 
08428 static /*@exposed@*/ exprNode
08429 exprNode_lastStatement (/*@returned@*/ exprNode e)
08430 {
08431   if (exprNode_isDefined (e))
08432     {
08433       if (e->kind == XPR_STMTLIST)
08434         {
08435           exprNode b = exprData_getPairB (e->edata);
08436 
08437           if (exprNode_isDefined (b))
08438             {
08439               return exprNode_lastStatement (b);
08440             }
08441           else
08442             {
08443               return exprNode_lastStatement (exprData_getPairA (e->edata));
08444             }
08445         }
08446       else if (e->kind == XPR_BLOCK)
08447         {
08448           return (exprNode_lastStatement (exprData_getSingle (e->edata)));
08449         }
08450       else
08451         {
08452           return (e);
08453         }
08454     }
08455 
08456   return exprNode_undefined;
08457 }
08458 
08459 static /*@exposed@*/ exprNode
08460 exprNode_firstStatement (/*@returned@*/ exprNode e)
08461 {
08462   if (exprNode_isDefined (e))
08463     {
08464       if (e->kind == XPR_STMTLIST)
08465         {
08466           exprNode b = exprData_getPairA (e->edata);
08467 
08468           if (exprNode_isDefined (b))
08469             {
08470               return exprNode_firstStatement (b);
08471             }
08472           else
08473             {
08474               return exprNode_firstStatement (exprData_getPairB (e->edata));
08475             }
08476         }
08477       else if (e->kind == XPR_BLOCK)
08478         {
08479           return (exprNode_firstStatement (exprData_getSingle (e->edata)));
08480         }
08481       else
08482         {
08483           return (e);
08484         }
08485     }
08486 
08487   return exprNode_undefined;
08488 }
08489   
08490 static void
08491 exprNode_mergeUSs (exprNode res, exprNode other)
08492 {
08493   if (exprNode_isDefined (res) && exprNode_isDefined (other))
08494     {
08495       res->msets = sRefSet_union (res->msets, other->msets);
08496       res->sets = sRefSet_union (res->sets, other->sets);
08497       res->uses = sRefSet_union (res->uses, other->uses);
08498     }
08499 }
08500 
08501 static void
08502 exprNode_mergeCondUSs (exprNode res, exprNode other1, exprNode other2)
08503 {
08504   if (exprNode_isDefined (res))
08505     {
08506       if (exprNode_isDefined (other1))
08507         {
08508           res->sets = sRefSet_union (res->sets, other1->sets);
08509           res->msets = sRefSet_union (res->msets, other1->msets);
08510           res->uses = sRefSet_union (res->uses, other1->uses);
08511         }
08512       if (exprNode_isDefined (other2))
08513         {
08514           res->sets = sRefSet_union (res->sets, other2->sets);
08515           res->msets = sRefSet_union (res->msets, other2->msets);
08516           res->uses = sRefSet_union (res->uses, other2->uses);
08517         }
08518     }
08519 }
08520 
08521 /*
08522 ** modifies e->uses
08523 **
08524 ** Reports errors is s is not defined.
08525 */
08526 
08527 static void
08528 exprNode_addUse (exprNode e, sRef s)
08529 {
08530   if (exprNode_isDefined (e))
08531     {
08532       e->uses = sRefSet_insert (e->uses, s);
08533     }
08534 }
08535   
08536 void
08537 exprNode_checkUse (exprNode e, sRef s, fileloc loc)
08538 {
08539   if (sRef_isKnown (s) && !sRef_isConst (s))
08540     {
08541       /*
08542       ** need to check all outer types are useable
08543       */
08544 
08545       DPRINTF (("Check use: %s / %s",
08546                 exprNode_unparse (e), sRef_unparse (s)));
08547 
08548       exprNode_addUse (e, s);
08549      
08550       if (!context_inProtectVars ())
08551         {
08552           /*
08553           ** only report the deepest error
08554           */
08555           
08556           sRef errorRef = sRef_undefined;
08557           sRef lastRef  = sRef_undefined;
08558           bool deadRef = FALSE;
08559           bool unuseable = FALSE;
08560           bool errorMaybe = FALSE;
08561           
08562           while (sRef_isValid (s) && sRef_isKnown (s))
08563             {
08564               ynm readable = sRef_isReadable (s);
08565 
08566               if (!(ynm_toBoolStrict (readable)))
08567                 {
08568                   if (ynm_isMaybe (readable))
08569                     {
08570                       lastRef = errorRef;
08571                       errorRef = s;
08572                       deadRef = sRef_isPossiblyDead (errorRef);
08573                       unuseable = sRef_isUnuseable (errorRef);
08574                       errorMaybe = TRUE;
08575                     }
08576                   else
08577                     {
08578                       lastRef = errorRef;
08579                       errorRef = s;
08580                       deadRef = sRef_isDead (errorRef);
08581                       unuseable = sRef_isUnuseable (errorRef);
08582                       errorMaybe = FALSE;
08583                     }
08584 
08585                   if (!sRef_isPartial (s))
08586                     {
08587                       sRef_setDefined (s, fileloc_undefined);
08588                     }
08589                 }
08590 
08591               s = sRef_getBaseSafe (s);
08592             } /* end while */
08593           
08594           if (sRef_isValid (errorRef)) 
08595             {
08596               if (sRef_isValid (lastRef) && sRef_isField (lastRef) 
08597                   && sRef_isPointer (errorRef))
08598                 {
08599                   errorRef = lastRef;
08600                 }
08601               
08602               if (deadRef)
08603                 {
08604                   if (sRef_isThroughArrayFetch (errorRef))
08605                     {
08606                       if (optgenerror 
08607                           (FLG_STRICTUSERELEASED,
08608                            message ("%q %q may be used after being released", 
08609                                     sRef_unparseKindNamePlain (errorRef),
08610                                     sRef_unparse (errorRef)),
08611                            loc))
08612                         {
08613                           sRef_showRefKilled (errorRef);
08614                           
08615                           if (sRef_isKept (errorRef))
08616                             {
08617                               sRef_clearAliasState (errorRef, loc);
08618                             }
08619                         }
08620                     }
08621                   else
08622                     {
08623                       DPRINTF (("HERE: %s", sRef_unparse (errorRef)));
08624 
08625                       if (optgenerror
08626                           (FLG_USERELEASED,
08627                            message ("%q %q %qused after being released", 
08628                                     sRef_unparseKindNamePlain (errorRef),
08629                                     sRef_unparse (errorRef),
08630                                     cstring_makeLiteral (errorMaybe 
08631                                                          ? "may be " : "")),
08632                            loc))
08633                         {
08634                           sRef_showRefKilled (errorRef);
08635                           
08636                           if (sRef_isKept (errorRef))
08637                             {
08638                               sRef_clearAliasState (errorRef, loc);
08639                             }
08640                         }
08641                     }
08642                 }
08643               else if (unuseable)
08644                 {
08645                   if (optgenerror
08646                       (FLG_USEDEF,
08647                        message ("%q %q%qused in inconsistent state", 
08648                                 sRef_unparseKindName (errorRef),
08649                                 sRef_unparseOpt (errorRef),
08650                                 cstring_makeLiteral (errorMaybe ? "may be " : "")),
08651                        loc))
08652                     {
08653                       sRef_showStateInconsistent (errorRef);
08654                     }
08655                 }
08656               else
08657                 {
08658                   DPRINTF (("HERE: %s", sRef_unparse (errorRef)));
08659 
08660                   voptgenerror 
08661                     (FLG_USEDEF,
08662                      message ("%q %q%qused before definition", 
08663                               sRef_unparseKindName (errorRef),
08664                               sRef_unparseOpt (errorRef),
08665                               cstring_makeLiteral (errorMaybe ? "may be " : "")),
08666                      loc);
08667                 }
08668               
08669               sRef_setDefined (errorRef, loc);
08670           
08671               if (sRef_isAddress (errorRef))
08672                 {
08673                   sRef_setDefined (sRef_getRootBase (errorRef), loc);
08674                 }
08675             } /* end is error */
08676         }
08677     }
08678 
08679   setCodePoint ();
08680 }
08681 
08682 static void
08683 checkSafeUse (exprNode e, sRef s)
08684 {
08685   if (exprNode_isDefined (e) && sRef_isKnown (s))
08686     {
08687       e->uses = sRefSet_insert (e->uses, s);
08688     }
08689 }
08690 
08691 static void
08692 exprNode_checkSetAny (exprNode e, /*@dependent@*/ cstring name)
08693 {
08694   if (exprNode_isDefined (e))
08695     {
08696       e->sets = sRefSet_insert (e->sets, sRef_makeUnconstrained (name));
08697     }
08698 }
08699 
08700 void
08701 exprNode_checkSet (exprNode e, sRef s)
08702 {
08703   sRef defines = sRef_undefined;
08704 
08705   if (sRef_isValid (s) && !sRef_isNothing (s))
08706     {
08707       uentry ue = sRef_getBaseUentry (s);
08708 
08709       if (uentry_isValid (ue))
08710         {
08711           uentry_setLset (ue);
08712         }
08713 
08714       if (!ynm_toBoolStrict (sRef_isWriteable (s)))
08715         {
08716           voptgenerror (FLG_USEDEF,
08717                         message ("Attempt to set unuseable storage: %q", 
08718                                  sRef_unparse (s)),
08719                         exprNode_loc (e));
08720         }
08721      
08722       if (sRef_isMeaningful (s))
08723         {
08724           
08725           if (sRef_isDead (s))
08726             {
08727               sRef base = sRef_getBaseSafe (s);
08728 
08729               if (sRef_isValid (base) 
08730                   && sRef_isDead (base))
08731                 {
08732                   sRef_setPartial (s, exprNode_loc (e));
08733                 }
08734               
08735               defines = s; /* okay - modifies for only param */
08736             }
08737           else if (sRef_isPartial (s))
08738             {
08739               sRef eref = exprNode_getSref (e);
08740 
08741               if (!sRef_isPartial (eref))
08742                 {
08743                   /*
08744                   ** should do something different here???
08745                   */
08746                   
08747                   sRef_setDefinedComplete (eref, exprNode_loc (e));               
08748                 }
08749               else
08750                 {
08751                   sRef_setPartialDefinedComplete (eref, exprNode_loc (e));
08752                 }
08753 
08754               if (sRef_isMeaningful (eref))
08755                 {
08756                   defines = eref;
08757                 }
08758               else
08759                 {                
08760                   defines = s;
08761                 }
08762             }
08763           else if (sRef_isAllocated (s))
08764             {
08765               sRef eref = exprNode_getSref (e);
08766 
08767               
08768               if (!sRef_isAllocated (eref))
08769                 {
08770                   sRef_setDefinedComplete (eref, exprNode_loc (e));
08771                 }
08772               else
08773                 {
08774                   sRef base = sRef_getBaseSafe (eref);
08775                   
08776                   if (sRef_isValid (base))
08777                     {
08778                       sRef_setPdefined (base, exprNode_loc (e)); 
08779                     }
08780                 }
08781 
08782               defines = s;
08783             }
08784           else 
08785             {
08786               sRef_setDefinedNCComplete (s, exprNode_loc (e));
08787               defines = s;
08788             }
08789 
08790         }
08791       else /* not meaningful...but still need to insert it */
08792         {
08793           defines = s;
08794         }
08795     }
08796 
08797   if (exprNode_isDefined (e) && sRef_isValid (defines))
08798     {
08799       e->sets = sRefSet_insert (e->sets, defines); 
08800     }
08801 }
08802 
08803 void
08804 exprNode_checkMSet (exprNode e, sRef s)
08805 {
08806   if (sRef_isValid (s) && !sRef_isNothing (s))
08807     {
08808       uentry ue = sRef_getBaseUentry (s);
08809 
08810       if (uentry_isValid (ue))
08811         {
08812           uentry_setLset (ue);
08813         }
08814 
08815       if (!ynm_toBoolStrict (sRef_isWriteable (s)))
08816         {
08817           voptgenerror (FLG_USEDEF,
08818                         message ("Attempt to set unuseable storage: %q", sRef_unparse (s)),
08819                         exprNode_loc (e));
08820         }
08821       
08822       if (sRef_isMeaningful (s))
08823         {
08824           sRef_setDefinedComplete (s, exprNode_loc (e));
08825         }
08826       
08827       if (exprNode_isDefined (e))
08828         {
08829           e->msets = sRefSet_insert (e->msets, s);
08830         }
08831     }
08832 }
08833 
08834 static void
08835 checkUnspecCall (/*@notnull@*/ /*@dependent@*/ exprNode fcn, uentryList params, exprNodeList args)
08836 {
08837   checkAnyCall (fcn, cstring_undefined, params, args, 
08838                 FALSE, sRefSet_undefined, FALSE, 0);
08839 }
08840 
08841 static void
08842 checkOneArg (uentry ucurrent, /*@notnull@*/ exprNode current, 
08843              /*@dependent@*/ exprNode fcn, bool isSpec, int argno, int totargs)
08844 {
08845   setCodePoint ();
08846   
08847   if (uentry_isYield (ucurrent))
08848     {
08849       sRef_setDefined (exprNode_getSref (current), exprNode_loc (current));
08850       exprNode_checkSet (current, current->sref);
08851     }
08852   else 
08853     {
08854       if (uentry_isSefParam (ucurrent))
08855         {
08856           sRefSet sets = current->sets;
08857           sRef ref = exprNode_getSref (current);
08858 
08859           if (sRef_isMacroParamRef (ref))
08860             {
08861               uentry ue = sRef_getUentry (ref);
08862 
08863               if (!uentry_isSefParam (ue))
08864                 {
08865                   voptgenerror 
08866                     (FLG_SEFPARAMS,
08867                      message
08868                      ("Parameter %d to %s is declared sef, but "
08869                       "the argument is a macro parameter declared "
08870                       "without sef: %s",
08871                       argno, exprNode_unparse (fcn),
08872                       exprNode_unparse (current)),
08873                      exprNode_loc (current));
08874                 }
08875             }
08876 
08877           if (!sRefSet_isEmpty (sets))
08878             {
08879               sRefSet reported = sRefSet_undefined;
08880               
08881               sRefSet_realElements (current->sets, el)
08882                 {
08883                   if (sRefSet_isSameNameMember (reported, el))
08884                     {
08885                       ; /* don't report again */
08886                     }
08887                   else
08888                     {
08889                       if (sRef_isUnconstrained (el))
08890                         {
08891                           voptgenerror 
08892                             (FLG_SEFUNSPEC,
08893                              message
08894                              ("Parameter %d to %s is declared sef, but "
08895                               "the argument calls unconstrained function %s "
08896                               "(no guarantee it will not modify something): %s",
08897                               argno, exprNode_unparse (fcn),
08898                               sRef_unconstrainedName (el),
08899                               exprNode_unparse (current)),
08900                              exprNode_loc (current));
08901                         }
08902                       else
08903                         {
08904                           voptgenerror 
08905                             (FLG_SEFPARAMS,
08906                              message
08907                              ("Parameter %d to %s is declared sef, but "
08908                               "the argument may modify %q: %s",
08909                               argno, exprNode_unparse (fcn),
08910                               sRef_unparse (el),
08911                               exprNode_unparse (current)),
08912                              exprNode_loc (current));
08913                         }
08914                     } 
08915                 } end_sRefSet_realElements;
08916             }
08917         }
08918       
08919       checkPassTransfer (current, ucurrent, isSpec, fcn, argno, totargs);
08920       exprNode_mergeUSs (fcn, current);
08921     }
08922 }
08923 
08924 static void
08925   checkAnyCall (/*@dependent@*/ exprNode fcn, 
08926                 /*@dependent@*/ cstring fname,
08927                 uentryList pn, 
08928                 exprNodeList args, 
08929                 bool hasMods, sRefSet mods,
08930                 bool isSpec,
08931                 int specialArgs)
08932 {
08933   int paramno = 0;
08934   int nargs = exprNodeList_size (args);
08935 
08936   setCodePoint ();
08937 
08938   /*
08939   ** concat all args ud's to f, add each arg sref as a use unless
08940   ** it was specified as "out", in which case it is a def.
08941   */
08942   
08943   uentryList_reset (pn);
08944   
08945   /*
08946   ** aliasing checks:
08947   **
08948   **    if paramn is only or unique, no other arg may alias argn
08949   */
08950   
08951   exprNodeList_elements (args, current) 
08952     {
08953       paramno++;
08954       
08955       if (exprNode_isDefined (current)) 
08956         {
08957           if ((!uentryList_isUndefined (pn) && !uentryList_isFinished (pn))) 
08958             {
08959               uentry ucurrent = uentryList_current (pn);
08960               
08961               if (specialArgs == 0 
08962                   || (paramno < specialArgs))
08963                 {
08964                                   checkOneArg (ucurrent, current, fcn, isSpec, paramno, nargs);
08965 
08966                   if (context_maybeSet (FLG_ALIASUNIQUE))
08967                     {
08968                       if (uentry_isOnly (ucurrent)
08969                           || uentry_isUnique (ucurrent))
08970                         {
08971                           checkUniqueParams (fcn, current, args,
08972                                              paramno, ucurrent);
08973                         }
08974                     }
08975                 } 
08976             }
08977           else /* uentry is undefined */
08978             {
08979               if (specialArgs == 0)
08980                 {
08981                   exprNode_checkUseParam (current);
08982                 }
08983 
08984               exprNode_mergeUSs (fcn, current);
08985             }   
08986         }
08987       uentryList_advanceSafe (pn);
08988     } end_exprNodeList_elements;
08989   
08990   if (hasMods)
08991     {
08992       setCodePoint ();
08993 
08994       sRefSet_allElements (mods, s)
08995         {
08996           sRef fb;
08997           sRef rb = sRef_getRootBase (s);
08998           
08999           if (sRef_isGlobal (rb))
09000             {
09001               context_usedGlobal (rb);
09002             }
09003           
09004           fb = sRef_fixBaseParam (s, args);
09005           
09006           if (!sRef_isMacroParamRef (fb))
09007             {
09008               if (sRef_isNothing (fb))
09009                 {
09010                   ;
09011                 }
09012               else
09013                 {
09014                   if (sRef_isValid (fb))
09015                     {
09016                       uentry ue = sRef_getBaseUentry (s);
09017                       
09018                       if (uentry_isValid (ue))
09019                         {
09020                           uentry_setLset (ue);
09021                         }
09022                     }
09023                   
09024                   fcn->sets = sRefSet_insert (fcn->sets, fb);
09025                 }
09026             }
09027           sRef_clearDerivedComplete (s); 
09028         } end_sRefSet_allElements;
09029       
09030       setCodePoint ();
09031     }
09032   else
09033     {
09034       if (context_hasMods ())
09035         {
09036           if (context_maybeSet (FLG_MODUNCON))
09037             {
09038               voptgenerror
09039                 (FLG_MODUNCON,
09040                  message ("Undetected modification possible "
09041                           "from call to unconstrained function %s: %s", 
09042                           fname,
09043                           exprNode_unparse (fcn)),
09044                  exprNode_loc (fcn));
09045             }
09046         }
09047       else
09048         {
09049           if (context_maybeSet (FLG_MODUNCONNOMODS)
09050               && !(context_inIterDef () || context_inIterEnd ()))
09051             {
09052               voptgenerror
09053                 (FLG_MODUNCONNOMODS,
09054                  message ("Undetected modification possible "
09055                           "from call to unconstrained function %s: %s", 
09056                           fname,
09057                           exprNode_unparse (fcn)),
09058                  exprNode_loc (fcn));
09059             }
09060         }
09061 
09062       exprNode_checkSetAny (fcn, fname);
09063     }
09064 }
09065 
09066 void exprNode_checkUseParam (exprNode current)
09067 {
09068   if (exprNode_isDefined (current))
09069     {
09070       exprNode_checkUse (current, current->sref, current->loc);
09071     }
09072 }
09073 
09074 static ctype
09075   checkNumerics (ctype tr1, ctype tr2, ctype te1, ctype te2,
09076                  /*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2,
09077                  lltok op)
09078 {
09079   ctype ret = tr1;
09080   
09081   if (!ctype_match (tr1, tr2))
09082     {
09083       if ((ctype_isRealInt (tr1) || ctype_isReal (tr1)) &&
09084           (ctype_isRealInt (tr2) || ctype_isReal (tr2)))
09085         {
09086           ;
09087         }
09088       else
09089         {
09090           (void) gentypeerror 
09091             (tr1, e1, tr2, e2,
09092              message ("Incompatible types for %s (%s, %s): %s %s %s",
09093                       lltok_unparse (op),
09094                       ctype_unparse (te1),
09095                       ctype_unparse (te2),
09096                       exprNode_unparse (e1), lltok_unparse (op), 
09097                       exprNode_unparse (e2)),
09098              e1->loc);
09099         }
09100       ret = ctype_unknown;
09101     }
09102   else
09103     {
09104       if (ctype_isForceRealNumeric (&tr1) && ctype_isForceRealNumeric (&tr2))
09105         {
09106           ret = ctype_resolveNumerics (tr1, tr2);
09107         }
09108       else if (!context_msgStrictOps ()) 
09109         {
09110                   if (ctype_isPointer (tr1))
09111             {
09112               if (ctype_isPointer (tr2) && !exprNode_isNullValue (e2))
09113                 {
09114                   ret = ctype_int;
09115                 }
09116               else if (ctype_isInt (tr2))
09117                 {
09118                   ret = te1;
09119                 }
09120               else
09121                 {
09122                   ret = ctype_unknown;
09123                 }
09124             }
09125           else if (ctype_isPointer (tr2))
09126             {
09127               if (ctype_isPointer (tr1))
09128                 {
09129                   ret = ctype_int;
09130                 }
09131               else if (ctype_isInt (tr1))
09132                 {
09133                   ret = te2;
09134                 }
09135               else
09136                 {
09137                   ret = ctype_unknown; 
09138                 }
09139             }
09140           else
09141             {
09142               ret = ctype_resolveNumerics (tr1, tr2);
09143             }
09144         }
09145       else
09146         {
09147           int opid = lltok_getTok (op);
09148           bool comparop = (opid == EQ_OP || opid == NE_OP 
09149                            || opid == TLT || opid == TGT
09150                            || opid == LE_OP || opid == GE_OP);
09151           
09152           if (!ctype_isNumeric (tr1) && !ctype_isNumeric (tr2))
09153             {
09154               if (comparop
09155                   && ((ctype_isEnum (tr1) && ctype_isEnum (tr2))
09156                       || (ctype_isBool (tr1) && ctype_isBool (tr2))
09157                       || (ctype_isChar (tr1) && ctype_isChar (tr2))))
09158                 {
09159                   ; /* no error */
09160                 }
09161               else
09162                 {
09163                   if (ctype_sameName (te1, te2))
09164                     {
09165                       voptgenerror
09166                         (FLG_STRICTOPS,
09167                          message ("Operands of %s are non-numeric (%t): %s %s %s",
09168                                   lltok_unparse (op), te1, 
09169                                   exprNode_unparse (e1), lltok_unparse (op), 
09170                                   exprNode_unparse (e2)),
09171                          e1->loc);
09172                     }
09173                   else
09174                     {
09175                       voptgenerror
09176                         (FLG_STRICTOPS,
09177                          message ("Operands of %s are non-numerics (%t, %t): %s %s %s",
09178                                   lltok_unparse (op), te1, te2, 
09179                                   exprNode_unparse (e1), lltok_unparse (op),
09180                                   exprNode_unparse (e2)),
09181                          e1->loc);
09182                     }
09183                 }
09184             }
09185           else if (!ctype_isNumeric (tr1))
09186             {
09187               voptgenerror
09188                 (FLG_STRICTOPS,
09189                  message ("Right operand of %s is non-numeric (%t): %s %s %s",
09190                           lltok_unparse (op), te1, 
09191                           exprNode_unparse (e1), lltok_unparse (op), 
09192                           exprNode_unparse (e2)),
09193                  e1->loc);
09194             }
09195           else 
09196             {
09197               if (!ctype_isNumeric (tr2))
09198                 {
09199                   voptgenerror
09200                     (FLG_STRICTOPS,
09201                      message ("Left operand of %s is non-numeric (%t): %s %s %s",
09202                               lltok_unparse (op), te2, 
09203                               exprNode_unparse (e1), lltok_unparse (op), 
09204                               exprNode_unparse (e2)),
09205                      e2->loc);
09206                 }
09207             }
09208           
09209           ret = ctype_unknown;
09210         }
09211     }
09212 
09213   return ret;
09214 }
09215 
09216 static void
09217 abstractOpError (ctype tr1, ctype tr2, lltok op, 
09218                  /*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2, 
09219                  fileloc loc1, fileloc loc2)
09220 {
09221   if (ctype_isRealAbstract (tr1) && ctype_isRealAbstract (tr2))
09222     {
09223       if (ctype_match (tr1, tr2))
09224         {
09225           voptgenerror
09226             (FLG_ABSTRACT,
09227              message ("Operands of %s are abstract type (%t): %s %s %s",
09228                       lltok_unparse (op), tr1, 
09229                       exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
09230              loc1);
09231         }
09232       else
09233         {
09234           voptgenerror 
09235             (FLG_ABSTRACT,
09236              message ("Operands of %s are abstract types (%t, %t): %s %s %s",
09237                       lltok_unparse (op), tr1, tr2, 
09238                       exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
09239              loc1);
09240         }
09241     }
09242   else if (ctype_isRealAbstract (tr1))
09243     {
09244       voptgenerror
09245         (FLG_ABSTRACT,
09246          message ("Left operand of %s is abstract type (%t): %s %s %s",
09247                   lltok_unparse (op), tr1, 
09248                   exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
09249          loc1);
09250     }
09251   else 
09252     {
09253       if (ctype_isRealAbstract (tr2))
09254         {
09255           voptgenerror
09256             (FLG_ABSTRACT,
09257              message ("Right operand of %s is abstract type (%t): %s %s %s",
09258                       lltok_unparse (op), tr2, 
09259                       exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
09260              loc2);
09261         }
09262     }
09263 }
09264 
09265 /*
09266 ** e1 <= e2
09267 **
09268 ** requies e1 and e2 and not error exprNode's.
09269 **
09270 ** Checks:
09271 **
09272 **    If e1 is a component of an abstract type, and e2 is mutable and client-visible, 
09273 **    the rep of the abstract type is exposed.
09274 **
09275 ** The order is very important:
09276 **
09277 **    check rep expose (move into check transfer)
09278 **    check transfer
09279 **    setup aliases
09280 */
09281 
09282 /*
09283 ** This isn't really a sensible procedure, but the indententation
09284 ** was getting too deep.
09285 */
09286 
09287 static void
09288 checkOneRepExpose (sRef ysr, sRef base, 
09289                    /*@notnull@*/ exprNode e1, 
09290                    /*@notnull@*/ exprNode e2, ctype ct,
09291                    sRef s2b)
09292 {
09293   if (!(sRef_isOnly (ysr) || sRef_isKeep (ysr) 
09294         || sRef_isOwned (ysr) || sRef_isExposed (ysr)))
09295     {
09296       if (sRef_isAnyParam (base) && !sRef_isExposed (base))
09297         {
09298           if (sRef_isIReference (ysr))
09299             {
09300               if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
09301                 {
09302                   voptgenerror 
09303                     (FLG_ASSIGNEXPOSE,
09304                      message
09305                      ("Assignment of mutable component of parameter %q "
09306                       "to component of abstract "
09307                       "type %s exposes rep: %s = %s",
09308                       sRef_unparse (base),
09309                       ctype_unparse (ct),
09310                       exprNode_unparse (e1), exprNode_unparse (e2)),
09311                      e1->loc);
09312                 }
09313               else
09314                 {
09315                   voptgenerror 
09316                     (FLG_ASSIGNEXPOSE,
09317                      message
09318                      ("Assignment of mutable component of parameter %q "
09319                       "(through alias %q) to component of abstract "
09320                       "type %s exposes rep: %s = %s",
09321                       sRef_unparse (base),
09322                       sRef_unparse (e2->sref),
09323                       ctype_unparse (ct),
09324                       exprNode_unparse (e1), exprNode_unparse (e2)),
09325                      e1->loc);
09326                 }
09327             }
09328           else
09329             {
09330               if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
09331                 {
09332                   voptgenerror 
09333                     (FLG_ASSIGNEXPOSE,
09334                      message ("Assignment of mutable parameter %q "
09335                               "to component of abstract type %s "
09336                               "exposes rep: %s = %s",
09337                               sRef_unparse (base),
09338                               ctype_unparse (ct),
09339                               exprNode_unparse (e1), 
09340                               exprNode_unparse (e2)),
09341                      e1->loc);
09342                 }
09343               else
09344                 {
09345                   voptgenerror 
09346                     (FLG_ASSIGNEXPOSE,
09347                      message ("Assignment of mutable parameter %q "
09348                               "(through alias %q) to "
09349                               "component of abstract type %s exposes "
09350                               "rep: %s = %s",
09351                               sRef_unparse (base),
09352                               sRef_unparse (e2->sref),
09353                               ctype_unparse (ct),
09354                               exprNode_unparse (e1), 
09355                               exprNode_unparse (e2)),
09356                      e1->loc);
09357                 }
09358             }
09359         }
09360       
09361       if (sRef_isGlobal (s2b))
09362         {
09363           if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
09364             {
09365               voptgenerror 
09366                 (FLG_REPEXPOSE,
09367                  message ("Assignment of global %q "
09368                           "to component of "
09369                           "abstract type %s exposes rep: %s = %s",
09370                           sRef_unparse (base),
09371                           ctype_unparse (ct),
09372                           exprNode_unparse (e1), exprNode_unparse (e2)),
09373                  e1->loc);
09374             }
09375           else
09376             {
09377               voptgenerror 
09378                 (FLG_REPEXPOSE,
09379                  message ("Assignment of global %q (through alias %q) "
09380                           "to component of "
09381                           "abstract type %s exposes rep: %s = %s",
09382                           sRef_unparse (base),
09383                           sRef_unparse (e2->sref),
09384                           ctype_unparse (ct),
09385                           exprNode_unparse (e1), exprNode_unparse (e2)),
09386                  e1->loc);
09387             }
09388         }
09389     }
09390 }
09391 
09392 static void
09393 doAssign (/*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2, bool isInit)
09394 {
09395   if (ctype_isRealFunction (exprNode_getType (e1))
09396       && !ctype_isRealPointer (exprNode_getType (e1)))
09397     {
09398       voptgenerror 
09399         (FLG_TYPE,
09400          message ("Invalid left-hand side of assignment (function type %s): %s",
09401                   ctype_unparse (exprNode_getType (e1)),
09402                   exprNode_unparse (e1)),
09403          e1->loc);
09404     }
09405 
09406   if (context_getFlag (FLG_ASSIGNEXPOSE) && ctype_isMutable (e2->typ))
09407     {
09408       ctype t2 = exprNode_getType (e2);
09409       sRef sr = sRef_getRootBase (e1->sref);
09410       ctype ct = sRef_getType (sr);
09411 
09412       if (ctype_isAbstract (t2) 
09413           && !(uentry_isMutableDatatype (usymtab_getTypeEntry (ctype_typeId (t2)))))
09414         {
09415           /* it is immutable, okay to reference */
09416           goto donerepexpose;
09417         }
09418 
09419       if (ctype_isAbstract (ct) && sRef_isIReference (e1->sref))
09420         {
09421           sRef s2b = sRef_getRootBase (e2->sref);
09422           sRef s1 = e1->sref;
09423           sRef s1b = sRef_getRootBase (s1);
09424           sRefSet aliases;
09425 
09426           aliases = usymtab_canAlias (e2->sref);
09427           
09428           if (!sRef_similar (s2b, s1b) 
09429               && !sRef_isExposed (s1)
09430               && !(sRef_isOnly (s2b) || sRef_isKeep (s2b) || sRef_isExposed (s2b)))
09431             {
09432               if (sRef_isAnyParam (s2b) && !sRef_isOnly (s2b) 
09433                   && !sRef_isOwned (s2b) && !sRef_isKeep (s2b)
09434                   && !sRef_isExposed (s2b))
09435                 {
09436                   if (sRef_isIReference (e2->sref))
09437                     {
09438                       voptgenerror 
09439                         (FLG_ASSIGNEXPOSE,
09440                          message 
09441                          ("Assignment of mutable component of parameter %q "
09442                           "to component of abstract type %s exposes rep: %s = %s",
09443                           sRef_unparse (s2b),
09444                           ctype_unparse (ct),
09445                           exprNode_unparse (e1), exprNode_unparse (e2)),
09446                          e1->loc);
09447                     }
09448                   else
09449                     {
09450                       voptgenerror 
09451                         (FLG_ASSIGNEXPOSE,
09452                          message ("Assignment of mutable parameter %q to "
09453                                   "component of abstract type %s exposes rep: %s = %s",
09454                                   sRef_unparse (s2b),
09455                                   ctype_unparse (ct),
09456                                   exprNode_unparse (e1), exprNode_unparse (e2)),
09457                          e1->loc);
09458                     }
09459                 }
09460 
09461               if (sRef_isGlobal (s2b))
09462                 {
09463                   voptgenerror
09464                     (FLG_ASSIGNEXPOSE,
09465                      message ("Assignment of global %q to component of "
09466                               "abstract type %s exposes rep: %s = %s",
09467                               sRef_unparse (s2b),
09468                               ctype_unparse (ct),
09469                               exprNode_unparse (e1), exprNode_unparse (e2)),
09470                      e1->loc);
09471                 }
09472               
09473               sRefSet_realElements (aliases, ysr)
09474                 {
09475                   sRef base = sRef_getRootBase (ysr);
09476                   
09477                   if (sRef_similar (ysr, s2b) || sRef_similar (s1b, base)
09478                       || sRef_sameName (base, s1b))
09479                     {
09480                      ; /* error already reported or same sref */
09481                     }
09482                   else
09483                     {
09484                       checkOneRepExpose (ysr, base, e1, e2, ct, s2b);
09485                     }
09486                 } end_sRefSet_realElements;
09487             }
09488           sRefSet_free (aliases);
09489         }
09490     }
09491 
09492  donerepexpose:
09493 
09494   /*
09495   ** function variables don't really work...
09496   */
09497 
09498   if (!ctype_isFunction (ctype_realType (e2->typ)))
09499     {
09500       if (isInit)
09501         {
09502           checkInitTransfer (e1, e2); 
09503         }
09504       else
09505         {
09506           checkAssignTransfer (e1, e2); 
09507         }
09508     }
09509   else
09510     {
09511       sRef fref = e2->sref;
09512 
09513       sRef_setDefState (e1->sref, sRef_getDefState (fref), e1->loc);
09514       sRef_setNullState (e1->sref, sRef_getNullState (fref), e1->loc);
09515 
09516             /* Need to typecheck the annotation on the parameters */
09517       
09518       if (ctype_isRealFunction (e1->typ)) {
09519         uentryList e1p = ctype_argsFunction (ctype_realType (e1->typ));
09520         uentryList e2p = ctype_argsFunction (ctype_realType (e2->typ));
09521 
09522         if (!uentryList_isMissingParams (e1p)
09523             && !uentryList_isMissingParams (e2p)
09524             && uentryList_size (e1p) > 0) {
09525           if (uentryList_size (e1p) == uentryList_size (e2p)) {
09526             int n = 0;
09527             
09528             uentryList_elements (e1p, el1) {
09529               uentry el2;
09530 
09531               el2 = uentryList_getN (e2p, n);
09532               n++;
09533               uentry_checkMatchParam (el1, el2, n, e2);
09534             } end_uentryList_elements;
09535           }
09536         }
09537       }
09538     }
09539 
09540   if (isInit && sRef_isGlobal (e1->sref))
09541     {
09542        ;
09543     }
09544   else
09545     {
09546       updateAliases (e1, e2); 
09547     }
09548 }
09549 
09550 static void 
09551 checkMacroParen (exprNode e)
09552 {
09553   if (exprNode_isError (e) || e->kind == XPR_CAST)
09554     {
09555      ;
09556     }
09557   else 
09558     {
09559       if (sRef_isUnsafe (e->sref) && !exprNode_isInParens (e))
09560         {
09561           voptgenerror 
09562             (FLG_MACROPARENS,
09563              message ("Macro parameter used without parentheses: %s", 
09564                       exprNode_unparse (e)),
09565              e->loc);
09566         }
09567     }
09568 }
09569 
09570 static void
09571 reflectNullTest (/*@notnull@*/ exprNode e, bool isnull)
09572 {
09573   if (isnull)
09574     {
09575       e->guards = guardSet_addTrueGuard (e->guards, e->sref);
09576     }
09577   else
09578     {
09579       e->guards = guardSet_addFalseGuard (e->guards, e->sref);
09580     }
09581 }
09582 
09583 /*
09584 ** e1 <= e2
09585 **
09586 ** if e2 is a parameter or global derived location which
09587 ** can be modified (that is, e2 is a mutable abstract type,
09588 ** or a derived pointer), then e1 can alias e2.
09589 **
09590 ** e1 can alias everything which e2 can alias.
09591 **
09592 ** Also, if e1 is guarded, remove from guard sets!
09593 */
09594 
09595 static void updateAliases (/*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2)
09596 {
09597   if (!context_inProtectVars ())
09598     {
09599       /*
09600       ** depends on types of e1 and e2
09601       */
09602       
09603       sRef s1 = e1->sref;
09604       sRef s2 = e2->sref;
09605       ctype t1 = exprNode_getType (e1);
09606       
09607       /* handle pointer sRefs, record fields, arrays, etc... */
09608       
09609       if (!ctype_isRealSU (t1))
09610         {
09611           sRef_copyRealDerivedComplete (s1, s2);
09612         }
09613 
09614       if (ctype_isMutable (t1) && sRef_isKnown (s1))
09615         {
09616           usymtab_clearAlias (s1);
09617           usymtab_addMustAlias (s1, s2); 
09618         }
09619 
09620       if (sRef_possiblyNull (s1) && usymtab_isGuarded (s1))
09621         {
09622           usymtab_unguard (s1);
09623         }
09624     }
09625 }
09626 
09627 exprNode exprNode_updateLocation (/*@returned@*/ exprNode e, /*@temp@*/ fileloc loc)
09628 {
09629   if (exprNode_isDefined (e))
09630     {
09631       e->loc = fileloc_update (e->loc, loc);
09632     }
09633   else
09634     {
09635       e = exprNode_createLoc (ctype_unknown, fileloc_copy (loc));
09636     }
09637 
09638   return (e);
09639 }
09640 
09641 static void checkUniqueParams (exprNode fcn,
09642                                /*@notnull@*/ exprNode current, 
09643                                exprNodeList args, 
09644                                int paramno, uentry ucurrent)
09645 {
09646   int iparamno = 0;
09647   sRef thisref = exprNode_getSref (current);
09648   
09649   /*
09650   ** Check if any argument could match this argument.
09651   */
09652   
09653   exprNodeList_elements (args, icurrent) 
09654     {
09655       iparamno++;
09656       
09657       if (iparamno != paramno)
09658         {
09659           sRef sr = exprNode_getSref (icurrent);
09660           
09661           if (sRef_similarRelaxed (thisref, sr))
09662             {
09663               if (!sRef_isConst (thisref) && !sRef_isConst (sr))
09664                 {
09665                   voptgenerror 
09666                     (FLG_ALIASUNIQUE,
09667                      message
09668                      ("Parameter %d (%s) to function %s is declared %s but "
09669                       "is aliased by parameter %d (%s)",
09670                       paramno, 
09671                       exprNode_unparse (current),
09672                       exprNode_unparse (fcn),
09673                       alkind_unparse (uentry_getAliasKind (ucurrent)),
09674                       iparamno, exprNode_unparse (icurrent)),
09675                      current->loc);
09676                 }
09677             }
09678           else
09679             {
09680               sRefSet aliases = usymtab_canAlias (sr);
09681 
09682               sRefSet_allElements (aliases, asr)
09683                 {
09684                   if (ctype_isUnknown (sRef_getType (thisref)))
09685                     {
09686                       sRef_setType (thisref, uentry_getType (ucurrent));
09687                     }
09688                   
09689                   if (sRef_similarRelaxed (thisref, asr)) 
09690                     {
09691                       if (sRef_isExternal (asr))  
09692                         {
09693                           if (sRef_isLocalState (thisref))
09694                             {
09695                               ; /* okay */
09696                             }
09697                           else
09698                             {
09699                               sRef base = sRef_getRootBase (asr);
09700                               
09701                               if (!sRef_similar (sRef_getBase (asr), thisref)) 
09702                                 {
09703                                   if (sRef_isUnique (base) || sRef_isOnly (base)
09704                                       || sRef_isKept (base)
09705                                       || (sRef_isAddress (asr) && sRef_isLocalVar (base))
09706                                       || (sRef_isAddress (thisref) 
09707                                           && sRef_isLocalVar (sRef_getRootBase (thisref))))
09708                                     {
09709                                       ; /* okay, no error */
09710                                     }
09711                                   else
09712                                     {
09713                                       voptgenerror 
09714                                         (FLG_MAYALIASUNIQUE,
09715                                          message
09716                                          ("Parameter %d (%s) to function %s is declared %s but "
09717                                           "may be aliased externally by parameter %d (%s)",
09718                                           paramno, 
09719                                           exprNode_unparse (current),
09720                                           exprNode_unparse (fcn),
09721                                           alkind_unparse (uentry_getAliasKind (ucurrent)),
09722                                           iparamno, exprNode_unparse (icurrent)),
09723                                          current->loc);
09724                                     }
09725                                 }
09726                             }
09727                         }
09728                       else
09729                         {
09730                           voptgenerror 
09731                             (FLG_ALIASUNIQUE,
09732                              message
09733                              ("Parameter %d (%s) to function %s is declared %s but "
09734                               "is aliased externally by parameter %d (%s) through "
09735                               "alias %q",
09736                               paramno, 
09737                               exprNode_unparse (current),
09738                               exprNode_unparse (fcn),
09739                               alkind_unparse (uentry_getAliasKind (ucurrent)),
09740                               iparamno, exprNode_unparse (icurrent),
09741                               sRef_unparse (asr)),
09742                              current->loc);
09743                         }
09744                     }
09745                 } end_sRefSet_allElements;
09746               sRefSet_free (aliases);
09747             }
09748         }
09749     } end_exprNodeList_elements;
09750 }
09751 
09752 long exprNode_getLongValue (exprNode e) {
09753   long value;
09754 
09755   if (exprNode_hasValue (e) 
09756       && multiVal_isInt (exprNode_getValue (e)))
09757     {
09758       value = multiVal_forceInt (exprNode_getValue (e));
09759     }
09760   else
09761     {
09762       value = 0;
09763     }
09764   
09765   return value;
09766 }

Generated at Fri Nov 3 18:57:41 2000 for LCLint by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000