/*
** Splint - annotation-assisted static program checker
** Copyright (C) 1994-2002 University of Virginia,
**         Massachusetts Institute of Technology
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
** Free Software Foundation; either version 2 of the License, or (at your
** option) any later version.
** 
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** The GNU General Public License is available from http://www.gnu.org/ or
** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
** MA 02111-1307, USA.
**
** For information on splint: info@splint.org
** To report a bug: splint-bug@splint.org
** For more information: http://www.splint.org
*/
/*
** uentry.c
*/

# include "splintMacros.nf"
# include "basic.h"
# include "structNames.h"
# include "nameChecks.h"

static /*@dependent@*/ uentry posRedeclared = uentry_undefined;
static /*@only@*/ fileloc posLoc = fileloc_undefined;
static int nuentries = 0;
static int totuentries = 0;

static void checkGlobalsModifies (/*@notnull@*/ uentry p_ue, sRefSet p_sr) ;
static void uentry_setDeclDef (uentry p_e, fileloc p_f) /*@modifies p_e@*/ ;
static bool uentry_isRefCounted (uentry p_ue) /*@*/ ;
static bool uentry_isRefsField (uentry p_ue) /*@*/ ;
static bool uentry_isReallySpecified (uentry p_e) /*@*/ ;
static void uentry_checkIterArgs (uentry p_ue);
static cstring uentry_dumpAux (uentry p_v, bool p_isParam);

static void uentry_showWhereLastKind (uentry p_spec) /*@modifies g_msgstream@*/ ; 

static void uentry_combineModifies (uentry p_ue, /*@owned@*/ sRefSet p_sr) 
     /*@modifies p_ue@*/ ;

static void uentry_addStateClause (uentry p_ue, /*@only@*/ stateClause p_sc)
     /*@modifies p_ue@*/ ;

/*@access ekind@*/
static void checkAliasState (/*@notnull@*/ uentry p_old,
			       /*@notnull@*/ uentry p_unew, 
			       bool p_mustConform, bool p_completeConform) 
   /*@modifies p_old, p_unew@*/ ;
static void checkNullState (/*@notnull@*/ uentry p_old,
			    /*@notnull@*/ uentry p_unew, 
			    bool p_mustConform, bool p_completeConform) 
   /*@modifies p_old, p_unew@*/ ;

static void checkVarConformance (/*@notnull@*/ uentry p_old,
				 /*@notnull@*/ uentry p_unew, 
				 bool p_mustConform, bool p_completeConform) 
   /*@modifies p_old, p_unew@*/;

# ifndef NOLCL
static void uentry_setHasMods (uentry p_ue) /*@modifies p_ue@*/;
static void uentry_setHasGlobs (uentry p_ue) /*@modifies p_ue@*/;
# endif

static void uentry_reallyFree (/*@notnull@*/ /*@only@*/ uentry p_e);

static void uentry_setSpecDef (/*@special@*/ uentry p_e, /*@keep@*/ fileloc p_f)
   /*@defines p_e->whereSpecified, p_e->whereDeclared, p_e->whereDefined@*/
   /*@modifies p_e@*/;

static void returnValueError (/*@notnull@*/ uentry p_old, /*@notnull@*/ uentry p_unew);
static void nargsError (/*@notnull@*/ uentry p_old, /*@notnull@*/ uentry p_unew);
static /*@observer@*/ cstring paramStorageName (uentry p_ue) /*@*/ ;
static /*@observer@*/ cstring fcnErrName (uentry p_ue) /*@*/ ;
static /*@observer@*/ cstring checkedName (chkind p_checked) /*@*/ ;
static void 
  paramTypeError (/*@notnull@*/ uentry p_old, /*@notnull@*/ uentry p_oldCurrent,
		  ctype p_oldType, /*@notnull@*/ uentry p_unew,
		  /*@notnull@*/ uentry p_newCurrent, 
		  ctype p_newType, int p_paramno) /*@modifies g_msgstream@*/ ;

static /*@only@*/ /*@notnull@*/ uentry 
  uentry_makeVariableAux (cstring p_n, ctype p_t, /*@keep@*/ fileloc p_f,
			  /*@exposed@*/ sRef p_s, bool p_priv, vkind p_kind);

static /*@only@*/ /*@notnull@*/ uentry 
  uentry_makeConstantAux (cstring p_n, ctype p_t, 
			  /*@keep@*/ fileloc p_f, bool p_priv, bool p_macro,
			  /*@only@*/ multiVal p_m) /*@*/ ;

static void uentry_convertVarFunction (uentry ue) /*@modifies ue@*/
{
  if (uentry_isVariable (ue) 
      && (ctype_isFunction (ctype_realType (uentry_getType (ue)))
	  || ctype_isUnknown (uentry_getType (ue))))
    {
      uentry_makeVarFunction (ue);
    }
}

static /*@out@*/ /*@notnull@*/ uentry uentry_alloc (void) /*@*/ 
{
  uentry ue = (uentry) dmalloc (sizeof (*ue));
  ue->warn = warnClause_undefined; /*@i32@*/
  nuentries++;
  totuentries++;
  
  return ue;
}

static cstring uentry_getOptName (uentry p_e) /*@*/ ;
static void uentry_updateInto (/*@unique@*/ uentry p_unew, uentry p_old) /*@modifies p_unew, p_old@*/ ;

static void uentry_setNullState (/*@notnull@*/ uentry p_ue, nstate p_ns);
static void uentry_setAliasKind (/*@notnull@*/ uentry p_ue, alkind p_ak);
static /*@only@*/ /*@null@*/ uinfo uinfo_copy (uinfo p_u, ekind p_kind);
static void uinfo_free (/*@only@*/ uinfo p_u, ekind p_kind);
static void ucinfo_free (/*@only@*/ ucinfo p_u);
static void uvinfo_free (/*@only@*/ uvinfo p_u);

# ifdef DOANNOTS

static /*@only@*/ cstring ancontext_unparse (ancontext an)
{
  switch (an)
    {
    case AN_UNKNOWN: return cstring_makeLiteral ("unknown");
    case AN_FCNRETURN: return cstring_makeLiteral ("return value");
    case AN_FCNPARAM: return cstring_makeLiteral ("function param");
    case AN_SUFIELD: return cstring_makeLiteral ("su field");
    case AN_TDEFN: return cstring_makeLiteral ("type definition");
    case AN_GSVAR: return cstring_makeLiteral ("global/static var");
    case AN_CONST: return cstring_makeLiteral ("constant");
    BADDEFAULT;
    }
  BADEXIT;
}

static int annots[AN_LAST][QU_LAST];
static int decls[AN_LAST];
static int shdecls[AN_LAST];
static int idecls[AN_LAST];

void initAnnots ()
{
  int i, j;

  for (i = AN_UNKNOWN; i < AN_LAST; i++)
    {
      decls[i] = 0;
      shdecls[i] = 0;
      idecls[i] = 0;

      for (j = QU_UNKNOWN; j < QU_LAST; j++)
	{
	  annots[i][j] = 0;
	}
    }
}

static void tallyAnnot (ancontext ac, qual q)
{
  (annots[ac][q])++;
}

void printAnnots ()
{
  int total[QU_LAST];
  int alltotals = 0;
  int totdecls = 0;
  int totshdecls = 0;
  int totidecls = 0;
  int i, j;

  for (j = QU_UNKNOWN; j < QU_LAST; j++)
    {
      total[j] = 0;
    }

  for (i = AN_UNKNOWN; i < AN_LAST; i++)
    {
      int tmptot;

      if (decls[i] > 0)
	{
	  printf ("Context: %s (%d declarations, %d sharable, %d indirect)\n", 
		  ancontext_unparse (i),
		  decls[i], shdecls[i], idecls[i]);
	  
	  totdecls += decls[i];
	  totshdecls += shdecls[i];
	  totidecls += idecls[i];
	  
	  for (j = QU_UNKNOWN; j < QU_LAST; j++)
	    {
	      total[j] += annots[i][j];
	      alltotals += annots[i][j];
	    }
	  
	  printf ("   Allocation:\n");
	  
	  tmptot = 0;
	  
	  for (j = QU_UNKNOWN; j < QU_LAST; j++)
	    {
	      if (qual_isAliasQual (j) && !qual_isUnique (j))
		{
		  if (annots[i][j] > 0)
		    {
		      printf ("\t%10s: %5d (%3.2f%%)\n", qual_unparse (j), annots[i][j],
			      100.0 * (double)annots[i][j] / (double)decls[i]);
		      tmptot += annots[i][j];
		    }
		}
	    }

	  printf ("   Exposure:\n");
	  
	  tmptot = 0;
	  
	  for (j = QU_UNKNOWN; j < QU_LAST; j++)
	    {
	      if (qual_isExQual (j))
		{
		  if (annots[i][j] > 0)
		    {
		      printf ("\t%10s: %5d (%3.2f%%)\n", qual_unparse (j), annots[i][j],
			      100.0 * (double)annots[i][j] / (double)decls[i]);
		      tmptot += annots[i][j];
		    }
		}
	    }
	  
	  printf ("   Definition:\n");
	  
	  for (j = QU_UNKNOWN; j < QU_LAST; j++)
	    {
	      if (qual_isAllocQual (j))
		{
		  if (annots[i][j] > 0)
		    {
		      printf ("\t%10s: %5d (%3.2f%%)\n", qual_unparse (j), annots[i][j],
			      100.0 * (double)annots[i][j] / (double)decls[i]);
		    }
		}
	    }
	  
	  printf ("   Null:\n");
	  
	  for (j = QU_UNKNOWN; j < QU_LAST; j++)
	    {
	      if (qual_isNull (j) || qual_isNotNull (j) || qual_isRelNull (j))
		{
		  if (annots[i][j] > 0)
		    {
		      printf ("\t%10s: %5d (%3.2f%%)\n", qual_unparse (j), annots[i][j],
			      100.0 * (double)annots[i][j] / (double)decls[i]);
		    }
		}
	    }

	  printf ("\n");
	}
    }

  for (j = QU_UNKNOWN; j < QU_LAST; j++)
    {
      bool hasone = FALSE;

      for (i = AN_UNKNOWN; i < AN_LAST; i++)
	{
	  if (annots[i][j] > 0)
	    {
	      hasone = TRUE;
	      break;
	    }
	}

      if (hasone)
	{
	  printf ("Annotation: %s\n", qual_unparse (j));
	  
	  for (i = AN_UNKNOWN; i < AN_LAST; i++)
	    {
	      if (annots[i][j] > 0)
		{
		  printf ("%25s: %5d\n", ancontext_unparse (i), annots[i][j]);
		}
	    }
	  printf ("\n");
	}
    }

  printf ("All Contexts\n");
  
  for (j = QU_UNKNOWN; j < QU_LAST; j++)
    {
      if (total[j] > 0)
	{
	  printf ("%10s: %5d (%3.2f%%)\n", qual_unparse (j), total[j],
		  100.0 * (double)total[j] / (double)(totdecls));
	}
    }
  printf ("\n");

  printf ("Total Annotations: %d (%d decls, %d sharable, %d indirect)\n", alltotals, totdecls, totshdecls, totidecls); }

extern void uentry_tallyAnnots (uentry u, ancontext kind)
{
  alkind ak = sRef_getAliasKind (u->sref);
  exkind ek = sRef_getExKind (u->sref);
  nstate ns = sRef_getNullState (u->sref);
  sstate ss = sRef_getDefState (u->sref);
  bool recordUnknown = FALSE;
  
  if (kind == AN_UNKNOWN)
    {
      ekind e = u->ukind;

      if (e == KENDITER)
	{
	  return;
	}
      else if (e == KCONST || e == KENUMCONST)
	{
	  kind = AN_CONST;
	}
      else if (e == KFCN || e == KITER)
	{
	  uentryList params = uentry_getParams (u);
	  bool hasRet = FALSE;

	  uentryList_elements (params, current)
	    {
	      if (uentry_isReturned (current))
		{
		  hasRet = TRUE;
		}
	      if (!uentry_isElipsisMarker (current))
		{
		  uentry_tallyAnnots (current, AN_FCNPARAM);
		}
	    } end_uentryList_elements;
	  
	  kind = AN_FCNRETURN;
	  
	  if (ctype_isFunction (u->utype)
	      && !hasRet
	      && ctype_isVisiblySharable (ctype_realType (ctype_getReturnType (u->utype))))
	    {
	      recordUnknown = TRUE;
	    }
	}
      else if (e == KDATATYPE || e == KSTRUCTTAG || e == KUNIONTAG || e == KENUMTAG)
	{
	  ctype t = ctype_realType (u->utype);

	  if (ctype_isSU (t))
	    {
	      uentryList fields = ctype_getFields (t);

	      uentryList_elements (fields, current)
		{
		  uentry_tallyAnnots (current, AN_SUFIELD);
		}
	    } end_uentryList_elements;
	  
	  kind = AN_TDEFN;

	  if (ctype_isVisiblySharable (u->utype))
	    {
	      recordUnknown = TRUE;
	    }
	}
      else 
	{
	  kind = AN_GSVAR;
	  
	  
	  if (ctype_isVisiblySharable (ctype_realType (u->utype)))
	    {
	      recordUnknown = TRUE;
	    }
	}
    }

  decls[kind]++;

  if (kind == AN_FCNRETURN)
    {
      if (recordUnknown) 
	{
	  shdecls[kind]++;
	  idecls[kind]++;
	}
      else 
	{
	  ;
	}
    }
  else
    {
      if (ctype_isVisiblySharable (ctype_realType (u->utype)))
	{
	  shdecls[kind]++;
	  	}
      
      if (ctype_isRealPointer (ctype_realType (u->utype)))
	{
	  idecls[kind]++;
	}
    }
  
  switch (ss)
    {
    case SS_ALLOCATED: tallyAnnot (kind, QU_OUT); break;
    case SS_PARTIAL:   tallyAnnot (kind, QU_PARTIAL); break;
    case SS_RELDEF:    tallyAnnot (kind, QU_RELDEF); break;
    case SS_SPECIAL:   tallyAnnot (kind, QU_SPECIAL); break;
    default: break;
    }

  if (uentry_isReturned (u))
    {
      tallyAnnot (kind, QU_RETURNED); 
    }

  switch (ak)
    {
    case AK_UNKNOWN:    
      if (ctype_isRefCounted (ctype_realType (u->utype))
	  || (ctype_isFunction (u->utype) &&
	      ctype_isRefCounted (ctype_realType (ctype_getReturnType (u->utype)))))
	{
	  ;
	}
      else
	{
	  if (kind == AN_FCNPARAM) 
	    { 
	      tallyAnnot (kind, QU_TEMP); 
	    } 
	  else if (recordUnknown) 
	    { 
	      if (kind == AN_FCNRETURN)
		{
		  		}
	      tallyAnnot (kind, QU_UNKNOWN); 
	    }
	}
      break;
    case AK_ONLY:       tallyAnnot (kind, QU_ONLY); break;
    case AK_IMPONLY:    tallyAnnot (kind, QU_ONLY); break;
    case AK_KEEP:       tallyAnnot (kind, QU_KEEP); break;
    case AK_KEPT:       tallyAnnot (kind, QU_KEPT); break;
    case AK_IMPTEMP:
    case AK_TEMP:       tallyAnnot (kind, QU_TEMP); break;
    case AK_SHARED:     tallyAnnot (kind, QU_SHARED); break;
    case AK_UNIQUE:     tallyAnnot (kind, QU_UNIQUE); break;
    case AK_RETURNED:   tallyAnnot (kind, QU_RETURNED); break;
    case AK_REFCOUNTED: tallyAnnot (kind, QU_UNKNOWN); break;
    case AK_REFS:       tallyAnnot (kind, QU_REFS); break;
    case AK_KILLREF:    tallyAnnot (kind, QU_KILLREF); break;
    case AK_NEWREF:     tallyAnnot (kind, QU_NEWREF); break;
    case AK_OWNED:      tallyAnnot (kind, QU_OWNED); break;
    case AK_IMPDEPENDENT:
    case AK_DEPENDENT:  tallyAnnot (kind, QU_DEPENDENT); break;
    case AK_ERROR:    
    case AK_FRESH:
    case AK_STACK:
    case AK_LOCAL:
      break;
    }

  switch (ek)
    {
    case XO_EXPOSED:    tallyAnnot (kind, QU_EXPOSED); break;
    case XO_OBSERVER:   tallyAnnot (kind, QU_OBSERVER); break;
    default:  break;
    }

  switch (ns)
    {
    case NS_ERROR:   break;
    case NS_UNKNOWN:   break;
    case NS_NOTNULL:   break;
    case NS_MNOTNULL:  tallyAnnot (kind, QU_NOTNULL); break;
    case NS_RELNULL:   tallyAnnot (kind, QU_RELNULL); break;
    case NS_CONSTNULL: tallyAnnot (kind, QU_NULL); break;
    case NS_POSNULL:   tallyAnnot (kind, QU_NULL); break;
    case NS_DEFNULL: 
    case NS_ABSNULL:   break;   
    }
}

# endif

static /*@observer@*/ cstring specCode_unparse (specCode s) /*@*/
{
  switch (s)
    {
    case SPC_NONE: return cstring_makeLiteralTemp ("normal");
    case SPC_PRINTFLIKE: return cstring_makeLiteralTemp ("printflike");
    case SPC_SCANFLIKE: return cstring_makeLiteralTemp ("scanflike");
    case SPC_MESSAGELIKE: return cstring_makeLiteralTemp ("messagelike");
    case SPC_LAST: return cstring_makeLiteralTemp ("<error>");
    }

  BADEXIT;
}

static specCode specCode_fromInt (int i)
{
  /*@+enumint@*/
  llassert (i >= SPC_NONE && i < SPC_LAST);

  return ((specCode) i);
  /*@=enumint@*/
}

/*@observer@*/ cstring uentry_specOrDefName (uentry u) 
{
  if (uentry_isDeclared (u))
    {
      return cstring_makeLiteralTemp ("previously declared");
    }
  else
    {
      return cstring_makeLiteralTemp ("specified");
    }
}

/*@observer@*/ cstring uentry_specDeclName (uentry u) 
{
  if (uentry_isDeclared (u))
    {
      return cstring_makeLiteralTemp ("previous declaration");
    }
  else
    {
      return cstring_makeLiteralTemp ("specification");
    }
}

static /*@observer@*/ cstring uentry_reDefDecl (uentry old, uentry unew)  /*@*/ 
{
  if (uentry_isCodeDefined (old) && uentry_isCodeDefined (unew))
    {
      return cstring_makeLiteralTemp ("redefined");
    }
  else if (uentry_isCodeDefined (unew))
    {
      return cstring_makeLiteralTemp ("defined");
    }
  else if (uentry_isDeclared (old) && uentry_isDeclared (unew))
    {
      return cstring_makeLiteralTemp ("redeclared");
    }
  else
    {
      return cstring_makeLiteralTemp ("declared");
    }
}

static constraintList uentry_getFunctionConditions (uentry ue, bool isPost)
{
  if (uentry_isValid (ue))
    {
      functionConstraint constraint;

      DPRINTF((message ("called uentry_getFcnPostconditions on  %s",
			 uentry_unparse (ue) ) ) );
      
      if (uentry_isVariable (ue) && ctype_isFunction (uentry_getType (ue)))
	{
	  DPRINTF((message ("called uentry_getFunctionConditions on nonfunction %s",
			     uentry_unparse (ue) ) ) );
	  if (!uentry_isFunction (ue) )
	    {
	      DPRINTF((message ("called uentry_getFunctionConditions on nonfunction %s",
				uentry_unparse (ue) ) ));
	      return constraintList_undefined;
	    }
	  
	  
	  return constraintList_undefined;
	}
      
      if (!uentry_isFunction(ue))
	{
	  
	  DPRINTF((message ("called uentry_getFunctionConditions on non function  %s",
			     uentry_unparse (ue) ) ) );
	  return constraintList_undefined;
	  
	}

      llassert (uentry_isFunction (ue));

      if (isPost)
	{
	  constraint = ue->info->fcn->postconditions;
	}
      else
	{
	  constraint = ue->info->fcn->preconditions;
	}

      return functionConstraint_getBufferConstraints (constraint);
    }
  
  return constraintList_undefined;
  
}

/*drl7x*/
/*@only@*/ constraintList uentry_getFcnPreconditions (uentry ue)
{
  return uentry_getFunctionConditions (ue, FALSE);
}

/*drl
  12/28/2000
*/

constraintList uentry_getFcnPostconditions (uentry ue)
{
  return uentry_getFunctionConditions (ue, TRUE);
}

static /*@only@*/ fileloc setLocation (void)
{
  fileloc fl = context_getSaveLocation ();

  if (fileloc_isDefined (fl)) 
    {
      return fl;
    }
  else
    {
      return fileloc_copy (g_currentloc);
    }
}

static void uentry_setConstantValue (uentry ue, /*@only@*/ multiVal val)
{
  llassert (uentry_isEitherConstant (ue));
  sRef_setValue (ue->sref, val);
}

/*@notnull@*/ uentry uentry_makeEnumConstant (cstring n, ctype t)
{
  fileloc loc = setLocation ();
  uentry ue = uentry_makeConstant (n, t, loc);

  ue->ukind = KENUMCONST;
  uentry_setDefined (ue, loc);
  return ue;
}

/*@notnull@*/ uentry uentry_makeEnumInitializedConstant (cstring n, ctype t, exprNode expr)
{
  fileloc loc = setLocation ();
  uentry ue = uentry_makeConstant (n, t, loc);
  ctype etype = exprNode_getType (expr);

  if (!ctype_isRealInt (etype)) {
    voptgenerror 
      (FLG_ENUMMEMBERS,
       message
       ("Value of enum member is not an integeral type (type %s): %s",
	ctype_unparse (etype), exprNode_unparse (expr)),
       exprNode_loc (expr));
  }
  
  ue->ukind = KENUMCONST;
  uentry_setDefined (ue, loc);
  return ue;
}

# ifndef NOLCL
/*@notnull@*/ uentry uentry_makeSpecEnumConstant (cstring n, ctype t, fileloc loc)
{
  uentry ue = uentry_makeConstant (n, t, loc);

  ue->ukind = KENUMCONST;
  return ue;
}
# endif

/*@notnull@*/ uentry uentry_makeVariableLoc (cstring n, ctype t)
{
  return uentry_makeVariable (n, t, setLocation (), FALSE);
}

# ifndef NOLCL
/*@notnull@*/ /*@only@*/ uentry uentry_makeUnnamedVariable (ctype t)
{
  return uentry_makeVariable (cstring_undefined, t, setLocation (), FALSE);
}
# endif

/*@notnull@*/ uentry uentry_makeIdDatatype (idDecl id)
{
  ctype ct = idDecl_getCtype (id);
  uentry ue = uentry_makeDatatype (idDecl_observeId (id), ct, 
				   MAYBE, MAYBE, setLocation ());

  uentry_reflectQualifiers (ue, idDecl_getQuals (id));
  
  if (!ynm_isOn (ue->info->datatype->abs))
    {
      if (ctype_isUnknown (ct))
	{
	  ue->info->datatype->mut = MAYBE;
	}
      else
	{
	  ue->info->datatype->mut = ynm_fromBool (ctype_isMutable (ct));
	}
    }
  
  return ue;
}

void uentry_checkParams (uentry ue)
{
  if (uentry_isValid (ue))
    {
      bool isExt = uentry_isExtern (ue);

      if (uentry_isRealFunction (ue))
	{
	  uentryList params = uentry_getParams (ue);

	  uentryList_elements (params, current)
	    {
	      if (uentry_isValid (current))
		{
		  ctype ct = current->utype;		      
		  
		  if (ctype_isFixedArray (ct))
		    {
		      if (ctype_isArray (ctype_baseArrayPtr (ct))
			  && !ctype_isFixedArray (ctype_baseArrayPtr (ct)))
			{
			  ;
			}
		      else
			{
			  voptgenerror 
			    (FLG_FIXEDFORMALARRAY,
			     message ("Function parameter %q declared as "
				      "manifest array (size constant is meaningless)",
				      uentry_getName (current)),
			     uentry_whereDeclared (current));
			}
		    }
		  else 
		    {
		      if (ctype_isArray (ct))
			{
			  voptgenerror 
			    (FLG_FORMALARRAY,
			     message ("Function parameter %q declared as "
				      "array (treated as pointer)", 
				      uentry_getName (current)),
			     uentry_whereDeclared (current));
			}
		    }

		  if (sRef_getNullState (uentry_getSref (current)) == NS_MNOTNULL)
		    {
		      if (ctype_isAbstract (ct) && 
			  (isExt || (ctype_isAbstract (ctype_realType (ct))
				     && !context_hasFileAccess (ctype_typeId (ct)))))
			{
			  vgenhinterror 
			    (FLG_INCONDEFS,
			     message 
			     ("Function %q declared with notnull parameter %q of abstract "
			      "type %s",
			      uentry_getName (ue),
			      uentry_getName (current),
			      ctype_unparse (ct)),
			     message 
			     ("Since %s is an abstract type, notnull can only be "
			      "used for parameters if the function is static to a "
			      "module where %s is accessible.",
			      ctype_unparse (ct),
			      ctype_unparse (ct)),
			     uentry_whereDeclared (current));
			}
		    }
		}
	    } end_uentryList_elements;
	  
	  if (sRef_getNullState (uentry_getSref (ue)) == NS_MNOTNULL)
	    {
	      ctype ct = ue->utype;
		  
	      if (ctype_isAbstract (ct) 
		  && (isExt || (ctype_isAbstract (ctype_realType (ct))
				&& !context_hasFileAccess (ctype_typeId (ct)))))
		{
		  vgenhinterror 
		    (FLG_INCONDEFS,
		     message 
		     ("%s %q declared %s notnull storage of abstract type %s",
		      ekind_capName (uentry_getKind (ue)),
		      uentry_getName (ue),
		      fcnErrName (ue),
		      ctype_unparse (ct)),
		     message 
		     ("Since %s is an abstract type, notnull can only be used "
		      "if it is static to a module where %s is accessible.",
		      ctype_unparse (ct),
		      ctype_unparse (ct)),
		     uentry_whereDeclared (ue));
		}
	    }
	}
    }
}

static void reflectImplicitFunctionQualifiers (/*@notnull@*/ uentry ue, bool spec)
{
  alkind ak = sRef_getAliasKind (ue->sref);

  if (alkind_isRefCounted (ak))
    {
      sRef_setAliasKind (ue->sref, AK_NEWREF, fileloc_undefined);
    }
  else 
    {
      if (alkind_isUnknown (ak))
	{
	  exkind ek = sRef_getExKind (ue->sref);
	  
	  if (exkind_isKnown (ek))
	    {
	      DPRINTF (("Setting imp dependent: %s",
			uentry_unparseFull (ue)));
	      sRef_setAliasKind (ue->sref, AK_IMPDEPENDENT, fileloc_undefined);
	    }
	  else 
	    {
	      if (context_getFlag (spec ? FLG_SPECRETIMPONLY : FLG_RETIMPONLY))
		{
		  /* evans 2000-12-22 removed ctype_realType so it will
		     not apply to immutable abstract types. */

		  if (ctype_isVisiblySharable 
		      (ctype_realType (ctype_getReturnType (ue->utype))))
		    {
		      if (uentryList_hasReturned (uentry_getParams (ue)))
			{
			  ;
			}
		      else 
			{
			  if (ctype_isImmutableAbstract (ctype_getReturnType (ue->utype))) 
			    {
			      ; /* Immutable objects are not shared. */
			    }
			  else
			    {
			      sRef_setAliasKind (ue->sref, AK_IMPONLY, 
						 fileloc_undefined);
			      DPRINTF (("Ret imp only: %s",
					ctype_unparse (ctype_getReturnType (ue->utype))));
			    }
			}
		    }
		}
	    }
	}
    }
}

static /*@notnull@*/ uentry 
uentry_makeFunctionAux (cstring n, ctype t, 
			typeIdSet access,
			/*@only@*/ globSet globs, 
			/*@only@*/ sRefSet mods,
			/*@only@*/ warnClause warn,
			/*@keep@*/ fileloc f, bool priv,
			/*@unused@*/ bool isForward)
{
  uentry e = uentry_alloc ();
  ctype ret;

  llassert (warnClause_isUndefined (warn)); /*@i325 remove parameter! */

  DPRINTF (("Make function: %s", n));

  if (ctype_isFunction (t))
    {
      ret = ctype_getReturnType (t);
    }
  else
    {
      if (ctype_isKnown (t))
	{
	  llbug (message ("not function: %s", ctype_unparse (t)));
	}
      ret = ctype_unknown;
    }

  e->ukind = KFCN;

  if (fileloc_isSpec (f) || fileloc_isImport (f))
    {
      e->whereSpecified = f;
      e->whereDeclared = fileloc_undefined;
    }
  else
    {
      e->whereSpecified = fileloc_undefined;
      e->whereDeclared = f;
    }

  /* e->shallowCopy = FALSE; */
  e->uname = cstring_copy (n);
  e->utype = t;
  e->storageclass = SCNONE;

  e->sref = sRef_makeResult (ret); /* evans 2001-07-19 - was sRef_makeType */

  DPRINTF (("Result: %s", sRef_unparseFull (e->sref)));

  if (ctype_isUA (ret))
    {
      sRef_setStateFromType (e->sref, ret);
    }
  
  e->used = FALSE;
  e->lset = FALSE;
  e->uses = filelocList_new ();
  e->isPrivate = priv;
  e->hasNameError = FALSE;

  e->warn = warn;

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->fcn = (ufinfo) dmalloc (sizeof (*e->info->fcn));

  e->info->fcn->hasMods = sRefSet_isDefined (mods);
  e->info->fcn->hasGlobs = globSet_isDefined (globs);

  e->info->fcn->exitCode = XK_UNKNOWN;
  e->info->fcn->nullPred = qual_createUnknown ();
  e->info->fcn->specialCode = SPC_NONE;

  e->info->fcn->access = access;
  e->info->fcn->globs = globs;
  e->info->fcn->defparams = uentryList_undefined;

  sRef_setDefined (e->sref, f);
  e->whereDefined = fileloc_undefined;
  
  e->info->fcn->mods = sRefSet_undefined;
  e->info->fcn->specclauses = NULL;

  /*drl 11 29 2000*/
  e->info->fcn->preconditions = NULL;
  /*end drl*/
  
  /*drl 12 28 2000*/
  e->info->fcn->postconditions = NULL;
  /*end drl*/
  
  checkGlobalsModifies (e, mods);
  e->info->fcn->mods = mods;

  return (e);
}

static void uentry_reflectClauses (uentry ue, functionClauseList clauses)
{
  functionClauseList_elements (clauses, el)
    {
      DPRINTF (("Reflect clause: %s on %s",
		functionClause_unparse (el), uentry_getName (ue)));
      
      if (functionClause_isNoMods (el))
	{
	  modifiesClause mel = functionClause_getModifies (el);
	  
	  if (uentry_hasGlobs (ue))
	    {
	      voptgenerror 
		(FLG_SYNTAX,
		 message
		 ("No globals and modifies inconsistent to globals clause for %q: %q",
		  uentry_getName (ue),
		  globSet_unparse (uentry_getGlobs (ue))),
		 modifiesClause_getLoc (mel));
	      
	    }

	  if (uentry_hasMods (ue))
	    {
	      voptgenerror 
		(FLG_SYNTAX,
		 message
		 ("No globals and modifies inconsistent to modifies clause for %q: %q",
		  uentry_getName (ue),
		  sRefSet_unparse (uentry_getMods (ue))),
		 modifiesClause_getLoc (mel));
	    }

	  uentry_setGlobals (ue, globSet_undefined);
	  uentry_setModifies (ue, sRefSet_undefined);
	}
      else if (functionClause_isGlobals (el))
	{
	  globalsClause glc = functionClause_getGlobals (el);
	  
	  DPRINTF (("Globals: %s / %s", uentry_unparse (ue),
		    globalsClause_unparse (glc)));

	  if (uentry_hasGlobs (ue))
	    {
	      voptgenerror 
		(FLG_SYNTAX,
		 message
		 ("Multiple globals clauses for %q: %q",
		  uentry_getName (ue),
		  globalsClause_unparse (glc)),
		 globalsClause_getLoc (glc));
	      uentry_setGlobals (ue, globalsClause_takeGlobs (glc)); /*@i32@*/
	    }
	  else
	    {
	      DPRINTF (("Taking globs: %s", globalsClause_unparse (glc)));
	      uentry_setGlobals (ue, globalsClause_takeGlobs (glc));
	      DPRINTF (("Taking globs after: %s", globalsClause_unparse (glc)));
	    }
	}
      else if (functionClause_isModifies (el))
	{
	  modifiesClause mlc = functionClause_getModifies (el);

	  DPRINTF (("Has modifies: %s", uentry_unparseFull (ue)));

	  if (uentry_hasMods (ue))
	    {
	      /* 
	      ** Not an error:

	      if (optgenerror 
		  (FLG_SYNTAX,
		   message
		   ("Multiple modifies clauses for %s: %s",
		    uentry_getName (ue),
		    modifiesClause_unparse (mlc)),
		   modifiesClause_getLoc (mlc)))
		{
		  llhint (message ("Previous modifies clause: ", 
				   sRefSet_unparse (uentry_getMods (ue))));
		}

	      **
	      */

	      uentry_combineModifies (ue, modifiesClause_takeMods (mlc)); /*@i32@*/
	    }
	  else
	    {
	      uentry_setModifies (ue, modifiesClause_takeMods (mlc));
	    }
	}
      else if (functionClause_isEnsures (el))
	{
	  functionConstraint cl = functionClause_takeEnsures (el);
	  DPRINTF (("Setting post: %s / %s",
		    uentry_unparse (ue), functionConstraint_unparse (cl)));
	  uentry_setPostconditions (ue, cl);
	}
      else if (functionClause_isRequires (el))
	{
	  functionConstraint cl = functionClause_takeRequires (el);
	  uentry_setPreconditions (ue, cl);
	}
      else if (functionClause_isState (el))
	{
	  stateClause sc = functionClause_takeState (el);

	  if (stateClause_isBefore (sc) && stateClause_setsMetaState (sc))
	    {
	      sRefSet rfs = stateClause_getRefs (sc);

	      sRefSet_elements (rfs, s)
		{
		  if (sRef_isParam (s))
		    {
		      /* 
		      ** Can't use requires on parameters
		      */
		      
		      voptgenerror
			(FLG_ANNOTATIONERROR,
			 message ("Requires clauses for %q concerns parameters %q should be "
				  "a parameter annotation instead: %q",
				  uentry_unparse (ue),
				  sRef_unparse (s),
				  stateClause_unparse (sc)),
			 stateClause_loc (sc));
		    }
		} end_sRefSet_elements ;
	    }

	  DPRINTF (("State clause: %s", stateClause_unparse (sc)));
	  uentry_addStateClause (ue, sc);
	}
      else if (functionClause_isWarn (el))
	{
	  warnClause wc = functionClause_takeWarn (el);
	  uentry_addWarning (ue, wc);
	}
      else 
	{
	  DPRINTF (("Unhandled clause: %s", functionClause_unparse (el)));
	}
    } end_functionClauseList_elements ;

  DPRINTF (("Checking all: %s", sRef_unparseFull (ue->sref)));
  stateClauseList_checkAll (ue);
}

/*@notnull@*/ uentry uentry_makeIdFunction (idDecl id)
{
  bool leaveFunc = FALSE;
  uentry ue = 
    uentry_makeFunction (idDecl_observeId (id), idDecl_getCtype (id), 
			 typeId_invalid, globSet_undefined, 
			 sRefSet_undefined, warnClause_undefined,
			 setLocation ());

  DPRINTF (("Id function: %s", sRef_unparseFull (ue->sref)));

  /*
  ** This makes parameters names print out correctly.
  ** (But we might be a local variable declaration for a function type...)
  */

  if (context_inFunctionLike ())
    {
      DPRINTF (("Header: %s / %s",
		uentry_unparse (context_getHeader ()),
		idDecl_unparse (id)));
    }
  else
    {
      context_enterFunctionDeclaration (ue);
      leaveFunc = TRUE;
    }

  DPRINTF (("Id function: %s", sRef_unparseFull (ue->sref)));
  uentry_reflectQualifiers (ue, idDecl_getQuals (id));
  DPRINTF (("Id function: %s", sRef_unparseFull (ue->sref)));
  reflectImplicitFunctionQualifiers (ue, FALSE);
  DPRINTF (("Id function: %s", sRef_unparseFull (ue->sref)));
  uentry_reflectClauses (ue, idDecl_getClauses (id));
  DPRINTF (("Id function: %s", sRef_unparseFull (ue->sref)));

  if (!uentry_isStatic (ue)
      && cstring_equalLit (ue->uname, "main"))
    {
      ctype typ = ue->utype;
      ctype retval;
      uentryList args;

      llassert (ctype_isFunction (typ));

      retval = ctype_getReturnType (typ);

      if (!ctype_isInt (retval))
	{
	  voptgenerror 
	    (FLG_MAINTYPE,
	     message ("Function main declared to return %s, should return int",
		      ctype_unparse (retval)),
	     uentry_whereDeclared (ue));
	}

      args = ctype_argsFunction (typ);

      if (uentryList_isMissingParams (args) 
	  || uentryList_size (args) == 0)
	{
	  ;
	}
      else
	{
	  if (uentryList_size (args) != 2)
	    {
	      voptgenerror 
		(FLG_MAINTYPE,
		 message ("Function main declared with %d arg%&, "
			  "should have 2 (int argc, char *argv[])",
			  uentryList_size (args)),
		 uentry_whereLast (ue));
	    }
	  else
	    {
	      uentry arg = uentryList_getN (args, 0);
	      ctype ct = uentry_getType (arg);

	      if (!ctype_isInt (ct))
		{
		  voptgenerror 
		    (FLG_MAINTYPE,
		     message ("Parameter 1, %q, of function main declared "
			      "with type %t, should have type int",
			      uentry_getName (arg), ct),
		     uentry_whereDeclared (arg));
		}

	      arg = uentryList_getN (args, 1);
	      ct = uentry_getType (arg);

	      if (ctype_isArrayPtr (ct)
		  && ctype_isArrayPtr (ctype_baseArrayPtr (ct))
		  && ctype_isChar (ctype_baseArrayPtr (ctype_baseArrayPtr (ct))))
		{
		  ;
		}
	      else
		{
		  voptgenerror 
		    (FLG_MAINTYPE,
		     message ("Parameter 2, %q, of function main declared "
			      "with type %t, should have type char **",
			      uentry_getName (arg), ct),
		     uentry_whereDeclared (arg));
		}
	    }
	}
    }

  if (leaveFunc)
    {
      context_exitFunctionDeclaration ();
    }

  return ue;
}

static void uentry_implicitParamAnnots (/*@notnull@*/ uentry e)
{
  alkind ak = sRef_getAliasKind (e->sref);

  if ((alkind_isUnknown (ak) || alkind_isImplicit (ak))
      && context_getFlag (FLG_PARAMIMPTEMP))
    {
      exkind ek = sRef_getExKind (e->sref);
      
      if (exkind_isKnown (ek))
	{
	  DPRINTF (("imp dep: %s", uentry_unparseFull (e)));
	  sRef_setAliasKind (e->sref, AK_IMPDEPENDENT, fileloc_undefined);
	  sRef_setOrigAliasKind (e->sref, AK_IMPDEPENDENT);
	}
      else
	{
	  sRef_setAliasKind (e->sref, AK_IMPTEMP, fileloc_undefined);
	  sRef_setOrigAliasKind (e->sref, AK_IMPTEMP);
	}
    }
}

static /*@only@*/ /*@notnull@*/ uentry 
uentry_makeVariableParamAux (cstring n, ctype t, /*@dependent@*/ sRef s, 
			     /*@only@*/ fileloc loc, sstate defstate) /*@i32 exposed*/
{
  cstring pname = makeParam (n);
  uentry e;

  DPRINTF (("Sref: %s", sRef_unparseFull (s)));
  e = uentry_makeVariableAux (pname, t, loc, s, FALSE, VKPARAM);

  cstring_free (pname);
  DPRINTF (("Param: %s", uentry_unparseFull (e)));
  uentry_implicitParamAnnots (e);
  DPRINTF (("Param: %s", uentry_unparseFull (e)));

  if (!sRef_isAllocated (e->sref) && !sRef_isPartial (e->sref))
    {
      DPRINTF (("Param: %s", uentry_unparseFull (e)));
      sRef_setDefState (e->sref, defstate, uentry_whereDeclared (e));
      e->info->var->defstate = defstate;
    }

  DPRINTF (("Param: %s", uentry_unparseFull (e)));
  return (e);
}

# ifndef NOLCL
void
uentry_setRefCounted (uentry e)
{
  if (uentry_isValid (e))
    {
      uentry_setAliasKind (e, AK_REFCOUNTED);
      sRef_storeState (e->sref);
    }
}
# endif

void
uentry_setStatic (uentry c)
{
  if (uentry_isValid (c)) 
    {
      alkind ak = sRef_getAliasKind (c->sref);
      c->storageclass = SCSTATIC;

      if (uentry_isVariable (c) && !ctype_isFunction (uentry_getType (c)))
	{
	  if (!alkind_isUnknown (ak)
	      && !alkind_isStatic (ak))
	    {
	      if  (!(ctype_isRealPointer (uentry_getType (c)))
		   && !(ctype_isAbstract (ctype_realType (uentry_getType (c))))
		   && !alkind_isRefCounted (ak))
		{
		  if (alkind_isImplicit (ak)
		      && alkind_isDependent (ak)
		      && ctype_isArray (uentry_getType (c)))
		    {
		      ; /* no error for observer arrays */
		    }
		  else
		    {
		      voptgenerror 
			(FLG_INCONDEFS,
			 message ("Static storage %q declared as %s",
				  uentry_getName (c),
				  alkind_unparse (ak)),
			 uentry_whereDeclared (c));
		    }
		}
	    }
	  else
	    {
	      if (alkind_isUnknown (ak)
		  || (alkind_isImplicit (sRef_getAliasKind (c->sref))
		      && !alkind_isDependent (sRef_getAliasKind (c->sref))))
		{
		  sRef_setAliasKind (c->sref, AK_STATIC, fileloc_undefined);
		  sRef_setOrigAliasKind (c->sref, AK_STATIC);
		}
	    }
	}
    }
}

void
uentry_setExtern (uentry c)
{
  if (uentry_isValid (c)) 
    c->storageclass = SCEXTERN;
}

void
uentry_setParamNo (uentry ue, int pno)
{
  llassert (uentry_isAnyParam (ue) && sRef_isParam (ue->sref));
  sRef_setParamNo (ue->sref, pno);
}

static
void checkGlobalsModifies (/*@notnull@*/ uentry ue, sRefSet sr)
{
  sRefSet_allElements (sr, el)
    {
      sRef base = sRef_getRootBase (el);
      
      if (sRef_isFileOrGlobalScope (base) || sRef_isInternalState (base)
	  || (sRef_isKindSpecial (base) && !sRef_isNothing (base)))
	{
	  if (!globSet_member (ue->info->fcn->globs, base))
	    {
	      if (uentry_hasGlobs (ue)
		  || context_getFlag (FLG_WARNMISSINGGLOBALSNOGLOBS))
		{
		  if (optgenerror 
		      (FLG_WARNMISSINGGLOBALS,
		       message
		       ("Modifies list for %q uses global %q, "
			"not included in globals list.",
			uentry_getName (ue),
			sRef_unparse (base)),
		       uentry_whereLast (ue)))
		    {
		      uentry_showWhereSpecified (ue);
		    } 
		}
	      
	      ue->info->fcn->globs = globSet_insert (ue->info->fcn->globs, 
						     base);
	      if (sRef_isFileStatic (base))
		{
		  context_recordFileGlobals (ue->info->fcn->globs);
		}
	    }
	}
    } end_sRefSet_allElements;
}

uentry
uentry_makeVariableSrefParam (cstring n, ctype t, /*@only@*/ fileloc loc, /*@exposed@*/ sRef s)
{
  return (uentry_makeVariableParamAux (n, t, s, loc, SS_UNKNOWN));
}

void
uentry_fixupSref (uentry ue)
{
  sRef sr;
  
  if (uentry_isUndefined (ue) || uentry_isElipsisMarker (ue)) 
    {
      return;
    }
  
  sr = uentry_getSref (ue);

  sRef_resetState (sr);
  sRef_clearDerived (sr);
  
  llassertprint (uentry_isVariable (ue), ("fixing: %s", uentry_unparseFull (ue)));
  llassert (sRef_isValid (sr)); 
  
  if (uentry_isVariable (ue))
    {
      /*@i634 	  ue->sref = sRef_saveCopyShallow (ue->info->var->origsref); */
      sRef_setDefState (sr, ue->info->var->defstate, fileloc_undefined);
      sRef_setNullState (sr, ue->info->var->nullstate, fileloc_undefined);
    }
}

static void uentry_addStateClause (uentry ue, stateClause sc)
{
  /*
  ** Okay to allow multiple clauses of the same kind.
  */ /*@i834 is this true?@*/

  ue->info->fcn->specclauses = 
    stateClauseList_add (ue->info->fcn->specclauses, sc);

  /* Will call checkAll to check later... */
}

void uentry_setStateClauseList (uentry ue, stateClauseList clauses)
{
  llassert (uentry_isFunction (ue));
  llassert (!stateClauseList_isDefined (ue->info->fcn->specclauses));

  DPRINTF (("checked clauses: %s", stateClauseList_unparse (clauses)));
  ue->info->fcn->specclauses = clauses;
  stateClauseList_checkAll (ue);
  DPRINTF (("checked clauses: %s", uentry_unparseFull (ue)));
}

/*
** Used for @modifies@ @endmodifies@ syntax.
**
** If ue is specified, sr must contain *only*:
**
**      o file static globals
**      o sRef's derived from modifies spec (i.e., more specific than
**        what was specified)
**
** Otherwise, if sr has modifies it must match sr.
**
** If it doesn't have modifies, set them to sr.
*/

static bool
uentry_checkModifiesContext (void) 
{
  if (sRef_modInFunction ())
    {
      llparseerror
	(message
	 ("Modifies list not in function context.  "
	  "A modifies list can only appear following the parameter list "
	  "in a function declaration or header."));
      
      return FALSE;
    }
  
  return TRUE;
}

void
uentry_setModifies (uentry ue, /*@owned@*/ sRefSet sr)
{
  if (!uentry_checkModifiesContext ())
    {
      sRefSet_free (sr);
      return;
    }

  if (uentry_isValid (ue))
    {
      if (uentry_isIter (ue))
	{
	  llassert (sRefSet_isUndefined (ue->info->iter->mods));
	  ue->info->iter->mods = sr;
	}
      else
	{
	  uentry_convertVarFunction (ue);
	  llassertfatal (uentry_isFunction (ue));
	  llassert (sRefSet_isUndefined (ue->info->fcn->mods));
	  
	  ue->info->fcn->mods = sr;
	  ue->info->fcn->hasMods = TRUE;
	  
	  checkGlobalsModifies (ue, sr);
	}
      
      if (context_getFlag (FLG_MODIFIESIMPNOGLOBALS))
	{
	  ue->info->fcn->hasGlobs = TRUE;
	}

      if (sRefSet_hasStatic (ue->info->fcn->mods))
	{
	  context_recordFileModifies (ue->info->fcn->mods);
	}
    }
  else
    {
      sRefSet_free (sr);
    }
}

static void
uentry_combineModifies (uentry ue, /*@owned@*/ sRefSet sr)
{
  /* 
  ** Function already has one modifies clause (possibly from
  ** a specification).
  */

  if (!uentry_checkModifiesContext ())
    {
      BADBRANCH;
    }
  
  llassert (uentry_isValid (ue));

  if (uentry_isIter (ue))
    {
      ue->info->iter->mods = sRefSet_unionFree (ue->info->iter->mods, sr);
    }
  else
    {
      llassertfatal (uentry_isFunction (ue));
      llassert (ue->info->fcn->hasMods);
      
      checkGlobalsModifies (ue, sr);
      ue->info->fcn->mods = sRefSet_unionFree (ue->info->fcn->mods, sr);
      
      if (context_getFlag (FLG_MODIFIESIMPNOGLOBALS))
	{
	  ue->info->fcn->hasGlobs = TRUE;
	}
    }

  if (sRefSet_hasStatic (ue->info->fcn->mods))
    {
      context_recordFileModifies (ue->info->fcn->mods);
    }
}

bool uentry_hasWarning (uentry ue)
{
  return (uentry_isValid (ue)
	  && warnClause_isDefined (ue->warn));
}

void uentry_addWarning (uentry ue, /*@only@*/ warnClause warn)
{
  llassert (warnClause_isUndefined (ue->warn));
  ue->warn = warn;
}

void
uentry_setPreconditions (uentry ue, /*@only@*/ functionConstraint preconditions)
{
  if (sRef_modInFunction ())
    {
      llparseerror
	(message ("Precondition list not in function context.  "
		  "A precondition list can only appear following the parameter list "
		  "in a function declaration or header."));

      /*@-mustfree@*/ return; /*@=mustfree@*/ 
    }

  if (uentry_isValid (ue))
    {
      uentry_convertVarFunction (ue);
      llassertfatal (uentry_isFunction (ue));
      
      if (functionConstraint_isDefined (ue->info->fcn->preconditions))
	{
	  /* drl 11-29-2002
	     I changed this so it didn't appear as a Splint bug
	     among other things this gets triggered when there is
	     a function with two requires clauses.  Now Splint
	     prints an error and tries to conjoin the lists.
	  */
      llparseerror
	(message ("Duplicate precondition list"
		  "Attemping the conjoin the requires clauses"
		  ));


	  /* should conjoin constraints? */
	  /*@notreached@*/ 
	  ue->info->fcn->preconditions = functionConstraint_conjoin (ue->info->fcn->preconditions, preconditions);
	}
      else
	{
	  ue->info->fcn->preconditions = preconditions;
	}
    }
  else
    {
      llfatalbug ((message("uentry_setPreconditions called with invalid uentry") ));
    }
}

/*
  drl
  added 12/28/2000
*/
void
uentry_setPostconditions (uentry ue, /*@only@*/ functionConstraint postconditions)
{
  if (sRef_modInFunction ())
    {
      llparseerror
	(message ("Postcondition list not in function context.  "
		  "A postcondition list can only appear following the parameter list "
		  "in a function declaration or header."));
      
      /*@-mustfree@*/ return; /*@=mustfree@*/ 
    }

  if (uentry_isValid (ue))
    {
      uentry_convertVarFunction (ue);
      llassertfatal (uentry_isFunction (ue));
      
      if (functionConstraint_isUndefined (ue->info->fcn->postconditions))
	{
	  ue->info->fcn->postconditions = postconditions;
	}
      else
	{
	  ue->info->fcn->postconditions = functionConstraint_conjoin (ue->info->fcn->postconditions, postconditions);
	}	    
    }
  else
    {
      llfatalbug ((message("uentry_setPostconditions called with invalid uentry") ));
    }
}

/*
** requires: new and old are functions
*/
 
static void
checkGlobalsConformance (/*@notnull@*/ uentry old, 
			 /*@notnull@*/ uentry unew, 
			 bool mustConform, bool completeConform)
{
  bool hasInternalState = FALSE;

  old->info->fcn->hasGlobs |= unew->info->fcn->hasGlobs;

  if (globSet_isDefined (unew->info->fcn->globs))
    {
      globSet_allElements (unew->info->fcn->globs, el)
	{
	  if (sRef_isFileStatic (el))
	    {
	      sRef sr = globSet_lookup (old->info->fcn->globs, el);

	      if (sRef_isInvalid (sr))
		{
		  bool hasError = FALSE;

		  if (!hasInternalState 
		      && sRef_isInvalid (globSet_lookup (old->info->fcn->globs,
							 sRef_makeInternalState ()))
		      && sRef_isInvalid (globSet_lookup (old->info->fcn->globs,
							 sRef_makeSpecState ())))
		    {
		      if (mustConform 
			  && !uentry_isStatic (old)
			  && optgenerror 
			  (FLG_INCONDEFS,
			   message ("Globals list for %q includes internal state, %q, "
				    "but %s without globals internalState.",
				    uentry_getName (old),
				    sRef_unparse (el),
				    uentry_specOrDefName (old)),
			   uentry_whereLast (unew)))
			{
			  uentry_showWhereSpecified (old);
			  hasError = TRUE;
			}
		      
		      old->info->fcn->globs = globSet_insert (old->info->fcn->globs,
							      sRef_makeInternalState ());
		      hasInternalState = TRUE;
		    }

		  if (!hasError
		      && fileloc_sameFile (uentry_whereDeclared (unew),
					   uentry_whereDeclared (old)))
		    {
		      if (mustConform
			  && optgenerror 
			  (FLG_INCONDEFS,
			   message ("Function %q inconsistently %rdeclared (in "
				    "same file) with file static global %q in "
				    "globals list",
				    uentry_getName (unew),
				    uentry_isDeclared (old),
				    sRef_unparse (el)),
			   uentry_whereDeclared (unew)))
			{
			  uentry_showWhereSpecified (old);
			}
		    }
		}

	      old->info->fcn->globs = globSet_insert (old->info->fcn->globs, el);
	      context_recordFileGlobals (old->info->fcn->globs);
	    }
	  else
	    {
	      sRef sr = globSet_lookup (old->info->fcn->globs, el);
	      
	      if (sRef_isInvalid (sr))
		{
		  if (mustConform
		      && optgenerror 
		      (FLG_INCONDEFS,
		       message ("Function %q inconsistently %rdeclared with "
				"%q in globals list",
				uentry_getName (unew),
				uentry_isDeclared (old),
				sRef_unparse (el)),
		       uentry_whereDeclared (unew)))
		    {
		      old->info->fcn->globs = globSet_insert (old->info->fcn->globs, el);
		      uentry_showWhereSpecified (old);
		    }
		}
	      else
		{
		  if (!bool_equal (sRef_isAllocated (el), sRef_isAllocated (sr)))
		    {
		      if (mustConform
			  && optgenerror 
			  (FLG_INCONDEFS,
			   message 
			   ("Function %q global %q inconsistently "
			    "%rdeclared as %qout global",
			    uentry_getName (unew),
			    sRef_unparse (el),
			    uentry_isDeclared (old),
			    cstring_makeLiteral (sRef_isAllocated (el) ? "" : "non-")),
			   uentry_whereDeclared (unew)))
			{
			  uentry_showWhereSpecified (old);
			}
		    }
		}
	    }
	} end_globSet_allElements ;

      if (completeConform)
	{
	  globSet_allElements (old->info->fcn->globs, el)
	    {
	      sRef sr = globSet_lookup (unew->info->fcn->globs, el);
	      
	      if (sRef_isInvalid (sr))
		{
		  if (mustConform
		      && uentry_isReallySpecified (old)
		      && optgenerror 
		      (FLG_NEEDSPEC,
		       message ("Function %q specified with %q in globals list, "
				"but declared without %q",
				uentry_getName (unew),
				sRef_unparse (el),
				sRef_unparse (el)),
		       uentry_whereDeclared (unew)))
		    {
		      uentry_showWhereSpecified (old);
		    }
		}
	    } end_globSet_allElements;
	}
    }
  else
    {
      if (completeConform && !globSet_isEmpty (old->info->fcn->globs))
	{
	  if (uentry_isReallySpecified (old)
	      && optgenerror 
	      (FLG_NEEDSPEC,
	       message ("%s %q specified with globals list, but "
			"declared with no globals",
			ekind_capName (unew->ukind),
			uentry_getName (unew)),
	       uentry_whereDeclared (unew)))
	    {
	      llgenindentmsg 
		(message ("Specification globals: %q", 
			  globSet_unparse (old->info->fcn->globs)),
		 uentry_whereSpecified (old));
	    }
	}
      
      unew->info->fcn->globs = globSet_copyInto (unew->info->fcn->globs, 
						 old->info->fcn->globs);
    }
}

/*
** new modifies list must be included by old modifies list.
**
** file static state may be added to new, if old has internal.
*/

static void
checkModifiesConformance (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew, 
			  bool mustConform, bool completeConform)
{
  sRefSet newMods;
  bool changedMods = FALSE;
  bool modInternal = FALSE;

  llassert (uentry_isFunction (old) && uentry_isFunction (unew));

  old->info->fcn->hasMods |= unew->info->fcn->hasMods;
  newMods = unew->info->fcn->mods;
	    
  if (sRefSet_isEmpty (newMods))
    {
      if (completeConform && !sRefSet_isEmpty (old->info->fcn->mods)
	  && uentry_isReallySpecified (old))
	{
	  if (optgenerror 
	      (FLG_NEEDSPEC,
	       message ("%s %q specified with modifies clause, "
			"but declared with no modifies clause",
			ekind_capName (unew->ukind),
			uentry_getName (unew)),
	       uentry_whereDeclared (unew)))
	    {
	      llgenindentmsg (message ("Specification has modifies %q", 
				       sRefSet_unparse (old->info->fcn->mods)),
			      uentry_whereSpecified (old));
	    }
	}

      return;
    }

  sRefSet_allElements (newMods, current)
    {
      if (sRef_isValid (current))
	{
	  sRef rb = sRef_getRootBase (current);
	  
	  if (sRef_isFileStatic (rb))
	    {
	      if (!modInternal)
		{
		  if (!sRefSet_isSameMember (old->info->fcn->mods, 
					     sRef_makeInternalState ())
		      && !sRefSet_isSameMember (old->info->fcn->mods, 
						sRef_makeSpecState ()))
		    {
		      if (mustConform 
			  && !uentry_isStatic (old)
			  && optgenerror 
			  (FLG_INCONDEFS,
			   message
			   ("Modifies list for %q includes internal state, "
			    "but %s without modifies internal.",
			    uentry_getName (old),
			    uentry_specOrDefName (old)),
			   uentry_whereLast (unew)))
			{
			  uentry_showWhereSpecified (old);
			}
		      
		      old->info->fcn->mods = 
			sRefSet_insert (old->info->fcn->mods, 
					sRef_makeInternalState ());
		      modInternal = TRUE;
		    }
		}
	      
	      old->info->fcn->mods = sRefSet_insert (old->info->fcn->mods,
						     current);
	      changedMods = TRUE;
	    }
	  else
	    {
	      if (sRef_canModifyVal (current, old->info->fcn->mods))
		{
		  int size = sRefSet_size (old->info->fcn->mods);

		  old->info->fcn->mods = sRefSet_insert (old->info->fcn->mods,
							 current);

		  if (sRefSet_size (old->info->fcn->mods) != size)
		    {
		      changedMods = TRUE;
		    }
		}
	      else
		{
		  if (mustConform
		      && optgenerror 
		      (FLG_INCONDEFS,
		       message 
		       ("Modifies list for %q contains %q, not modifiable "
			"according to %s",
			uentry_getName (old),
			sRef_unparse (current),
			uentry_specDeclName (old)),
		       uentry_whereLast (unew)))
		    {
		      uentry_showWhereSpecified (old);
		    }
		}
	    }
	}
    } end_sRefSet_allElements;

  if (completeConform && uentry_isReallySpecified (old))
    {
      sRefSet_allElements (old->info->fcn->mods, el)
	{
	  if (sRef_canModify (el, newMods))
	    {
	      ; /* okay */
	    }
	  else
	    {
	      if (optgenerror 
		  (FLG_NEEDSPEC,
		   message 
		   ("Specification modifies clause for %q contains %q, "
		    "not included in declaration modifies clause",
		    uentry_getName (old),
		    sRef_unparse (el)),
		   uentry_whereLast (unew)))
		{
		  uentry_showWhereSpecified (old);
		}
	    }
	} end_sRefSet_allElements ;
    } 

  /*
  ** Make sure file static elements will be removed.
  */

  if (changedMods)
    {
      context_recordFileModifies (old->info->fcn->mods);
    }
}

static void 
  uentry_checkMutableType (uentry ue)
{
  ctype ct = uentry_getType (ue);

  if (!ctype_isRealPointer (ct) && !ctype_isRealAbstract (ct))
    {
      DPRINTF (("Check mutable: %s", uentry_unparseFull (ue)));

      voptgenerror (FLG_MUTREP,
		    message ("Mutable abstract type %q declared without pointer "
			     "indirection: %t (violates assignment semantics)",
			     uentry_getName (ue), ct),
		    uentry_whereDeclared (ue));
    }
}

void
uentry_setMutable (uentry e)
{
  llassert (uentry_isDatatype (e));
  e->info->datatype->mut = YES;
}

static void
uentry_checkIterArgs (uentry ue)
{
  bool hasYield = FALSE;
  uentryList args;

  llassert (uentry_isIter (ue));

  args = uentry_getParams (ue);

  uentryList_elements (args, el)
    {
      sstate ds = uentry_getDefState (el);

      if (uentry_isYield (el))
	{
	  hasYield = TRUE;
	}

      if (sstate_isUnknown (ds))
	{
	  uentry_setDefState (el, SS_DEFINED);
	}
      else
	{
	  ;
	}
    } end_uentryList_elements;

  if (!hasYield)
    {
      voptgenerror (FLG_HASYIELD,
		    message ("Iterator %q declared with no yield parameters",
			     uentry_getName (ue)),
		    uentry_whereDeclared (ue));
    }
}

static chkind
chkind_fromQual (qual qel)
{
  if (qual_isChecked (qel))
    {
      return CH_CHECKED;
    }
  else if (qual_isCheckMod (qel))
    {
      return CH_CHECKMOD;
    }
  else if (qual_isCheckedStrict (qel))
    {
      return CH_CHECKEDSTRICT;
    }
  else if (qual_isUnchecked (qel))
    {
      return CH_UNCHECKED;
    }
  else
    {
      BADEXIT;
      /*@notreached@*/ return CH_UNKNOWN;
    }
}

static void
uentry_reflectOtherQualifier (/*@notnull@*/ uentry ue, qual qel)
{
  if (qual_isKillRef (qel) || qual_isNewRef (qel) || qual_isTempRef (qel))
    {
      if (!uentry_isRefCounted (ue))
	{
	  voptgenerror
	    (FLG_ANNOTATIONERROR,
	     message ("Reference counting qualifier %s used on non-reference "
		      "counted storage: %q",
		      qual_unparse (qel), 
		      uentry_unparse (ue)),
	     uentry_whereLast (ue));
	}
      else
	{
	  alkind ak = alkind_fromQual (qel);
	  
	  uentry_setAliasKind (ue, ak);
	}
    }
  else if (qual_isRefCounted (qel))
    {
      ctype ct = ctype_realType (uentry_getType (ue));
      ctype rt;
      
      if (ctype_isPointer (ct) 
	  && (ctype_isStruct (rt = ctype_realType (ctype_baseArrayPtr (ct)))))
	{
	  /* check there is a refs field */
	  uentryList fields = ctype_getFields (rt);
	  uentry refs = uentry_undefined;

	  uentryList_elements (fields, field)
	    {
	      if (uentry_isRefsField (field))
		{
		  if (uentry_isValid (refs))
		    {
		      voptgenerror
			(FLG_ANNOTATIONERROR, 
			 message ("Reference counted structure type %s has "
				  "multiple refs fields: %q and %q",
				  ctype_unparse (ct),
				  uentry_getName (refs),
				  uentry_getName (field)),
			 uentry_whereLast (field));
		    }
		  
		  refs = field;
		}
	    } end_uentryList_elements;

	  if (uentry_isInvalid (refs))
	    {
	      vgenhinterror 
		(FLG_SYNTAX, 
		 message ("Reference counted structure type %s has "
			  "no refs field",
			  ctype_unparse (ct)),
		 cstring_makeLiteral
		 ("To count reference, the structure must have a field named "
		  "refs of type int."),
		 g_currentloc);		  
	    }
	  else if (!ctype_isInt (uentry_getType (refs)))
	    {
	      voptgenerror
		(FLG_ANNOTATIONERROR, 
		 message ("Reference counted structure type %s refs field has "
			  "type %s (should be int)", ctype_unparse (ct),
			  ctype_unparse (uentry_getType (refs))),
		 uentry_whereLast (refs));
	    }
	  else
	    {
	      sRef_setAliasKind (ue->sref, alkind_fromQual (qel), 
				 uentry_whereDeclared (ue));
	    }
	}
      else
	{
	  if ((ctype_isPointer (ct) 
	       && ctype_isUnknown (ctype_realType (ctype_baseArrayPtr (ct))))
	      ||ctype_isAbstract (ct) || ctype_isUnknown (ct))
	    {
	      sRef_setAliasKind (ue->sref, alkind_fromQual (qel), 
				 uentry_whereDeclared (ue));
	    }
	  else
	    {
	      voptgenerror
		(FLG_ANNOTATIONERROR, 
		 message ("Non-pointer to structure type %s declared with "
			  "refcounted qualifier",
			  ctype_unparse (ct)),
		 uentry_whereLast (ue));
	    }
	}
    }
  else if (qual_isRefs (qel))
    {
      if (uentry_isVariable (ue) && !uentry_isParam (ue))
	{
	  uentry_setAliasKind (ue, AK_REFS);
	}
      else
	{
	  voptgenerror 
	    (FLG_ANNOTATIONERROR,
	     message ("Refs qualifier used on non-structure field: %q",
		      uentry_unparse (ue)),
	     uentry_whereLast (ue));
	}
    }
  else if (qual_isAliasQual (qel))
    {
      alkind ak = alkind_fromQual (qel);
      bool okay = TRUE;
      alkind oldak = uentry_getAliasKind (ue);
      ctype ut = uentry_getType (ue);
      
      if (alkind_isImplicit (ak) 
	  && (alkind_isKnown (oldak) && !alkind_isImplicit (oldak)))
	{
	  /* ignore the implied qualifier */
	  okay = FALSE;
	}
      
      if (uentry_isEitherConstant (ue))
	{
	  voptgenerror 
	    (FLG_ANNOTATIONERROR, 
	     message ("Alias qualifier %s used on constant: %q",
		      alkind_unparse (ak), uentry_unparse (ue)),
	     uentry_whereLast (ue));

	  okay = FALSE;
	}
      
      if (ctype_isFunction (ut))
	{
	  ut = ctype_getReturnType (ut);
	}
      
      if (!(ctype_isVisiblySharable (ut) 
	    || ctype_isRealArray (ut)
	    || ctype_isRealSU (ut)))
	{
	  if (!qual_isImplied (qel))
	    {
	      voptgenerror
		(FLG_ANNOTATIONERROR, 
		 message ("Alias qualifier %s used on unsharable storage type %t: %q",
			  alkind_unparse (ak), ut, uentry_getName (ue)),
		 uentry_whereLast (ue));
	    }
	  
	  okay = FALSE;
	}
      else
	{
	  if (uentry_isRefCounted (ue))
	    {
	      if (!(qual_isRefQual (qel) || qual_isOnly (qel)
		    || qual_isExposed (qel) 
		    || qual_isObserver (qel)))
		{
		  if (!qual_isImplied (qel))
		    {
		      voptgenerror
			(FLG_ANNOTATIONERROR, 
			 message 
			 ("Alias qualifier %s used on reference counted storage: %q",
			  alkind_unparse (ak), 
			  uentry_unparse (ue)),
			 uentry_whereLast (ue));
		    }
		  
		  okay = FALSE;
		}
	    }
	  else
	    {
	      if (qual_isRefQual (qel))
		{
		  voptgenerror 
		    (FLG_ANNOTATIONERROR,
		     message ("Qualifier %s used on non-reference counted storage: %q",
			      alkind_unparse (ak), uentry_unparse (ue)),
		     uentry_whereLast (ue));
		  
		  okay = FALSE;
		}
	    }
	}
      
      if (okay)
	{
	  uentry_setAliasKind (ue, ak);
	}
    }
  else if (qual_isNull (qel))
    {
      if (uentry_isConstant (ue))
	{
	  sRef_setNullState 
	    (ue->sref, 
	     ctype_isAbstract (ue->utype) ? NS_CONSTNULL : NS_DEFNULL, 
	     uentry_whereDeclared (ue));
	}
      else
	{
	  uentry_setNullState (ue, NS_POSNULL);
	}
    }
  else if (qual_isRelNull (qel))
    {
      uentry_setNullState (ue, NS_RELNULL);
    }
  else if (qual_isNotNull (qel))
    {
      uentry_setNullState (ue, NS_MNOTNULL);
    }
  else if (qual_isAbstract (qel)
	   || qual_isConcrete (qel))
    {
      if (!uentry_isDatatype (ue))
	{
	  voptgenerror 
	    (FLG_ANNOTATIONERROR, 
	     message ("Qualifier %s used with non-datatype", 
		      qual_unparse (qel)),
	     uentry_whereLast (ue));
	}
      else
	{
	  ue->info->datatype->abs = ynm_fromBool (qual_isAbstract (qel));
	}
    }
  else if (qual_isMutable (qel))
    {
      if (!uentry_isDatatype (ue))
	{
	  voptgenerror
	    (FLG_ANNOTATIONERROR,
	     message ("Qualifier %s used with non-datatype", qual_unparse (qel)),
	     uentry_whereLast (ue));
	}
      else
	{
	  if (!ynm_isOn (ue->info->datatype->mut))
	    {
	      uentry_checkMutableType (ue);
	    }
	  
	  ue->info->datatype->mut = YES;
	}
    }
  else if (qual_isImmutable (qel))
    {
      if (!uentry_isDatatype (ue))
	{
	  voptgenerror (FLG_ANNOTATIONERROR, 
			message ("Qualifier %s used with non-datatype", 
				 qual_unparse (qel)),
			uentry_whereLast (ue));
	}
      else
	{
	  ue->info->datatype->mut = NO;
	}
    }
  else if (qual_isNullPred (qel))
    {
      uentry_convertVarFunction (ue);

      if (uentry_isFunction (ue))
	{
	  ctype typ = uentry_getType (ue);
	  ctype rtype = ctype_getReturnType (uentry_getType (ue));
	  
	  if (ctype_isRealBool (rtype))
	    {
	      uentryList pl = ctype_argsFunction (typ);
	      
	      if (uentryList_size (pl) == 1)
		{
		  ue->info->fcn->nullPred = qel;
		}
	      else
		{
		  voptgenerror (FLG_ANNOTATIONERROR,
				message ("Qualifier %s used with function having %d "
					 "arguments (should have 1)", 
					 qual_unparse (qel),
					 uentryList_size (pl)),
				uentry_whereLast (ue));
		}
	    }
	  else
	    {
	      voptgenerror (FLG_ANNOTATIONERROR,
			    message ("Qualifier %s used with function returning %s "
				     "(should return bool)", 
				     qual_unparse (qel),
				     ctype_unparse (rtype)),
			    uentry_whereLast (ue));
	    }
	}
      else
	{
	  voptgenerror (FLG_ANNOTATIONERROR,
			message ("Qualifier %s used with non-function", 
				 qual_unparse (qel)),
			uentry_whereLast (ue));
	}
    }
  else if (qual_isExitQual (qel))
    {
      exitkind exk = exitkind_fromQual (qel);
      
      if (uentry_isFunction (ue))
	{
	  if (exitkind_isKnown (ue->info->fcn->exitCode))
	    {
	      voptgenerror (FLG_ANNOTATIONERROR,
			    message ("Multiple exit qualifiers used on function %q:  %s, %s", 
				     uentry_getName (ue),
				     exitkind_unparse (ue->info->fcn->exitCode),
				     exitkind_unparse (exk)),
			    uentry_whereLast (ue));
	    }
	  
	  ue->info->fcn->exitCode = exk;
	}
      else
	{
	  if (uentry_isVariable (ue) && ctype_isFunction (uentry_getType (ue)))
	    {
	      uentry_makeVarFunction (ue);
	      ue->info->fcn->exitCode = exk;
	    }
	  else
	    {
	      voptgenerror (FLG_ANNOTATIONERROR,
			    message ("Exit qualifier %s used with non-function (type %s)", 
				     qual_unparse (qel),
				     ctype_unparse (uentry_getType (ue))),
			    uentry_whereLast (ue));
	    }
	}
    }
  else if (qual_isMetaState (qel)) 
    {
      annotationInfo ainfo = qual_getAnnotationInfo (qel);

      if (annotationInfo_matchesContext (ainfo, ue))
	{
	  DPRINTF (("Reflecting %s on %s", 
		    annotationInfo_unparse (ainfo),
		    uentry_unparseFull (ue)));
	  
	  sRef_reflectAnnotation (ue->sref, ainfo, g_currentloc);
	  DPRINTF (("==> %s", sRef_unparseFull (ue->sref)));
	  DPRINTF (("==> %s", uentry_unparseFull (ue)));
	}
      else
	{
	  if (optgenerror
	      (FLG_ANNOTATIONERROR,
	       message ("Attribute annotation %s used in inconsistent context: %q",
			qual_unparse (qel),
			uentry_unparse (ue)),
	       uentry_whereLast (ue)))
	    {
	      /*@i! annotationInfo_showContextError (ainfo, ue); */
	    }
	}
    }
  else
    {
      if (qual_isCQual (qel))
	{
	  ; /* okay */
	}
      else
	{
	  llbug (message ("Unhandled qualifier: %s", qual_unparse (qel)));
	}
    }
}

void
uentry_reflectQualifiers (uentry ue, qualList q)
{
  llassert (uentry_isValid (ue)); 

  DPRINTF (("Reflect qualifiers: %s / %s",
	    uentry_unparseFull (ue), qualList_unparse (q)));

  qualList_elements (q, qel)
    {
      if (qual_isStatic (qel))
	{
	  uentry_setStatic (ue);
	}
      else if (qual_isUnused (qel))
	{
	  uentry_setUsed (ue, fileloc_undefined);	  
	}
      else if (qual_isExternal (qel))
	{
	  fileloc_free (ue->whereDefined);
	  ue->whereDefined = fileloc_createExternal ();
	}
      else if (qual_isSef (qel))
	{
	  if (uentry_isVariable (ue))
	    {
	      vkind vk = ue->info->var->kind;

	      llassert (vk != VKREFPARAM);

	      if (vk == VKYIELDPARAM)
		{
		  voptgenerror
		    (FLG_ANNOTATIONERROR,
		     message ("Qualifier sef cannot be used with %s: %q",
			      cstring_makeLiteralTemp (vk == VKYIELDPARAM ? "yield" : "returned"),
			      uentry_unparse (ue)),
		     uentry_whereLast (ue));
		}
	      else if (vk == VKRETPARAM)
		{
		  ue->info->var->kind = VKSEFRETPARAM;
		}
	      else
		{
		  ue->info->var->kind = VKSEFPARAM;
		}
	    }
	  else
	    {
	      voptgenerror 
		(FLG_ANNOTATIONERROR,
		 message ("Qualifier sef is meaningful only on parameters: %q", 
			  uentry_unparse (ue)),
		 uentry_whereLast (ue));
	    }
	}
      else if (qual_isExtern (qel))
	{
	  ue->storageclass = SCEXTERN;
	}
      else if (qual_isGlobalQual (qel)) /* undef, killed */
	{
	  DPRINTF (("Reflecting qual: %s / %s",
		    qual_unparse (qel), uentry_unparse (ue)));

	  if (uentry_isVariable (ue))
	    {
	      sstate oldstate = ue->info->var->defstate;
	      sstate defstate = sstate_fromQual (qel);


	      if ((oldstate == SS_UNDEFGLOB && defstate == SS_KILLED)
		  || (oldstate == SS_KILLED && defstate == SS_UNDEFGLOB))
		{
		  defstate = SS_UNDEFKILLED;
		}
	      else 
		{
		  ; /* any errors? */
		}

	      sRef_setDefState (ue->sref, defstate, fileloc_undefined);
	      ue->info->var->defstate = defstate;
	    }
	  else
	    {
	      voptgenerror 
		(FLG_ANNOTATIONERROR,
		 message ("Qualifier %s used on non-variable: %q",
			  qual_unparse (qel), uentry_unparse (ue)),
		 uentry_whereLast (ue));
	    }

	  DPRINTF (("After: %s", uentry_unparseFull (ue)));
	}
      /* start modifications */
      else if( qual_isBufQualifier(qel) ) {
        ctype ct = ctype_realType(uentry_getType(ue));
        if( ctype_isArray(ct) || ctype_isPointer(ct) ) {

            if( uentry_hasBufStateInfo(ue) )  {
                if( qual_isNullTerminated(qel) ) {  /* handle Nullterm */
                    
                   if (uentry_isAnyParam(ue) || uentry_isReturned (ue)) {
                                               /* If formal func param */
                       uentry_setNullTerminatedState(ue); 
                       uentry_setLen (ue, 1);
                       uentry_setSize (ue, 1);

                       sRef_setNullTerminatedState(uentry_getSref(ue));
                       sRef_setLen (uentry_getSref(ue), 1);
                       sRef_setSize (uentry_getSref(ue), 1);
                   } else {
                       uentry_setPossiblyNullTerminatedState(ue); 

                       sRef_setPossiblyNullTerminatedState(uentry_getSref(ue));
                   }

                } 
                /* put other BufState Qualifiers here */
            } else {
	      cstring s =  uentry_getName(ue);
	      llfatalbug(message("INTERNAL Error: we have a NULL BufState \
			struct for identifier %s\n", s) );
            }
         } else if (ctype_isFunction (ct)) { /* We have to handle function */

            sRef retSref = uentry_getSref (ue);
            ctype retType = sRef_getType (retSref);

            if (ctype_isPointer (retType) || ctype_isArray (retType)) {
	       sRef_setNullTerminatedState (retSref);

            } else {
              
	 	llerror 
	          (FLG_SYNTAX,
		       message ("Qualifier %s used on non-pointer on \
                            function return: %q", qual_unparse (qel),
                                                    uentry_unparse (ue)));
             }
         }
              
         else  {
	 	llerror 
	          (FLG_SYNTAX,
		       message ("Qualifier %s used on non-pointer: %q",
			  qual_unparse (qel), uentry_unparse (ue)));	      
	 }
	DPRINTF (("After: %s", uentry_unparseFull (ue)));
      }/* end else if */    
      else if (qual_isAllocQual (qel)) /* out, partial, reldef, special, etc. */
	{
	  ctype realType = ctype_realType (ue->utype);
	  sstate defstate = sstate_fromQual (qel);

	  if (ctype_isFunction (realType))
	    {
	      realType = ctype_realType (ctype_getReturnType (realType));
	    }

	  if (qual_isRelDef (qel))
	    {
	      ; /* okay anywhere */
	    }
	  else
	    {
	      if (!ctype_isAP (realType) 
		  && !ctype_isSU (realType)
		  && !ctype_isUnknown (realType)
		  && !ctype_isAbstract (ue->utype))
		{
		  voptgenerror 
		    (FLG_ANNOTATIONERROR,
		     message ("Qualifier %s used on non-pointer or struct: %q",
			      qual_unparse (qel), uentry_unparse (ue)),
		     uentry_whereLast (ue));
		}
	    }

	  uentry_setDefState (ue, defstate);

	  if (sRef_isStateSpecial (ue->sref)
	      && alkind_isImplicit (sRef_getAliasKind (ue->sref)))
	    {
	      sRef_setAliasKind (ue->sref, AK_ERROR, fileloc_undefined);
	    }
	}
      else if (qual_isYield (qel))
	{
	  if (uentry_isVariable (ue))
	    {
	      ue->info->var->kind = VKYIELDPARAM;
	    }
	  else
	    {
	      voptgenerror 
		(FLG_ANNOTATIONERROR,
		 message ("Qualifier %s used on non-iterator parameter: %q",
			  qual_unparse (qel), uentry_unparse (ue)),
		 uentry_whereLast (ue));
	    }
	}
      else if (qual_isExQual (qel))
	{
	  exkind ek = exkind_fromQual (qel);
	  ctype ut = uentry_getType (ue);

	  DPRINTF (("Reflect ex qual: %s / %s",
		    uentry_unparse (ue), exkind_unparse (ek)));

	  if (ctype_isFunction (ut))
	    {
	      ut = ctype_getReturnType (ut);
	    }
	  
	  if (!(ctype_isVisiblySharable (ut))
	      && !(ctype_isArray (ut)) /* can apply to arrays also! */
	      && !(ctype_isStruct (ctype_realType (ut)))) /* applies to structure fields! */
	    {
	      if (!qual_isImplied (qel))
		{
		  if (ctype_isImmutableAbstract (ut)) {
		    voptgenerror 
		      (FLG_REDUNDANTSHAREQUAL, 
		       message ("Qualifier %s used on unsharable storage type %t: %q",
				exkind_unparse (ek), ut, uentry_getName (ue)),
		       uentry_whereLast (ue));
		  } else {
		    voptgenerror 
		      (FLG_MISPLACEDSHAREQUAL, 
		       message ("Qualifier %s used on unsharable storage type %t: %q",
				exkind_unparse (ek), ut, uentry_getName (ue)),
		       uentry_whereLast (ue));
		  }
		}
	    }
	  else
	    {
	      alkind ak = sRef_getAliasKind (ue->sref);

	      sRef_setExKind (ue->sref, ek, uentry_whereDeclared (ue));
	      DPRINTF (("Set exkind: %s", sRef_unparseFull (ue->sref)));

	      if (alkind_isUnknown (ak) || alkind_isImplicit (ak) || alkind_isStatic (ak))
		{
		  if (!alkind_isTemp (ak))
		    {
		      DPRINTF (("imp dep: %s", uentry_unparseFull (ue)));
		      uentry_setAliasKind (ue, AK_IMPDEPENDENT);
		    }
		}
	      else if (alkind_isDependent (ak) || alkind_isTemp (ak)
		       || alkind_isOwned (ak))
		{
		  ; /* okay */
		}
	      else
		{
		  llerror 
		    (FLG_SYNTAX, 
		     message ("Exposure qualifier %s used on %s storage (should "
			      "be dependent): %q",
			      qual_unparse (qel), 
			      alkind_unparse (ak),
			      uentry_unparse (ue)));
		}
	    }
	}
      else if (qual_isGlobCheck (qel))
	{
	  if (uentry_isVariable (ue))
	    {
	      chkind ch = chkind_fromQual (qel); 		
		       
	      if (ue->info->var->checked != CH_UNKNOWN)
		{
		  if (ch == ue->info->var->checked)
		    {
		      llerror (FLG_SYNTAX, 
			       message ("Redundant %s qualifier on %q",
					qual_unparse (qel),
					uentry_getName (ue)));
		    }
		  else
		    {
		      llerror (FLG_SYNTAX, 
			       message
			       ("Contradictory %s and %s qualifiers on %q",
				qual_unparse (qel),
				checkedName (ue->info->var->checked),
				uentry_getName (ue)));
		    }
		}

	      ue->info->var->checked = ch;
	    }
	  else
	    {
	      llerror
		(FLG_SYNTAX, 
		 message ("Qualifier %s used with non-variable", 
			  qual_unparse (qel)));
	    }
	}
      else if (qual_isReturned (qel))
	{
	  if (uentry_isVariable (ue))
	    {
	      ue->info->var->kind = VKRETPARAM;
	    }
	  else
	    {
	      llerror (FLG_SYNTAX, message ("Qualifier %s used with non-variable", 
					    qual_unparse (qel)));
	    }
	}
      else
	{
	  uentry_reflectOtherQualifier (ue, qel);
	}

      sRef_storeState (ue->sref);
    } end_qualList_elements;

  qualList_clear (q);

  DPRINTF (("Done: %s", sRef_unparseFull (ue->sref)));
}
	
bool
uentry_isOnly (uentry ue)
{
  return (!uentry_isUndefined (ue) 
	  && uentry_isVariable (ue) 
	  && alkind_isOnly (sRef_getOrigAliasKind (ue->sref)));
}

static void
uentry_setAliasKind (/*@notnull@*/ uentry ue, alkind ak)
{
  sRef_setAliasKind (ue->sref, ak, uentry_whereDeclared (ue));
  sRef_setOrigAliasKind (ue->sref, ak);
}

static void
uentry_setNullState (/*@notnull@*/ uentry ue, nstate ns)
{
  if (uentry_isVariable (ue))
    {
      ue->info->var->nullstate = ns;
    }

  sRef_setNullState (ue->sref, ns, uentry_whereDeclared (ue));
}

bool
uentry_isUnique (uentry ue)
{
  return (!uentry_isUndefined (ue) 
	  && uentry_isVariable (ue) 
	  && alkind_isUnique (sRef_getOrigAliasKind (ue->sref)));
}

bool
uentry_isFileStatic (uentry ue)
{
  return (uentry_isStatic (ue) 
	  && (!uentry_isVariable (ue)
	      || sRef_isFileStatic (uentry_getSref (ue))));
}

bool
uentry_isExported (uentry ue)
{
  if (uentry_isValid (ue))
    {
      if (uentry_isVariable (ue))
	{
	  return (sRef_isRealGlobal (uentry_getSref (ue)));
	}
      else
	{
	  return !uentry_isStatic (ue);
	}
    }

  return FALSE;
}

bool
uentry_isNonLocal (uentry ue)
{
  return (uentry_isValid (ue) && uentry_isVariable (ue)
	  && (sRef_isFileOrGlobalScope (ue->sref) || uentry_isStatic (ue)));
}

bool
uentry_isGlobalVariable (uentry ue)
{
  return (uentry_isValid (ue) && uentry_isVariable (ue) 
	  && sRef_isFileOrGlobalScope (ue->sref));
}

bool
uentry_isVisibleExternally (uentry ue)
{
  return (uentry_isValid (ue) 
	  && ((uentry_isVariable (ue) && sRef_isRealGlobal (ue->sref))
	      || (!uentry_isStatic (ue) 
		  && (uentry_isFunction (ue)
		      || uentry_isIter (ue)
		      || uentry_isEndIter (ue)
		      || uentry_isConstant (ue)
		      || uentry_isDatatype (ue)
		      || uentry_isAnyTag (ue)))));
}

bool
uentry_isPrintfLike (uentry ue)
{
  return (uentry_isFunction (ue) 
	  && (ue->info->fcn->specialCode == SPC_PRINTFLIKE));
}

bool
uentry_isScanfLike (uentry ue)
{
  return (uentry_isFunction (ue) 
	  && (ue->info->fcn->specialCode == SPC_SCANFLIKE));
}

bool
uentry_isMessageLike (uentry ue)
{
  return (uentry_isFunction (ue) 
	  && (ue->info->fcn->specialCode == SPC_MESSAGELIKE));
}

static void checkSpecialFunction (/*@notnull@*/ uentry ue)
{
  uentryList args = uentry_getParams (ue);

  if (!uentryList_isMissingParams (args))
    {
      uentry last = uentry_undefined;

      uentryList_elements (args, current)
	{
	  if (uentry_isElipsisMarker (current))
	    {
	      if (uentry_isUndefined (last))
		{
		  voptgenerror 
		    (FLG_SYNTAX,
		     message ("Function %q is marked %s, but has no format "
			      "string argument before elipsis",
			      uentry_getName (ue),
			      specCode_unparse (ue->info->fcn->specialCode)),
		     uentry_whereLast (ue));
		  ue->info->fcn->specialCode = SPC_NONE;
		}
	      else
		{
		  ctype rt = ctype_realType (uentry_getType (last));

		  if (!ctype_match (rt, ctype_string))
		    {
		      bool okay = FALSE;

		      /* wchar_t * is okay too */
		      if (ctype_isAP (rt))
			{
			  ctype base = ctype_baseArrayPtr (rt);
			  
			  if (ctype_isArbitraryIntegral (base)) 
			    {
			      okay = TRUE;
			    }
			}
		      
		      if (!okay) 
			{
			  voptgenerror
			    (FLG_SYNTAX,
			     message ("Function %q is marked %s, but the argument "
				      "before the elipsis has type %s (should be char *)",
				      uentry_getName (ue),
				      specCode_unparse (ue->info->fcn->specialCode),
				      ctype_unparse (uentry_getType (last))),
			     uentry_whereLast (ue));
			  
			  ue->info->fcn->specialCode = SPC_NONE;
			}
		    }
		}
	      return;
	    }
	  last = current;
	} end_uentryList_elements ;

      voptgenerror 
	(FLG_SYNTAX,
	 message ("Function %q is marked %s, but has no elipsis parameter",
		  uentry_getName (ue),
		  specCode_unparse (ue->info->fcn->specialCode)),
	 uentry_whereLast (ue));

      ue->info->fcn->specialCode = SPC_NONE;
    }
}

void
uentry_setPrintfLike (uentry ue)
{
  uentry_convertVarFunction (ue);
  llassertfatal (uentry_isFunction (ue));
  ue->info->fcn->specialCode = SPC_PRINTFLIKE;
  checkSpecialFunction (ue);
}

void
uentry_setScanfLike (uentry ue)
{
  uentry_convertVarFunction (ue);
  llassertfatal (uentry_isFunction (ue));
  ue->info->fcn->specialCode = SPC_SCANFLIKE;
  checkSpecialFunction (ue);
}

void
uentry_setMessageLike (uentry ue)
{
  uentry_convertVarFunction (ue);  
  llassertfatal (uentry_isFunction (ue));
  ue->info->fcn->specialCode = SPC_MESSAGELIKE;
  checkSpecialFunction (ue);
}

bool
uentry_isSpecialFunction (uentry ue)
{
  return (uentry_isFunction (ue) 
	  && (ue->info->fcn->specialCode != SPC_NONE));
}

/*@notnull@*/ uentry uentry_makeParam (idDecl t, int i)
{
  ctype ct = idDecl_getCtype (t);
  ctype base = ct;
  fileloc loc = setLocation ();
  sRef pref = sRef_makeParam (i, ct, stateInfo_makeLoc (loc));
  uentry ue = uentry_makeVariableSrefParam (idDecl_observeId (t), ct, loc, pref);

  DPRINTF (("Make param: %s", uentry_unparseFull (ue)));
  uentry_reflectQualifiers (ue, idDecl_getQuals (t));
  uentry_implicitParamAnnots (ue);

  /* Parameter type [][] or [x][] is invalid */

  while (ctype_isFixedArray (base)) {
    base = ctype_baseArrayPtr (base);
  }
  
  if (ctype_isIncompleteArray (base)) {
    base = ctype_baseArrayPtr (base);

    if (ctype_isArray (base)) {
      if (!uentry_hasName (ue)) {
	(void) optgenerror (FLG_INCOMPLETETYPE, 
			    message ("Unnamed function parameter %d is incomplete type (inner array must have bounds): %s",
				     i + 1,
				     ctype_unparse (ct)),
			    uentry_whereLast (ue));
      } else {
	(void) optgenerror (FLG_INCOMPLETETYPE, 
			    message ("Function parameter %q is incomplete type (inner array must have bounds): %s",
				     uentry_getName (ue),
				     ctype_unparse (ct)),
			    uentry_whereLast (ue));
      }
    }
  }

  DPRINTF (("Param: %s", uentry_unparseFull (ue)));
  return ue;
}

/*@only@*/ /*@notnull@*/ uentry uentry_makeIdVariable (idDecl t)
{
  ctype ct = idDecl_getCtype (t);

  if (ctype_isFunction (ct))
    {
            return (uentry_makeIdFunction (t));
    }
  else
    {
      fileloc loc = setLocation ();
      uentry ue = uentry_makeVariable (idDecl_observeId (t), ct, loc, FALSE);
      
      uentry_reflectQualifiers (ue, idDecl_getQuals (t));

      if (!uentry_isExtern (ue))
	{
	  uentry_setDefined (ue, loc);
	}

      return ue;
    }
}

# ifndef NOLCL
/*@notnull@*/ uentry uentry_makeVariableParam (cstring n, ctype t, fileloc loc)
{
  return (uentry_makeVariableParamAux (n, t, sRef_makeType (t), fileloc_copy (loc), SS_DEFINED));
}
# endif

/*
** constants
*/

static /*@only@*/ /*@notnull@*/ 
uentry uentry_makeConstantAux (cstring n, ctype t, 
			       /*@keep@*/ fileloc f, bool priv, bool macro,
			       /*@only@*/ multiVal m)
{
  uentry e = uentry_alloc ();

  e->ukind = KCONST;
  e->uname = cstring_copy (n);
  e->utype = t;
  e->storageclass = SCNONE;

  e->warn = warnClause_undefined; /*@i32 warnings for constants? */

  e->sref  = sRef_makeConst (t);

  e->lset = FALSE;
  e->used = FALSE;
  
  e->uses = filelocList_new ();
  e->isPrivate = priv;
  e->hasNameError = FALSE;

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->uconst = (ucinfo) dmalloc (sizeof (*e->info->uconst));
  e->info->uconst->access = typeIdSet_undefined;
  e->info->uconst->macro = macro;

  uentry_setSpecDef (e, f);

  if (multiVal_isInt (m) && (multiVal_forceInt (m) == 0))
    {
      sRef_setDefNull (e->sref, uentry_whereDeclared (e)); 
    }

  uentry_setConstantValue (e, m);

  return (e);
}

/*@notnull@*/ uentry uentry_makeConstant (cstring n, ctype t, fileloc f)
{
  return (uentry_makeConstantAux (n, t, f, FALSE, FALSE, multiVal_unknown ()));
}

/*@notnull@*/ uentry uentry_makeConstantValue (cstring n, ctype t, fileloc f, bool priv, multiVal val)
{
  return (uentry_makeConstantAux (n, t, f, priv, FALSE, val));
}

/*@notnull@*/ uentry uentry_makeMacroConstant (cstring n, ctype t, fileloc f)
{
  return (uentry_makeConstantAux (n, t, f, FALSE, TRUE, multiVal_unknown ()));
}

/*@notnull@*/ uentry uentry_makeIdConstant (idDecl t)
{
  uentry ue = uentry_makeConstant (idDecl_observeId (t), 
				   idDecl_getCtype (t), 
				   fileloc_undefined);

  llassert (fileloc_isUndefined (ue->whereDeclared));
  ue->whereDeclared = setLocation ();
  uentry_reflectQualifiers (ue, idDecl_getQuals (t));

  DPRINTF (("Constant: %s", uentry_unparseFull (ue)));
  DPRINTF (("Value: %s", multiVal_unparse (uentry_getConstantValue (ue))));
  return ue;
}

/*
** variables
*/

void uentry_setDefState (uentry ue, sstate defstate)
{
  if (uentry_isValid (ue))
    {
      sRef_setDefState (ue->sref, defstate, fileloc_undefined);

      if (uentry_isVariable (ue))
	{
	  ue->info->var->defstate = defstate; /* evs 2000-05-17: fixed bug, was SS_DEFINED! */
	}
    }
}

bool uentry_isCheckedUnknown (uentry ue)
{
  return (uentry_isVar (ue) 
	  && (ue->info->var->checked == CH_UNKNOWN));
}

bool uentry_isCheckMod (uentry ue)
{
  return (uentry_isVar (ue) 
	  && (ue->info->var->checked == CH_CHECKMOD));
}

bool uentry_isUnchecked (uentry ue)
{
  return (uentry_isVar (ue) 
	  && (ue->info->var->checked == CH_UNCHECKED));
}

bool uentry_isChecked (uentry ue)
{
  return (uentry_isVar (ue) 
	  && (ue->info->var->checked == CH_CHECKED));
}

bool uentry_isCheckedModify (uentry ue)
{
  return (uentry_isVar (ue) 
	  && (ue->info->var->checked == CH_CHECKED
	      || ue->info->var->checked == CH_CHECKMOD
	      || ue->info->var->checked == CH_CHECKEDSTRICT));
}

bool uentry_isCheckedStrict (uentry ue)
{
  return (uentry_isVar (ue) 
	  && (ue->info->var->checked == CH_CHECKEDSTRICT));
}

void uentry_setUnchecked (uentry ue)
{
  llassert (uentry_isVar (ue));

  ue->info->var->checked = CH_UNCHECKED;
}

void uentry_setChecked (uentry ue)
{
  llassert (uentry_isVar (ue));

  ue->info->var->checked = CH_CHECKED;
}

void uentry_setCheckMod (uentry ue)
{
  llassert (uentry_isVar (ue));

  ue->info->var->checked = CH_CHECKMOD;
}

void uentry_setCheckedStrict (uentry ue)
{
  llassert (uentry_isVar (ue));
  
  ue->info->var->checked = CH_CHECKEDSTRICT;
}

static /*@only@*/ /*@notnull@*/ 
  uentry uentry_makeVariableAux (cstring n, ctype t, 
				 fileloc f,
				 /*@exposed@*/ sRef s,
				 bool priv, vkind kind)
{
  uentry e = uentry_alloc ();
  ctype rt = t;

  DPRINTF (("Make variable: %s %s %s", n, ctype_unparse (t), sRef_unparse (s)));

  e->ukind = KVAR;
  e->uname = cstring_copy (n);
  e->utype = t;

  e->storageclass = SCNONE;

  e->warn = warnClause_undefined; /*@i32 warnings for variable @*/

  e->sref  = s;

  e->used = FALSE;
  e->lset = FALSE;

  e->uses = filelocList_new ();
  e->isPrivate = priv;
  e->hasNameError = FALSE;

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->var = (uvinfo) dmalloc (sizeof (*e->info->var));
  e->info->var->kind = kind;

  /*@i523 e->info->var->origsref = sRef_saveCopy (e->sref); */
  e->info->var->checked = CH_UNKNOWN;

  DPRINTF (("Here we are: %s", sRef_unparseFull (e->sref)));
  uentry_setSpecDef (e, f);
  DPRINTF (("Here we are: %s", sRef_unparseFull (e->sref)));

  if (ctype_isFunction (rt))
    {
      rt = ctype_getReturnType (rt);
    }

  if (ctype_isUA (rt))
    {
      DPRINTF (("Here we are: %s", sRef_unparseFull (e->sref)));
      sRef_setStateFromType (e->sref, rt);
    }

  DPRINTF (("Here we are: %s", sRef_unparseFull (e->sref)));
  e->info->var->defstate = sRef_getDefState (e->sref);  
  e->info->var->nullstate = sRef_getNullState (e->sref);

  /* start modifications */
  /* This function sets the uentry for a pointer or array variable declaration,
     it allocates memory and sets the fields. We check if the type of the variable
     is a pointer or array and allocate a `bbufinfo' struct accordingly */
  
  if( ctype_isArray (t) || ctype_isPointer(t)) {
    /*@i222@*/e->info->var->bufinfo = dmalloc( sizeof(*e->info->var->bufinfo) );
     e->info->var->bufinfo->bufstate = BB_NOTNULLTERMINATED;
     /*@access sRef@*/ /*i@222*/
     /* It probably isn't necessary to violate the abstraction here
      I'll fix this later
     */
     s->bufinfo.bufstate = BB_NOTNULLTERMINATED;
     /*@noaccess sRef@*/
  } else {
     e->info->var->bufinfo = NULL;
  }/* end else */
/* end modification */

  return (e);
}

bool
uentry_isYield (uentry ue)
{
  return (uentry_isVariable (ue) 
	  && (ue->info->var->kind == VKYIELDPARAM
	      || ue->info->var->kind == VKREFYIELDPARAM));
}

static bool
uentry_isRefsField (uentry ue)
{
  return (uentry_isVariable (ue) && sRef_isRefsField (ue->sref));
}

/*@only@*/ /*@notnull@*/ 
uentry uentry_makeVariable (cstring n, ctype t, fileloc f, bool isPriv)
{
  return (uentry_makeVariableAux (n, t, f, sRef_makeType (t), isPriv, 
				  fileloc_isSpec (f) ? VKSPEC : VKNORMAL));
}

/*
** functions
*/

void uentry_makeVarFunction (uentry ue)
{
  alkind ak;
  exkind ek;
  uvinfo oldInfo;
  fileloc loc;

  llassert (uentry_isValid (ue));
  llassert (!sRef_modInFunction ());

  ak = sRef_getOrigAliasKind (ue->sref);
  ek = sRef_getOrigExKind (ue->sref);

  llassert (uentry_isVariable (ue));
  oldInfo = ue->info->var;

  DPRINTF (("ue: %s", uentry_unparseFull (ue)));
  llassert (ctype_isUnknown (ue->utype) || ctype_isFunction (ctype_realType (ue->utype)));

  /*
  ** expanded macro is marked used 
  */

  ue->used = ue->used || (oldInfo->kind == VKEXPMACRO);

  ue->ukind = KFCN;
  ue->info->fcn = (ufinfo) dmalloc (sizeof (*ue->info->fcn));
  ue->info->fcn->exitCode = XK_UNKNOWN;
  ue->info->fcn->nullPred = qual_createUnknown ();
  ue->info->fcn->specialCode = SPC_NONE;
  ue->info->fcn->access = typeIdSet_undefined;
  ue->info->fcn->hasGlobs = FALSE;
  ue->info->fcn->globs = globSet_undefined;
  ue->info->fcn->hasMods = FALSE;
  ue->info->fcn->mods = sRefSet_undefined;
  ue->info->fcn->specclauses = NULL;
  ue->info->fcn->defparams = uentryList_undefined;

  /*drl*/
  ue->info->fcn->preconditions = functionConstraint_undefined;
  /*end */

  /*drl 12/28/2000*/
  ue->info->fcn->postconditions = functionConstraint_undefined; 
  /*end */
  
  if (ctype_isFunction (ue->utype))
    {
      ue->sref = sRef_makeType (ctype_getReturnType (ue->utype)); 
    }
  else
    {
      ue->sref = sRef_makeType (ctype_unknown); 
    }

  if (sRef_isRefCounted (ue->sref))
    {
      ak = AK_NEWREF;
    }
  else
    {
      if (alkind_isUnknown (ak))
	{
	  if (exkind_isKnown (ek))
	    {
	      DPRINTF (("imp dep: %s", uentry_unparseFull (ue)));
	      ak = AK_IMPDEPENDENT;
	    }
	  else 
	    {
	      if (context_getFlag (FLG_RETIMPONLY))
		{
		  if (ctype_isFunction (ue->utype)
		      && ctype_isVisiblySharable 
		      (ctype_realType (ctype_getReturnType (ue->utype))))
		    {
		      if (uentryList_hasReturned (uentry_getParams (ue)))
			{
			  ;
			}
		      else
			{
			  if (ctype_isImmutableAbstract (ctype_getReturnType (ue->utype))) 
			    {
			      ;
			    }
			  else 
			    {
			      ak = AK_IMPONLY;
			    }
			}
		    }
		}
	    }
	}
    }

  loc = ue->whereDeclared;

  sRef_setAliasKind (ue->sref, ak, loc);
  sRef_setNullState (ue->sref, oldInfo->nullstate, loc);
  sRef_setDefState (ue->sref, oldInfo->defstate, loc);
  sRef_setExKind (ue->sref, ek, loc);

  if (oldInfo->kind == VKEXPMACRO)
    {
      ;
    }
  else
    {
      fileloc_free (ue->whereDefined);
      ue->whereDefined = fileloc_undefined;
    }

  uvinfo_free (oldInfo);
}

void uentry_makeConstantFunction (uentry ue)
{
  alkind ak;
  exkind ek;
  ucinfo oldInfo;
  fileloc loc;

  llassert (uentry_isValid (ue));
  llassert (!sRef_modInFunction ());

  ak = sRef_getOrigAliasKind (ue->sref);
  ek = sRef_getOrigExKind (ue->sref);

  llassert (uentry_isConstant (ue));
  oldInfo = ue->info->uconst;

  llassert (ctype_isUnknown (ue->utype) || ctype_isFunction (ue->utype));

  /*
  ** expanded macro is marked used (until I write a pre-processor)
  */

  ue->ukind = KFCN;
  ue->info->fcn = (ufinfo) dmalloc (sizeof (*ue->info->fcn));
  ue->info->fcn->exitCode = XK_UNKNOWN;
  ue->info->fcn->nullPred = qual_createUnknown ();
  ue->info->fcn->specialCode = SPC_NONE;
  ue->info->fcn->access = typeIdSet_undefined;
  ue->info->fcn->hasGlobs = FALSE;
  ue->info->fcn->globs = globSet_undefined;
  ue->info->fcn->hasMods = FALSE;
  ue->info->fcn->mods = sRefSet_undefined;
  ue->info->fcn->specclauses = NULL;
  ue->info->fcn->defparams = uentryList_undefined;

  /*drl*/
  ue->info->fcn->preconditions = functionConstraint_undefined;
  /*end */

  /*drl 12/28/2000*/
  ue->info->fcn->postconditions = functionConstraint_undefined;
  /*end */

  
  if (ctype_isFunction (ue->utype))
    {
      ue->sref = sRef_makeType (ctype_getReturnType (ue->utype)); 
    }
  else
    {
      ue->sref = sRef_makeType (ctype_unknown); 
    }

  if (sRef_isRefCounted (ue->sref))
    {
      ak = AK_NEWREF;
    }
  else
    {
      if (alkind_isUnknown (ak))
	{
	  if (exkind_isKnown (ek))
	    {
	      DPRINTF (("imp dep: %s", uentry_unparseFull (ue)));
	      ak = AK_IMPDEPENDENT;
	    }
	  else 
	    {
	      if (context_getFlag (FLG_RETIMPONLY))
		{
		  if (ctype_isFunction (ue->utype)
		      && ctype_isVisiblySharable 
		      (ctype_realType (ctype_getReturnType (ue->utype))))
		    {
		      if (uentryList_hasReturned (uentry_getParams (ue)))
			{
			  ;
			}
		      else
			{
			  if (ctype_isImmutableAbstract (ctype_getReturnType (ue->utype))) 
			    {
			      ;
			    }
			  else 
			    {
			      ak = AK_IMPONLY;
			    }
			}
		    }
		}
	    }
	}
    }

  loc = ue->whereDeclared;

  sRef_setAliasKind (ue->sref, ak, loc);
  sRef_setExKind (ue->sref, ek, loc);

  fileloc_free (ue->whereDefined);
  ue->whereDefined = fileloc_undefined;
  ucinfo_free (oldInfo);
}

void
uentry_setGlobals (uentry ue, /*@owned@*/ globSet globs)
{
  llassert (uentry_isValid (ue));

  if (uentry_isIter (ue))
    {
      llassert (globSet_isUndefined (ue->info->iter->globs));
      ue->info->iter->globs = globs;
    }
  else
    {
      uentry_convertVarFunction (ue);
      
      llassert (uentry_isFunction (ue));
      llassert (!ue->info->fcn->hasGlobs 
		&& globSet_isUndefined (ue->info->fcn->globs));
      
      ue->info->fcn->hasGlobs = TRUE;
      globSet_markImmutable (globs);
      /*@-mustfree@*/ ue->info->fcn->globs = globs;
      /*@=mustfree@*/
    }

  /*@i23*/
  /* ???  - evans 2001-09-09 not sure what's going on here...?
  if (globSet_hasStatic (globs))
    {
      context_recordFileGlobals (globs);
    }
  */

  if (context_getFlag (FLG_GLOBALSIMPMODIFIESNOTHING))
    {
      ue->info->fcn->hasMods = TRUE;
    }
}

void uentry_addAccessType (uentry ue, typeId tid)
{
  if (uentry_isFunction (ue))
    {
      ue->info->fcn->access = typeIdSet_insert (ue->info->fcn->access, tid);
    }
  else if (uentry_isEitherConstant (ue))
    {
      ue->info->uconst->access = typeIdSet_insert (ue->info->uconst->access, tid);
    }
  else if (uentry_isIter (ue))
    {
      ue->info->iter->access = typeIdSet_insert (ue->info->iter->access, tid);
    }
  else if (uentry_isEndIter (ue))
    {
      ue->info->enditer->access = typeIdSet_insert (ue->info->enditer->access, tid);
    }
  else
    {
      llbug (message ("no access for: %q", uentry_unparse (ue)));
    }
}

/*@only@*/ /*@notnull@*/ uentry 
  uentry_makeFunction (cstring n, ctype t, 
		       typeId access, 
		       /*@only@*/ globSet globs, /*@only@*/ sRefSet mods, 
		       /*@only@*/ warnClause warn,
		       fileloc f)
{
  llassert (warnClause_isUndefined (warn)); /*@i325 remove parameter! */
  return (uentry_makeFunctionAux (n, t, 
				  ((typeId_isInvalid (access)) ? typeIdSet_emptySet () 
				   : typeIdSet_single (access)),
				  globs, mods, warn,
				  f,
				  FALSE, FALSE));
}

# ifndef NOLCL
/*@notnull@*/ uentry 
  uentry_makePrivFunction2 (cstring n, ctype t, 
			    typeIdSet access, 
			    globSet globs, sRefSet mods, 
			    fileloc f)
{
  return (uentry_makeFunctionAux (n, t, access, globs, mods, warnClause_undefined,
				  f, TRUE, FALSE));
}


/*@notnull@*/ uentry 
  uentry_makeSpecFunction (cstring n, ctype t, 
			   typeIdSet access,
			   /*@only@*/ globSet globs, 
			   /*@only@*/ sRefSet mods, 
			   fileloc f)
{
  uentry ue = uentry_makeFunctionAux (n, t, access, 
				      globs, mods, warnClause_undefined, 
				      f, FALSE, FALSE);

  uentry_setHasGlobs (ue);
  uentry_setHasMods (ue);

  reflectImplicitFunctionQualifiers (ue, TRUE);
  return (ue);
}
# endif

uentry uentry_makeExpandedMacro (cstring s, fileloc f)
{
  uentry ue = uentry_makeVariableAux (s, ctype_unknown, fileloc_undefined, 
				      sRef_undefined, FALSE, VKEXPMACRO);

  uentry_setDefined (ue, f);
  return ue;
}

/*@notnull@*/ /*@notnull@*/ uentry 
  uentry_makeForwardFunction (cstring n, typeId access, fileloc f)
{
  uentry ue = uentry_makeFunctionAux (n, ctype_unknown, 
				      typeIdSet_singleOpt (access),
				      globSet_undefined, sRefSet_undefined, 
				      warnClause_undefined,
				      fileloc_undefined,
				      FALSE, TRUE);

  ue->whereDeclared = fileloc_update (ue->whereDeclared, f);
  return ue;
}

bool uentry_isForward (uentry e)
{
  if (uentry_isValid (e))
    {
      ctype ct = uentry_getType (e);

      return (ctype_isUnknown (ct)
	      || (ctype_isFunction (ct)
		  && ctype_isUnknown (ctype_getReturnType (ct))));
    }

  return FALSE;
}

# ifndef NOLCL
/*@notnull@*/ uentry 
uentry_makeTypeListFunction (cstring n, typeIdSet access, fileloc f)
{
  return (uentry_makeFunctionAux (n, ctype_unknown, access,
				  globSet_undefined, sRefSet_undefined, warnClause_undefined,
				  f,FALSE, TRUE));
}

/*@notnull@*/ uentry 
uentry_makeUnspecFunction (cstring n, ctype t, 
			   typeIdSet access, 
			   fileloc f)
{
  uentry ue = uentry_makeFunctionAux (n, t, access, globSet_undefined,
				      sRefSet_undefined, warnClause_undefined,
				      f, FALSE, TRUE);

  reflectImplicitFunctionQualifiers (ue, TRUE);
  return ue;
}
# endif

/*
** datatypes
*/

/* is exported for use by usymtab_interface */

/*@notnull@*/ uentry 
  uentry_makeDatatypeAux (cstring n, ctype t, ynm mut, ynm abstract, 
			  fileloc f, bool priv)
{
  uentry e = uentry_alloc ();

  DPRINTF (("Make datatype: %s / %s",
	    n, ctype_unparse (t)));

  /* e->shallowCopy = FALSE; */
  e->ukind = KDATATYPE;
  e->uname = cstring_copy (n);
  e->utype = t;
  e->storageclass = SCNONE;
  e->sref  = sRef_makeUnknown ();

  if (ctype_isUA (t))
    {
      sRef_setStateFromType (e->sref, t);
    }

  uentry_setSpecDef (e, f);

  e->warn = warnClause_undefined; /*@i634@*/ 
  e->uses = filelocList_new ();
  e->isPrivate = priv;
  e->hasNameError = FALSE;

  e->used = FALSE;
  e->lset = FALSE;

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->datatype = (udinfo) dmalloc (sizeof (*e->info->datatype));
  e->info->datatype->abs = abstract;
  e->info->datatype->mut = mut;
  e->info->datatype->type = ctype_undefined;

  if (uentry_isDeclared (e))
    {
      uentry_setDefined (e, f);
    }

  if (ynm_isOn (abstract) && !(uentry_isCodeDefined (e)))
    {
      sRef_setNullState (e->sref, NS_ABSNULL, uentry_whereDeclared (e));
    }

  return (e);
}

/*@notnull@*/ uentry
  uentry_makeDatatype (cstring n, ctype t, ynm mut, ynm abstract, fileloc f)
{
  return (uentry_makeDatatypeAux (n, t, mut, abstract, f, FALSE));
}

/*@notnull@*/ uentry uentry_makeBoolDatatype (ynm abstract)
{
  uentry ret = uentry_makeDatatypeAux (context_getBoolName (),
				       ctype_bool, NO, abstract, 
				       fileloc_getBuiltin (),
				       FALSE);
  
  ret->info->datatype->type = ctype_bool;
  return ret;
}

/*
** iters
*/

static /*@only@*/ /*@notnull@*/ uentry 
  uentry_makeIterAux (cstring n, typeIdSet access, ctype ct, 
		      /*@only@*/ fileloc f)
{
  uentry e = uentry_alloc ();

  e->ukind = KITER;
  e->uname = cstring_copy (n);
  e->utype = ct;
  e->sref  = sRef_makeUnknown ();
  e->storageclass = SCNONE;
  e->used = FALSE;
  e->lset = FALSE;

  uentry_setSpecDef (e, f);

  e->warn = warnClause_undefined; /*@i452@*/
  e->uses = filelocList_new ();
  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->iter = (uiinfo) dmalloc (sizeof (*e->info->iter));
  e->info->iter->access = access;
  e->info->iter->mods = sRefSet_undefined;
  e->info->iter->globs = globSet_undefined;

  uentry_checkIterArgs (e);
  return (e);
}

/*@notnull@*/ uentry uentry_makeIter (cstring n, ctype ct, fileloc f)
{
  return (uentry_makeIterAux (n, context_fileAccessTypes (), ct, f));
}

static /*@notnull@*/ uentry
uentry_makeEndIterAux (cstring n, typeIdSet access, /*@only@*/ fileloc f)
{
  uentry e = uentry_alloc ();

  /* e->shallowCopy = FALSE; */
  e->ukind = KENDITER;
  e->storageclass = SCNONE;
  e->uname = message ("end_%s", n);
  e->utype = ctype_unknown;
  e->sref  = sRef_makeUnknown ();

  uentry_setSpecDef (e, f);

  e->used = FALSE;
  e->lset = FALSE;

  e->uses = filelocList_new ();
  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->enditer = (ueinfo) dmalloc (sizeof (*e->info->enditer));

  e->info->enditer->access = access;

  e->warn = warnClause_undefined; /*@i452@*/
  return (e);
}

/*@notnull@*/ /*@only@*/ uentry uentry_makeEndIter (cstring n, fileloc f)
{
  return (uentry_makeEndIterAux (n, context_fileAccessTypes (), f));
}

/*
** tags
*/

static /*@only@*/ /*@notnull@*/ uentry 
  uentry_makeTagAux (cstring n, ctype t, 
		     /*@only@*/ fileloc fl, 
		     bool priv, ekind kind)
{
  uentry e = uentry_alloc ();
  
  if (kind != KSTRUCTTAG && kind != KUNIONTAG && kind != KENUMTAG)
    {
      llbuglit ("uentry_makeTagAux: not a tag type");
    }
  
  e->ukind = kind;
  /* e->shallowCopy = FALSE; */
  e->uname = cstring_copy (n);

  e->utype = t;
  e->sref  = sRef_makeUnknown ();
  e->storageclass = SCNONE;

  uentry_setSpecDef (e, fl);
  
  e->used = FALSE;
  e->lset = FALSE;

  e->uses = filelocList_new ();
  e->isPrivate = priv;
  e->hasNameError = FALSE;

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->datatype = (udinfo) dmalloc (sizeof (*e->info->datatype));
  e->info->datatype->abs = NO;
  e->info->datatype->mut = (kind == KENUMTAG) ? NO : MAYBE;
  e->info->datatype->type = t;
  e->warn = warnClause_undefined; /*@i452@*/

  if (uentry_isDeclared (e))
    {
      uentry_setDefined (e, fl);
    }

  return (e);  
}

uentry uentry_makeStructTagLoc (cstring n, ctype t)
{
  cstring sname = makeStruct (n);
  uentry ret = uentry_makeTagAux (sname, t, setLocation (), FALSE, KSTRUCTTAG);

  cstring_free (sname);
  return (ret);
}

/*@only@*/ uentry
uentry_makeStructTag (cstring n, ctype t, fileloc loc)
{
  cstring sname = makeStruct (n);
  uentry ret = uentry_makeTagAux (sname, t, loc, FALSE, KSTRUCTTAG);

  cstring_free (sname);
  return ret;
}

/*@only@*/ uentry
uentry_makeUnionTag (cstring n, ctype t, fileloc loc)
{
  cstring uname = makeUnion (n);
  uentry ret = uentry_makeTagAux (uname, t, loc, FALSE, KUNIONTAG);

  cstring_free (uname);
  return (ret);
}

# ifndef NOLCL
uentry
uentry_makeEnumTag (cstring n, ctype t, fileloc loc)
{
  cstring ename = makeEnum (n);
  uentry ret = uentry_makeTagAux (ename, t, loc, FALSE, KENUMTAG);

  cstring_free (ename);
  return ret;
}
# endif

uentry
uentry_makeUnionTagLoc (cstring n, ctype t)
{
  cstring uname = makeUnion (n);
  uentry ret = uentry_makeTagAux (uname, t, setLocation (), FALSE, KUNIONTAG);

  cstring_free (uname);
  return ret;
}

uentry
uentry_makeEnumTagLoc (cstring n, ctype t)
{
  cstring ename = makeEnum (n);
  uentry ret = uentry_makeTagAux (ename, t, setLocation (), FALSE, KENUMTAG);

  cstring_free (ename);
  return ret;
}

bool 
uentry_isStructTag (uentry ue) 
{
  return (uentry_isValid (ue) && ue->ukind == KSTRUCTTAG);
}

bool 
uentry_isUnionTag (uentry ue) 
{
  return (uentry_isValid (ue) && ue->ukind == KUNIONTAG);
}

bool 
uentry_isEnumTag (uentry ue) 
{
  return (uentry_isValid (ue) && ue->ukind == KENUMTAG);
}

bool
uentry_isAnyTag (uentry ue)
{
  return (uentry_isStructTag (ue) 
	  || uentry_isUnionTag (ue)
	  || uentry_isEnumTag (ue));
}

static /*@unchecked@*/ /*@only@*/ uentry emarker = NULL;

extern void uentry_destroyMod (void)
   /*@globals killed emarker@*/ /*@modifies emarker@*/
{
  static bool wasDestroyed = FALSE;

  llassert (!wasDestroyed);

  if (emarker != NULL)
    {
      uentry_reallyFree (emarker);
    }

  wasDestroyed = TRUE;
}

uentry
uentry_makeElipsisMarker (void)
{
  if (emarker == NULL)
    {
      emarker = uentry_alloc ();

      emarker->ukind = KELIPSMARKER;
      emarker->uname = cstring_makeLiteral ("...");
      emarker->utype = ctype_elipsMarker;
      emarker->sref  = sRef_undefined;
      emarker->storageclass = SCNONE;
      emarker->used = FALSE;
      emarker->lset = FALSE;
      emarker->info = NULL;

      uentry_setSpecDef (emarker, fileloc_undefined);
      emarker->uses = filelocList_new ();
      emarker->isPrivate = FALSE;
      emarker->hasNameError = FALSE;
    }

  /*@ignore@*/ return (emarker); /*@end@*/
} 

/*
** comparisons
*/

bool
uentry_equiv (uentry p1, uentry p2)
{
  if (uentry_compare (p1, p2) != 0)
    {
      return FALSE;
    }
  else
    {
      return TRUE;
    }
}

int
uentry_xcomparealpha (uentry *p1, uentry *p2)
{
  int res;

  if ((res = uentry_compare (*p1, *p2)) == 0) {
    if ((*p1 != NULL) && (*p2 != NULL)) {
      res = cstring_compare ((*p1)->uname,
			     (*p2)->uname);
    }
  }

  return res;
}

int
uentry_xcompareuses (uentry *p1, uentry *p2)
{
  uentry u1 = *p1;
  uentry u2 = *p2;

  if (uentry_isValid (u1))
    {
      if (uentry_isValid (u2))
	{
	  return (-1 * int_compare (filelocList_size (u1->uses), 
				    filelocList_size (u2->uses)));
	}
      else
	{
	  return 1;
	}
    }
  else
    {
      if (uentry_isValid (u2))
	{
	  return -1;
	}
      else
	{
	  return 0;
	}
    }
}

int 
uentry_compareStrict (uentry v1, uentry v2)
{
  COMPARERETURN (uentry_compare (v1, v2));

  if (v1 != v2 && uentry_isValid (v1) && uentry_isValid (v2))
    {
      COMPARERETURN (fileloc_compare (v1->whereDeclared, v2->whereDeclared));
      COMPARERETURN (fileloc_compare (v1->whereDefined, v2->whereDefined));
      COMPARERETURN (fileloc_compare (v1->whereSpecified, v2->whereSpecified));
    }

  return 0;
}

int
uentry_compare (uentry u1, uentry u2)
{
  if (u1 == u2) return 0;
  
  if (uentry_isInvalid (u1)) return -1;
  if (uentry_isInvalid (u2)) return 1;

  INTCOMPARERETURN (u1->ukind, u2->ukind);
  COMPARERETURN (ctype_compare (u1->utype, u2->utype));
  COMPARERETURN (bool_compare (uentry_isPriv (u1), uentry_isPriv (u2)));
  COMPARERETURN (sRef_compare (u1->sref, u2->sref));

  switch (u1->ukind)
    {
    case KINVALID:
    case KELIPSMARKER:
      /* bug detected by splint:  
      ** uentry.c:753,14: Return value type bool does not match declared type int: TRUE 
      */
      return 0;
    case KENUMCONST:
    case KCONST:
      return (multiVal_compare (uentry_getConstantValue (u1),
				uentry_getConstantValue (u2)));
    case KSTRUCTTAG: 
    case KUNIONTAG: 
    case KENUMTAG: 
      return (ctype_compare (u1->info->datatype->type, u2->info->datatype->type));
    case KITER:
      COMPARERETURN (typeIdSet_compare (uentry_accessType (u1), 
					 uentry_accessType (u2)));
      return (uentryList_compareParams (uentry_getParams (u1), 
					uentry_getParams (u2)));
    case KENDITER:
      return (typeIdSet_compare (uentry_accessType (u1), 
				  uentry_accessType (u2)));
    case KFCN:
      /*
      ** Functions are never equivalent
      */
      
      if (u1 - u2 < 0) /* evans 2001-08-21: was: ((int) u1 < (int) u2), changed to remove gcc warning */
	{
	  return -1;
	}
      else
	{
	  return 1;
	}
    case KVAR:
      
      COMPARERETURN (generic_compare (u1->info->var->kind, u2->info->var->kind));
      COMPARERETURN (generic_compare (sRef_getOrigAliasKind (u1->sref),
				      sRef_getOrigAliasKind (u2->sref)));
      COMPARERETURN (generic_compare (sRef_getOrigExKind (u1->sref),
				      sRef_getOrigExKind (u2->sref)));
      COMPARERETURN (generic_compare (u1->info->var->checked,
				      u2->info->var->checked));
      COMPARERETURN (generic_compare (u1->info->var->defstate, 
				      u2->info->var->defstate));
      return        (generic_compare (u1->info->var->nullstate, 
				      u2->info->var->nullstate));
    case KDATATYPE:
      COMPARERETURN (ctype_compare (u1->info->datatype->type,
				    u2->info->datatype->type));
      COMPARERETURN (ynm_compare (u1->info->datatype->mut,
				  u2->info->datatype->mut));
      return (ynm_compare (u1->info->datatype->abs, u2->info->datatype->abs));
    }
  
  BADEXIT;
}

/*
** library format:
**
** all entries are: <type>[@<info>]*#<name>
**
** info depends on kind:
*/

static void
advanceField (char **s)
{
  reader_checkChar (s, '@');
}

static void
advanceName (char **s)
{
  reader_checkChar (s, '#');
}

static vkind
vkind_fromInt (int i)
{
  if /*@+enumint@*/ (i < VKFIRST || i > VKLAST) /*@=enumint@*/
    {
      llbuglit ("vkind_fromInt: out of range");
    }

  return (vkind)i;
}

static uentry  
  uentry_makeConstantBase (/*@only@*/ cstring name, ctype ct, 
			   typeIdSet access, nstate nullstate,
			   /*@keep@*/ fileloc loc, /*@only@*/ multiVal m)
{
  uentry e = uentry_alloc ();
  
  e->ukind = KCONST;
  e->uname = name;
  e->utype = ct;
  e->sref  = sRef_makeConst (ct);

  sRef_setNullState (e->sref, nullstate, loc);
  e->storageclass = SCNONE;

  if (fileloc_isSpec (loc))
    {
      e->whereSpecified = loc;
      e->whereDeclared = fileloc_undefined;
    }
  else
    {
      e->whereSpecified = fileloc_undefined;
      e->whereDeclared = loc;
    }

  e->whereDefined = fileloc_undefined;
  e->uses = filelocList_new ();
  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->used = FALSE;
  e->lset = FALSE;

  e->warn = warnClause_undefined; /*@i452@*/

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->uconst = (ucinfo) dmalloc (sizeof (*e->info->uconst));
  e->info->uconst->access = access;
  e->info->uconst->macro = FALSE; /*@i523! fix this when macro info added to library */
  uentry_setConstantValue (e, m);
  sRef_storeState (e->sref);

  return (e);
}

static /*@only@*/ uentry  
  uentry_makeVariableBase (/*@only@*/ cstring name, ctype ct, vkind kind, 
			   sstate defstate, nstate isnull, alkind aliased,
			   exkind exp, chkind checked, 
			   /*@only@*/ fileloc loc)
{
  uentry e = uentry_alloc ();

  e->ukind = KVAR;
  e->uname = name;
  e->utype = ct;
  e->storageclass = SCNONE;

  e->sref  = sRef_makeType (ct);
  sRef_setNullState (e->sref, isnull, loc);

  e->whereDefined = fileloc_undefined;

  if (fileloc_isSpec (loc))
    {
      e->whereSpecified = loc;
      e->whereDeclared = fileloc_undefined;
    }
  else
    {
      e->whereSpecified = fileloc_undefined;
      e->whereDeclared = loc;
    }

  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->used = FALSE;
  e->lset = FALSE;

  e->uses = filelocList_new ();
  e->warn = warnClause_undefined; /*@i452@*/

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->var = (uvinfo) dmalloc (sizeof (*e->info->var));
  e->info->var->kind = kind;
  e->info->var->checked = checked;
  e->info->var->defstate = defstate;

  sRef_setDefState (e->sref, defstate, loc);

  e->info->var->nullstate = sRef_getNullState (e->sref);

  sRef_setExKind (e->sref, exp, loc);
  sRef_setAliasKind (e->sref, aliased, loc);

  sRef_storeState (e->sref);

  /*DRL ADDED 9-1-2000 */
  e->info->var->bufinfo = NULL;
  
  return (e);
}

static /*@only@*/ uentry  
uentry_makeDatatypeBase (/*@only@*/ cstring name, ctype ct, ynm abstract, 
			 ynm mut, ctype rtype, alkind ak, exkind exp, 
			 sstate defstate, nstate isnull,
			 /*@only@*/ fileloc loc)
{
  uentry e = uentry_alloc ();

  e->ukind = KDATATYPE;
  /* e->shallowCopy = FALSE; */
  e->uname = name;
  e->utype = ct;
  e->storageclass = SCNONE;
  e->sref  = sRef_makeUnknown ();
  DPRINTF (("Merge null 1: %s", sRef_unparseFull (e->sref)));

  /*
  ** This is only setting null state.  (I think?)
  */

  if (ctype_isUA (ct))
    {
      uentry te = usymtab_getTypeEntrySafe (ctype_typeId (ct));

      if (uentry_isValid (te))
	{
	  sRef_setStateFromUentry (e->sref, te);
	}
      else
	{
	  /* problem for recursive type definitions */
	}
    }
  
  sRef_setAliasKind (e->sref, ak, loc);
  sRef_setExKind (e->sref, exp, loc);

  sRef_setDefState (e->sref, defstate, loc);

  if (ynm_isOn (abstract) && ctype_isUnknown (ct) && isnull == NS_UNKNOWN)
    {
      isnull = NS_ABSNULL;
    }

  DPRINTF (("Merge null: %s", sRef_unparseFull (e->sref)));
  sRef_mergeNullState (e->sref, isnull);

  e->whereDefined = fileloc_copy (loc); /*< bogus!  (but necessary for lexer) >*/

  if (fileloc_isSpec (loc))
    {
      e->whereSpecified = loc;
      e->whereDeclared = fileloc_undefined;
    }
  else
    {
      e->whereSpecified = fileloc_undefined;
      e->whereDeclared = loc;
    }
  
  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->warn = warnClause_undefined; /*@i452@*/

  e->used = FALSE;
  e->lset = FALSE;
  e->uses = filelocList_new ();

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->datatype = (udinfo) dmalloc (sizeof (*e->info->datatype));
  e->info->datatype->abs = abstract;
  e->info->datatype->mut = mut;
  e->info->datatype->type = rtype;

  DPRINTF (("About to store: %s", sRef_unparseFull (e->sref)));
  sRef_storeState (e->sref);
  DPRINTF (("After store: %s", sRef_unparseFull (e->sref)));

  return (e);
}

# ifndef NOLCL
static void uentry_setHasGlobs (uentry ue)
{
  llassert (uentry_isFunction (ue));

  ue->info->fcn->hasGlobs = TRUE;
}

static void uentry_setHasMods (uentry ue)
{
  llassert (uentry_isFunction (ue));

  ue->info->fcn->hasMods = TRUE;
}
# endif

bool uentry_hasGlobs (uentry ue)
{
  if (uentry_isFunction (ue))
    {
      return (ue->info->fcn->hasGlobs);
    }

  return FALSE;
}

bool uentry_hasStateClauseList (uentry ue)
{
  return (uentry_isFunction (ue) && stateClauseList_isDefined (ue->info->fcn->specclauses));
}

bool uentry_hasConditions (uentry ue)
{
  return (uentry_isFunction (ue) 
	  && (functionConstraint_isDefined (ue->info->fcn->preconditions)
	      || functionConstraint_isDefined (ue->info->fcn->postconditions)));
}

stateClauseList uentry_getStateClauseList (uentry ue)
{
  if (!uentry_isFunction (ue))
    {
      llassert (uentry_isFunction (ue));
      return stateClauseList_undefined;
    }

  DPRINTF (("Get state clause list: %s", uentry_unparse (ue)));
  return ue->info->fcn->specclauses;
}

bool uentry_hasMods (uentry ue)
{
  if (uentry_isFunction (ue))
    {
      return (ue->info->fcn->hasMods);
    }

  return FALSE;
}

static uentry  
  uentry_makeFunctionBase (/*@only@*/ cstring name, ctype ct, 
			   typeIdSet access, 
			   bool hasGlobs, /*@only@*/ globSet globs, 
			   bool hasMods, /*@only@*/ sRefSet mods, 
			   alkind ak, exkind exp, 
			   sstate defstate, nstate isnull,
			   exitkind exitCode,
			   specCode sCode,
			   qual nullPred,
			   /*@only@*/ stateClauseList specclauses,
			   /*@only@*/ warnClause warnclause,
			   /*@only@*/ fileloc loc)
{
  uentry e = uentry_alloc ();
  ctype ret;

  /* e->shallowCopy = FALSE; */
  e->ukind = KFCN;
  e->uname = name;
  e->utype = ct;
  e->storageclass = SCNONE;

  if (ctype_isFunction (ct))
    {
      ret = ctype_getReturnType (ct);
    }
  else
    {
      if (ctype_isKnown (ct))
	{
	  llbug (message ("not function: %s", ctype_unparse (ct)));
	}

      ret = ctype_unknown;
    }

  e->sref  = sRef_makeType (ret);

  if (ctype_isUA (ret))
    {
      sRef_setStateFromType (e->sref, ret);
    }

  sRef_setDefined (e->sref, loc);
  sRef_setNullState (e->sref, isnull, loc);

  sRef_setAliasKind (e->sref, ak, loc);
  sRef_setExKind (e->sref, exp, loc);
  sRef_setDefState (e->sref, defstate, loc);

  e->whereSpecified = loc;
  e->whereDefined = fileloc_undefined;

  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->used = FALSE;
  e->lset = FALSE;
  e->uses = filelocList_new ();  
  e->warn = warnclause;

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->fcn = (ufinfo) dmalloc (sizeof (*e->info->fcn));
  
  e->info->fcn->exitCode = exitCode;
  e->info->fcn->specialCode = sCode;
  e->info->fcn->nullPred = nullPred;
  e->info->fcn->access = access;

  e->info->fcn->specclauses = specclauses;
  e->info->fcn->hasGlobs = hasGlobs;
  e->info->fcn->globs = globs;

  e->info->fcn->hasMods = hasMods;
  e->info->fcn->mods = mods;

  e->info->fcn->defparams = uentryList_undefined; 
  e->whereDeclared = fileloc_undefined;

  sRef_storeState (e->sref);

  /*drl 111  30 2000*/
  e->info->fcn->preconditions = NULL;
    /* end drl */

  /*drl 12  28 2000*/
  e->info->fcn->postconditions = NULL;
    /* end drl */
  
  return (e);
}

static /*@only@*/ uentry  
  uentry_makeTagBase (/*@only@*/ cstring name, ekind tagkind, 
		      ctype ct, ctype rtype, /*@only@*/ fileloc loc)
{
  uentry e = uentry_alloc ();
  
  if (tagkind != KSTRUCTTAG && tagkind != KUNIONTAG && tagkind != KENUMTAG)
    {
      llbuglit ("uentry_makeTagBase: not a tag type");
    }

  /* e->shallowCopy = FALSE; */
  e->ukind = tagkind;
  e->uname = name;
  e->utype = ct;
  e->sref  = sRef_makeUnknown ();
  e->storageclass = SCNONE;

  if (fileloc_isSpec (loc))
    {
      e->whereSpecified = loc;
      e->whereDeclared = fileloc_undefined;
    }
  else
    {
      e->whereDeclared = loc;
      e->whereSpecified = fileloc_undefined;
    }

  e->whereDefined = fileloc_undefined;

  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->used = FALSE;
  e->lset = FALSE;
  e->uses = filelocList_new ();
  e->warn = warnClause_undefined; /*@i452@*/

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->datatype = (udinfo) dmalloc (sizeof (*e->info->datatype));
  e->info->datatype->abs  = NO;
  e->info->datatype->mut  = MAYBE;
  e->info->datatype->type = rtype;

  sRef_storeState (e->sref);

  return (e);  
}

static uentry  
  uentry_makeIterBase (/*@only@*/ cstring name, typeIdSet access, 
		       ctype ct, /*@only@*/ fileloc loc)
{
  uentry e = uentry_alloc ();
  
  /* e->shallowCopy = FALSE; */
  e->ukind = KITER;
  e->uname = name;
  e->utype = ct;
  e->sref  = sRef_makeUnknown ();
  e->storageclass = SCNONE;

  if (fileloc_isSpec (loc))
    {
      e->whereSpecified = loc;
      e->whereDeclared = fileloc_undefined;
    }
  else
    {
      e->whereDeclared = loc;
      e->whereSpecified = fileloc_undefined;
    }

  e->whereDefined = fileloc_undefined;
  
  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->used = FALSE;
  e->lset = FALSE;
  e->uses = filelocList_new ();
  e->warn = warnClause_undefined; /*@i452@*/

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->iter = (uiinfo) dmalloc (sizeof (*e->info->iter));
  e->info->iter->access = access;
  e->info->iter->mods = sRefSet_undefined;
  e->info->iter->globs = globSet_undefined;
  
  sRef_storeState (e->sref);
  return (e);
}

static uentry  
  uentry_makeEndIterBase (/*@only@*/ cstring name, typeIdSet access, 
			  /*@only@*/ fileloc loc)
{
  uentry e = uentry_alloc ();

  /* e->shallowCopy = FALSE; */
  e->ukind = KENDITER;
  e->storageclass = SCNONE;
  e->uname = name;
  e->utype = ctype_unknown;
  e->sref  = sRef_makeUnknown ();
  
  if (fileloc_isSpec (loc))
    {
      e->whereSpecified = loc;
      e->whereDeclared = fileloc_undefined;
    }
  else
    {
      e->whereDeclared = loc;
      e->whereSpecified = fileloc_undefined;
    }

  e->whereDefined = fileloc_undefined;

  e->isPrivate = FALSE;
  e->hasNameError = FALSE;

  e->used = FALSE;
  e->lset = FALSE;
  e->uses = filelocList_new ();
  e->warn = warnClause_undefined; /*@i452@*/

  e->info = (uinfo) dmalloc (sizeof (*e->info));
  e->info->enditer = (ueinfo) dmalloc (sizeof (*e->info->enditer));
  e->info->enditer->access = access;
  sRef_storeState (e->sref);

  return (e);
}

void uentry_markFree (/*@unused@*/ /*@owned@*/ uentry u)
{
  /* should save u */
/*@-mustfree@*/
}
/*@=mustfree@*/

/*@only@*/ uentry
uentry_undump (ekind kind, fileloc loc, char **s)
{
  uentry ue;
  
  DPRINTF (("Uentry undump: %s", *s));

  if (**s == '!')
    {
      reader_checkChar (s, '!');
      reader_checkChar (s, '.');
      ue = uentry_makeElipsisMarker ();
    }
  else
    {
      ctype ct = ctype_undump (s);
      cstring name;

      switch (kind)
	{
	case KVAR:
	  {
	    vkind  tkind;
	    sstate defstate;
	    nstate isnull;
	    alkind aliased;
	    exkind exp;
	    chkind checked;
	    
	    reader_checkChar (s, '|');

	    if (reader_optCheckChar (s, '@'))
	      {
		tkind = vkind_fromInt (reader_getInt (s));
		reader_checkChar (s, '|');
	      }
	    else
	      {
		tkind = VKPARAM;
	      }

	    if (reader_optCheckChar (s, '$'))
	      {
		defstate = SS_UNKNOWN;
		isnull = NS_UNKNOWN;
		aliased = AK_IMPTEMP;
		exp = XO_UNKNOWN;
		checked = CH_UNKNOWN;
	      }		
	    else if (reader_optCheckChar (s, '&'))
	      {
		defstate = SS_DEFINED;
		isnull = NS_UNKNOWN;
		aliased = AK_IMPTEMP;
		exp = XO_UNKNOWN;
		checked = CH_UNKNOWN;
	      }		
	    else if (reader_optCheckChar (s, '^'))
	      {
		defstate = SS_UNKNOWN;
		isnull = NS_UNKNOWN;
		aliased = AK_IMPTEMP;
		exp = XO_UNKNOWN;
		checked = CH_UNKNOWN;
	      }		
	    else
	      {
		defstate = sstate_fromInt (reader_getInt (s));      
		advanceField (s); isnull = nstate_fromInt (reader_getInt (s));      
		advanceField (s); aliased = alkind_fromInt (reader_getInt (s));      

		if (reader_optCheckChar (s, '&'))
		  {
		    exp = XO_UNKNOWN;
		    checked = CH_UNKNOWN;
		  }
		else
		  {
		    advanceField (s); exp = exkind_fromInt (reader_getInt (s));      
		    advanceField (s); checked = (chkind) (reader_getInt (s));      
		  }
	      }

	    advanceName (s);
	    name = reader_getStringWord (s);
	    
	    llassert (!cstring_equal (name, GLOBAL_MARKER_NAME));

	    ue = uentry_makeVariableBase (name, ct, tkind, defstate, 
					  isnull, aliased, exp, 
					  checked, fileloc_copy (loc));
	  }
	  break;
	case KDATATYPE: 
	  {
	    ynm abstract;
	    ynm mut;
	    ctype rtype;
	    sstate defstate;
	    nstate isnull;
	    alkind aliased;
	    exkind exp;

	    advanceField (s); abstract = ynm_fromCodeChar (reader_loadChar (s));
	    advanceField (s); mut = ynm_fromCodeChar (reader_loadChar (s));
	    advanceField (s); defstate = sstate_fromInt (reader_getInt (s));      
	    advanceField (s); isnull = nstate_fromInt (reader_getInt (s));      
	    advanceField (s); aliased = alkind_fromInt (reader_getInt (s));      
	    advanceField (s); exp = exkind_fromInt (reader_getInt (s));      
	    advanceField (s); rtype = ctype_undump (s);
	    advanceName (s); 
	    name = reader_getStringWord (s);
	    DPRINTF (("Datatype %s, Exp = %s", name, exkind_unparse (exp)));
	    ue = uentry_makeDatatypeBase (name, ct, abstract, mut, rtype, 
					  aliased, exp, defstate, isnull, 
					  fileloc_copy (loc));
	  }
	  break;
	case KFCN:
	  {
	    alkind     ak;
	    exkind     exp;
	    sstate     defstate;
	    nstate     isnull;
	    exitkind   exitCode;
	    specCode   specc;
	    qual       nullPred;
	    typeIdSet access;
	    bool       hasGlobs;
	    globSet    globs;
	    bool       hasMods;
	    sRefSet    mods;
	    stateClauseList specclauses = stateClauseList_undefined;
	    warnClause warnclause = warnClause_undefined;

	    if (reader_optCheckChar (s, '$'))
	      {
		defstate = SS_DEFINED;
		isnull = NS_UNKNOWN;
		exitCode = XK_UNKNOWN;
		specc = SPC_NONE;
		nullPred = qual_createUnknown ();
	      }
	    else
	      {
		advanceField (s); defstate = sstate_fromInt (reader_getInt (s)); 
		advanceField (s); isnull = nstate_fromInt (reader_getInt (s)); 
		advanceField (s); exitCode = exitkind_fromInt (reader_getInt (s)); 
		advanceField (s); specc = specCode_fromInt (reader_getInt (s)); 
		advanceField (s); nullPred = qual_undump (s);
	      }

	    if (reader_optCheckChar (s, '$'))
	      {
		hasGlobs = FALSE;
		globs = globSet_undefined;
		hasMods = FALSE;
		mods = sRefSet_undefined;
	      }
	    else if (reader_optCheckChar (s, '^'))
	      {
		hasGlobs = TRUE;
		globs = globSet_undefined;
		hasMods = TRUE;
		mods = sRefSet_undefined;
	      }
	    else
	      {
		advanceField (s); hasGlobs = bool_fromInt (reader_getInt (s));
		advanceField (s); globs  = globSet_undump (s);
		advanceField (s); hasMods = bool_fromInt (reader_getInt (s));
		advanceField (s); mods   = sRefSet_undump (s);	    
	      }

	    if (reader_optCheckChar (s, '$'))
	      {
		ak = AK_UNKNOWN;
		exp = XO_UNKNOWN;
	      }
	    else
	      {
		advanceField (s); ak = alkind_fromInt (reader_getInt (s));
		advanceField (s); exp = exkind_fromInt (reader_getInt (s));      
	      }

	    advanceField (s); access = typeIdSet_undump (s);

	    /*
	    ** Optional clauses: Start with @<code>:
	    */

	    while (reader_optCheckChar (s, '@'))
	      {
		if (reader_optCheckChar (s, 'W')) /* Warn clause */
		  {
		    reader_checkChar (s, ':');
		    warnclause = warnClause_undump (s);
		  }
		else if (reader_optCheckChar (s, 'S')) /* stateClause List */
		  {
		    reader_checkChar (s, ':');
		    specclauses = stateClauseList_undump (s);
		  }
		else
		  {
		    BADBRANCH;
		  }
	      }

	    advanceName (s);  name = reader_getStringWord (s);

	    ue = uentry_makeFunctionBase (name, ct, access, 
					  hasGlobs, globs, 
					  hasMods, mods, 
					  ak, exp, defstate, isnull, 
					  exitCode, specc, nullPred,
					  specclauses,
					  warnclause,
					  fileloc_copy (loc));
	    DPRINTF (("Undump: %s", uentry_unparse (ue)));
	  }
	  break;
	case KITER:
	  {
	    typeIdSet access;
	    
	    advanceField (s); access = typeIdSet_undump (s);
	    advanceName (s);  name = reader_getStringWord (s);
	    
	    ue = uentry_makeIterBase (name, access, ct,
				      fileloc_copy (loc));
	  }
	  break;
	case KENDITER:
	  {
	    typeIdSet access;

	    advanceField (s); access = typeIdSet_undump (s);
	    advanceName (s);  name = reader_getStringWord (s);
	    
	    ue = uentry_makeEndIterBase (name, access, fileloc_copy (loc));
	  }
	  break;
	case KENUMCONST:  
	case KCONST:  
	  {
	    typeIdSet access;
	    multiVal val;
	    nstate nullstate;

	    if (reader_optCheckChar (s, '$'))
	      {
		val = multiVal_undefined;
		access = typeIdSet_undefined;
		nullstate = NS_UNKNOWN;
	      }
	    else
	      {
		advanceField (s); val = multiVal_undump (s);
		advanceField (s); access = typeIdSet_undump (s);
		advanceField (s); nullstate = nstate_fromInt (reader_getInt (s));
	      }

	    advanceName (s);  name = reader_getStringWord (s);
	    
	    ue = uentry_makeConstantBase (name, ct, access,
					  nullstate, fileloc_copy (loc), val);
	    break;
	  }
	case KSTRUCTTAG:
	case KUNIONTAG:
	case KENUMTAG:
	  {
	    ctype rtype;
	    
	    advanceField (s); rtype = ctype_undump (s);
	    advanceName (s);  name = reader_getStringWord (s);
	    ue = uentry_makeTagBase (name, kind, ct, rtype, fileloc_copy (loc));
	  }
	  break;
	case KINVALID:
	  llcontbuglit ("uentry_undump: invalid");
	  ue = uentry_undefined;
	  break;
	case KELIPSMARKER:
	  llcontbuglit ("uentry_undump: elips marker");
	  ue = uentry_undefined;
	  break;
	}
    }
  
  return (ue);
}

cstring
uentry_dump (uentry v)
{
  return (uentry_dumpAux (v, FALSE));
}

cstring
uentry_dumpParam (uentry v)
{
  llassertprint (uentry_isVariable (v) || uentry_isElipsisMarker (v),
		 ("dump: %s", uentry_unparseFull (v)));

  return (uentry_dumpAux (v, TRUE));
}

static cstring
uentry_dumpAux (uentry v, bool isParam)
{
  llassert (uentry_isValid (v));
  llassert (!uentry_isGlobalMarker (v));

  DPRINTF (("Dump uentry: [%p]", v));
  DPRINTF (("Dumping entry: %s", uentry_unparseFull (v)));
  
  switch (v->ukind)
    {
    case KINVALID: 
      llcontbuglit ("uentry_dump: invalid entry"); 
      return cstring_undefined;
    case KELIPSMARKER: 
      return (message ("!."));
    case KVAR:     
      {
	cstring sdump;
	vkind vk  = v->info->var->kind;
	sstate dss = sRef_getDefState (v->sref);
	nstate nst = sRef_getNullState (v->sref);
	alkind alk = sRef_getAliasKind (v->sref);
	exkind exk = sRef_getExKind (v->sref);
	chkind chk = v->info->var->checked;

	DPRINTF (("Dumping var"));

	if (dss == SS_UNKNOWN
	    && nst == NS_UNKNOWN
	    && alk == AK_IMPTEMP
	    && exk == XO_UNKNOWN
	    && chk == CH_UNKNOWN)
	  {
	    sdump = cstring_makeLiteral ("$");
	  }
	else if (dss == SS_DEFINED
		 && nst == NS_UNKNOWN
		 && alk == AK_IMPTEMP
		 && exk == XO_UNKNOWN
		 && chk == CH_UNKNOWN)
	  {
	    sdump = cstring_makeLiteral ("&");
	  }
	else if (dss == SS_UNKNOWN
		 && nst == NS_UNKNOWN
		 && alk == AK_UNKNOWN
		 && exk == XO_UNKNOWN
		 && chk == CH_UNKNOWN)
	  {
	    sdump = cstring_makeLiteral ("^");
	  }
	else if (exk == XO_UNKNOWN
		 && chk == CH_UNKNOWN)
	  {
	    sdump = message ("%d@%d@%d&",
			     (int) dss,
			     (int) nst,
			     (int) alk);
	  }
	else
	  {
	    sdump = message ("%d@%d@%d@%d@%d",	
		     (int) dss,
			     (int) nst,
			     (int) alk,
			     (int) exk,
			     (int) chk);
	  }
	

	if (vk != VKPARAM)
	  {
	    return (message ("%q|@%d|%q#%s", 
			     ctype_dump (v->utype), 
			     (int) vk,
			     sdump,
			     isParam ? cstring_undefined : v->uname));
	  }
	else
	  {
	    return (message ("%q|%q#%s", 
			     ctype_dump (v->utype), 
			     sdump,
			     isParam ? cstring_undefined : v->uname));
	  }

      }
    case KDATATYPE: 
      /*
      DPRINTF (("Dumping datatype: %s -> %s type: %s [%d]",
		uentry_unparse (v), 
		exkind_unparse (sRef_getExKind (v->sref)),
		ctype_unparse (v->utype), (int) v->utype));
      */

      return (message ("%q@%s@%s@%d@%d@%d@%d@%q#%s", 
		       ctype_dump (v->utype),
		       ynm_unparseCode (v->info->datatype->abs),
		       ynm_unparseCode (v->info->datatype->mut),
		       (int) sRef_getDefState (v->sref),
		       (int) sRef_getNullState (v->sref),
		       (int) sRef_getAliasKind (v->sref),
		       (int) sRef_getExKind (v->sref),
		       ctype_dump (v->info->datatype->type),
		       v->uname));
    case KFCN:
      {
	cstring sdump, gdump, adump, xdump;
	alkind alk = sRef_getAliasKind (v->sref);
	exkind exk = sRef_getExKind (v->sref);

	if (sRef_getDefState (v->sref) == SS_DEFINED
	    && !nstate_isKnown (sRef_getNullState (v->sref))
	    && !exitkind_isKnown (v->info->fcn->exitCode)
	    && v->info->fcn->specialCode == SPC_NONE
	    && qual_isUnknown (v->info->fcn->nullPred))
	  {
	    sdump = cstring_makeLiteral ("$");
	  }
	else
	  {
	    sdump = message ("@%d@%d@%d@%d@%x",
			     (int) sRef_getDefState (v->sref),
			     (int) sRef_getNullState (v->sref),
			     (int) v->info->fcn->exitCode,
			     (int) v->info->fcn->specialCode,
			     qual_dump (v->info->fcn->nullPred));
	  }

	if (!uentry_hasGlobs(v) && !uentry_hasMods (v))
	  {
	    gdump = cstring_makeLiteral ("$");
	  }
	else if (uentry_hasGlobs (v) && globSet_isEmpty (uentry_getGlobs (v))
		 && uentry_hasMods (v) && sRefSet_isEmpty (uentry_getMods (v)))
	  {
	    gdump = cstring_makeLiteral ("^");
	  }
	else
	  {
	    gdump = message ("@%s@%q@%s@%q",
			     bool_dump (uentry_hasGlobs (v)),
			     globSet_dump (uentry_getGlobs (v)),
			     bool_dump (uentry_hasMods (v)),
			     sRefSet_dump (uentry_getMods (v)));
	  }

	if (alk == AK_UNKNOWN && exk == XO_UNKNOWN)
	  {
	    adump = cstring_makeLiteral ("$");
	  }
	else
	  {
	    adump = message ("@%d@%d", (int) alk, (int) exk);
	  }

	xdump = cstring_undefined;

	if (uentry_hasWarning (v))
	  {
	    xdump = message ("%q@W:%q", xdump, warnClause_dump (v->warn));
	  }

	if (uentry_hasStateClauseList (v))
	  {
	    xdump = message ("%q@S:%q", xdump, stateClauseList_dump (v->info->fcn->specclauses));
	  }

	return (message ("%q%q%q%q@%q%q#%s",
			 ctype_dump (v->utype),
			 sdump,
			 gdump,
			 adump,
			 typeIdSet_dump (uentry_accessType (v)),
			 xdump,
			 v->uname));
      }
    case KITER:
      return (message ("%q@%q#%s",
		       ctype_dump (v->utype),
		       typeIdSet_dump (v->info->iter->access),
		       v->uname));
    case KENDITER:
      return (message ("%q@%q#%s",
		       ctype_dump (v->utype),
		       typeIdSet_dump (uentry_accessType (v)),
		       v->uname));
    case KENUMCONST:  
    case KCONST:  
      {
	cstring sdump;

	if (multiVal_isUnknown (uentry_getConstantValue (v))
	    && typeIdSet_isEmpty (uentry_accessType (v))
	    && (sRef_getNullState (v->sref) == NS_UNKNOWN))
	  {
	    sdump = cstring_makeLiteral ("$");
	  }
	else
	  {
	    sdump = message ("@%q@%q@%d",
			     multiVal_dump (uentry_getConstantValue (v)),
			     typeIdSet_dump (uentry_accessType (v)),
			     (int) sRef_getNullState (v->sref));
	  }

	return (message ("%q%q#%s", 
			 ctype_dump (v->utype), 
			 sdump,
			 v->uname));
      }
    case KSTRUCTTAG:
    case KUNIONTAG:
    case KENUMTAG:
      return (message ("%q@%q#%s", 
		       ctype_dump (v->utype), 
		       ctype_dump (v->info->datatype->type), v->uname));
    }

  BADEXIT;
}

/*@only@*/ cstring
uentry_unparseAbbrev (uentry v)
{
  if (!uentry_isVariable (v))
    {
      llcontbuglit ("uentry_unparseAbbrev: not variable");
      return uentry_unparse (v);
    }

  return (message ("%s %q", ctype_unparseDeep (v->utype), uentry_getName (v)));
}

/*@only@*/ cstring
uentry_unparse (uentry v)
{
  cstring st;

    if (uentry_isUndefined (v)) return (cstring_makeLiteral ("<undefined>"));
  if (uentry_isElipsisMarker (v)) return (cstring_makeLiteral ("..."));

  st = uentry_getName (v);

  if (cstring_isDefined (st))
    {
      return (ctype_unparseDeclaration (v->utype, st)); 
    }
  else
    {
      cstring_free (st);
      return (cstring_copy (ctype_unparse (v->utype)));
    }
}

/*@only@*/ cstring
uentry_unparseFull (uentry v)
{
  if (uentry_isUndefined (v))
    {
      return (cstring_makeLiteral ("<undefined>"));
    }
  else
    {
      cstring res;

      res = message ("[%w] %s %s: %s [spec: %q; decl: %q; def: %q]",
		     (unsigned long) v, ekind_unparse (v->ukind), v->uname,
		     ctype_unparse (v->utype),
		     fileloc_unparse (uentry_whereSpecified (v)),
		     fileloc_unparse (uentry_whereDeclared (v)),
		     fileloc_unparse (uentry_whereDefined (v)));

      DPRINTF (("uentry: %s", res));

      if (uentry_isDatatype (v))
	{
	  res = message ("%q / type: %s mut: %s abs: %s state: %q",
			 res,
			 ctype_unparse 
			 (ctype_isDefined (v->info->datatype->type) 
			  ? v->info->datatype->type : ctype_unknown),
			 ynm_unparse (v->info->datatype->mut),
			 ynm_unparse (v->info->datatype->abs),
			 sRef_unparseState (v->sref));
	}
      else if (uentry_isFunction (v))
	{
	  res = message ("%q / sref: %q / mods: %q / "
			 "globs: %q / clauses: %q / pre: %q / post: %q",
			 res,
			 sRef_unparseFull (v->sref),
			 sRefSet_unparse (v->info->fcn->mods),
			 globSet_unparse  (v->info->fcn->globs),
			 stateClauseList_unparse (v->info->fcn->specclauses),
			 functionConstraint_unparse (v->info->fcn->preconditions),
			 functionConstraint_unparse (v->info->fcn->postconditions));
	}
      else if (uentry_isIter (v))
	{
	  res = message ("%q / sref: %q",
			 res,
			 sRef_unparseFull (v->sref));
	}
      else if (uentry_isVariable (v))
	{
	  res = message ("%q / sref: %q / kind <%d> isout <%d> null <%d> used <%d>",
			 res,
			 sRef_unparseFull (v->sref),
			 (int) v->info->var->kind,
			 (int) v->info->var->defstate,
			 (int) v->info->var->nullstate,
			 (int) v->used);
	  DPRINTF (("sref: [%p]", v->sref));
	  DPRINTF (("sref: %s", sRef_unparseDebug (v->sref)));
	  /* DPRINTF (("sref: %s", sRef_unparseDeep (v->sref)));	   */
	}
      else if (uentry_isConstant (v))
	{
	  res = message ("%q = %q",
			 res, multiVal_unparse (uentry_getConstantValue (v)));
	}
      else
	{
	  res = message ("%q :: %q", res, uentry_unparse (v));
	}

      return res;
    }
}

bool uentry_hasAccessType (uentry e)
{
  if (uentry_isValid (e))
    {
      switch (e->ukind)
	{
	case KITER:
	  return (!typeIdSet_isEmpty (e->info->iter->access));
	case KENDITER:
	  return (!typeIdSet_isEmpty (e->info->enditer->access));
	case KFCN:
	  return (!typeIdSet_isEmpty (e->info->fcn->access));
	case KENUMCONST:
	case KCONST:
	  return (!typeIdSet_isEmpty (e->info->uconst->access));
	default:
	  return FALSE;
	}
    }

  return FALSE;
}
  
typeIdSet uentry_accessType (uentry e)
{
  if (uentry_isValid (e))
    {
      switch (e->ukind)
	{
	case KITER:
	  return (e->info->iter->access);
	case KENDITER:
	  return (e->info->enditer->access);
	case KFCN:
	  return (e->info->fcn->access);
	case KENUMCONST:
	case KCONST:
	  return (e->info->uconst->access);
	default:
	  break;
	}
    }

  return typeIdSet_undefined;
}

bool
uentry_isVariable (uentry e)
{
  return (uentry_isVar (e));
}

bool
uentry_isSpecified (uentry e)
{
  return (uentry_isValid (e) && !fileloc_isUndefined (e->whereSpecified));
}

static bool
uentry_isReallySpecified (uentry e)
{
  return (uentry_isValid (e) 
	  && fileloc_isRealSpec (e->whereSpecified));
}

bool
uentry_isVar (uentry e)
{
  return (!uentry_isUndefined (e) && e->ukind == KVAR);
}

bool 
uentry_isFakeTag (uentry e)
{
  return (uentry_isValid (e) && strchr (cstring_toCharsSafe (e->uname), '!') != 0);
}

bool
uentry_isDatatype (uentry e)
{
  return (!uentry_isUndefined (e) &&
	  (e->ukind == KDATATYPE || e->ukind == KSTRUCTTAG ||
	   e->ukind == KUNIONTAG || e->ukind == KENUMTAG));
}

void
uentry_setAbstract (uentry e)
{
  typeId oldid;

  llassert (uentry_isDatatype (e) 
	    && (ynm_isMaybe (e->info->datatype->abs)));

  oldid = ctype_typeId (e->info->datatype->type);
  e->info->datatype->abs = YES;
  e->info->datatype->type = ctype_createAbstract (oldid);
}

void
uentry_setConcrete (uentry e)
{
  llassert (uentry_isDatatype (e) 
	    && (ynm_isMaybe (e->info->datatype->abs)));

  e->info->datatype->abs = NO;
}

bool
uentry_isAbstractDatatype (uentry e)
{
  return (uentry_isDatatype (e) 
	  && (ynm_isOn (e->info->datatype->abs)));
}

bool
uentry_isMaybeAbstract (uentry e)
{
  return (uentry_isDatatype (e) 
	  && (ynm_isMaybe (e->info->datatype->abs)));
}

bool
uentry_isMutableDatatype (uentry e)
{
  bool res = uentry_isDatatype (e) 
    && (ynm_toBoolRelaxed (e->info->datatype->mut));
  
  return res;
}

bool
uentry_isRefCountedDatatype (uentry e)
{
  return (uentry_isDatatype (e) && (sRef_isRefCounted (uentry_getSref (e))));
}

bool
uentry_isParam (uentry u)
{
  return (uentry_isVariable (u) && (u->info->var->kind == VKPARAM
				    || u->info->var->kind == VKYIELDPARAM));
}

bool
uentry_isExpandedMacro (uentry u)
{
  return (uentry_isVariable (u) && (u->info->var->kind == VKEXPMACRO));
}

bool
uentry_isSefParam (uentry u)
{
  return (uentry_isVariable (u) 
	  && (u->info->var->kind == VKSEFPARAM
	      || u->info->var->kind == VKREFSEFPARAM
	      || u->info->var->kind == VKSEFRETPARAM
	      || u->info->var->kind == VKREFSEFRETPARAM));
}

bool
uentry_isRefParam (uentry u)
{
  return (uentry_isVariable (u) 
	  && (u->info->var->kind == VKREFPARAM
	      || u->info->var->kind == VKREFYIELDPARAM
	      || u->info->var->kind == VKREFSEFPARAM
	      || u->info->var->kind == VKREFSEFRETPARAM));
}

bool
uentry_isAnyParam (uentry u)
{
  return (uentry_isVariable (u) 
	  && ((u->info->var->kind == VKPARAM)
	      || (u->info->var->kind == VKSEFPARAM)
	      || (u->info->var->kind == VKYIELDPARAM)
	      || (u->info->var->kind == VKRETPARAM)
	      || (u->info->var->kind == VKSEFRETPARAM)));
}

sstate 
uentry_getDefState (uentry u)
{
  if (uentry_isValid (u))
    {
      return (sRef_getDefState (u->sref));
    }
  else
    {
      return (SS_UNKNOWN);
    }
}

bool
uentry_isOut (uentry u)
{
  return ((uentry_isVariable (u) && (u->info->var->defstate == SS_ALLOCATED))
	  || (uentry_isDatatype (u) && (sRef_isAllocated (u->sref))));
}

bool
uentry_isPartial (uentry u)
{
  return ((uentry_isVariable (u) && (u->info->var->defstate == SS_PARTIAL))
	  || (uentry_isDatatype (u) && (sRef_isAllocated (u->sref))));
}

bool
uentry_isStateSpecial (uentry u)
{
  return ((uentry_isVariable (u) 
	   && (u->info->var->defstate == SS_SPECIAL))
	  || (uentry_isValid (u) && sRef_isStateSpecial (u->sref)));
}

exitkind uentry_getExitCode (uentry ue) 
{
  if (uentry_isFunction (ue))
    {
      return ue->info->fcn->exitCode;
    }
  else
    {
      return XK_UNKNOWN;
    }
}

qual uentry_nullPred (uentry u)
{
  llassert (uentry_isRealFunction (u));

  if (uentry_isFunction (u))
    {
      return (u->info->fcn->nullPred);
    }
  else
    {
      return qual_createUnknown ();
    }
}

/*
** Note for variables, this is checking the declared state, not the current state.
*/

bool
uentry_possiblyNull (uentry u)
{
  return ((uentry_isVariable (u) && (nstate_possiblyNull (u->info->var->nullstate)))
	  || (uentry_isDatatype (u) && (sRef_possiblyNull (u->sref))));
}

alkind 
uentry_getAliasKind (uentry u)
{
  if (uentry_isValid (u))
    {
      return (sRef_getAliasKind (uentry_getSref (u)));
    }
  else
    {
      return AK_UNKNOWN;
    }
}

exkind 
uentry_getExpKind (uentry u)
{
  if (uentry_isValid (u))
    {
      return (sRef_getExKind (uentry_getSref (u)));
    }
  else
    {
      return XO_UNKNOWN;
    }
}

bool
uentry_isIter (uentry e)
{
  return (!uentry_isUndefined (e) && e->ukind == KITER);
}

bool
uentry_isEndIter (uentry e)
{
  return (!uentry_isUndefined (e) && e->ukind == KENDITER);
}

bool
uentry_isRealFunction (uentry e)
{
  return (uentry_isFunction (e) ||
	  (uentry_isVariable (e) && ctype_isFunction (uentry_getType (e))));
}

bool
uentry_hasName (uentry e)
{
  if (uentry_isValid (e))
    {
      cstring s = e->uname;
      
      return (!(cstring_isEmpty (s) || cstring_equalLit (s, "...")
		|| uentry_isFakeTag (e)));
    }
  else
    {
      return FALSE;
    }
}

/*
** Returns true for fake tags.
** This is used for dumping the library
*/

bool uentry_hasRealName (uentry e)
{
  return (uentry_isValid (e) 
	  && cstring_isNonEmpty (e->uname)
	  && !uentry_isGlobalMarker (e));
}


/*@observer@*/ globSet
uentry_getGlobs (uentry l)
{
  if (uentry_isInvalid (l)) 
    {
      return globSet_undefined;
    }

  if (l->ukind != KFCN)
    {
      if (l->ukind != KITER && l->ukind != KENDITER)
	{
	  if (l->ukind == KVAR)
	    {
	      llbug (message ("Bad call to uentry_getGlobs (var): %q (%s)", 
			      uentry_unparse (l), 
			      ekind_unparse (l->ukind)));
	    }
	  else
	    {
	      llbug (message ("Bad call to uentry_getGlobs: %q (%s)", 
			      uentry_unparse (l), 
			      ekind_unparse (l->ukind)));
	    }
	}
      return globSet_undefined;
    }

  return l->info->fcn->globs;
}

/*@observer@*/ sRefSet
uentry_getMods (uentry l)
{
  llassert (uentry_isValid (l));

  if (l->ukind != KFCN && l->ukind != KITER && l->ukind != KENDITER)
    {
      llcontbug (message ("Bad call to uentry_getMods: %q", uentry_unparse (l)));
      return sRefSet_undefined; 
    }

  return l->info->fcn->mods;
}

ekind
uentry_getKind (uentry e)
{
  llassert (uentry_isValid (e));

  return (e->ukind);
}

/*@observer@*/ multiVal uentry_getConstantValue (uentry e)
{
  llassert (uentry_isEitherConstant (e)); 
  return (sRef_getValue (e->sref));
}

/*@observer@*/ uentryList
uentry_getParams (uentry l)
{
  if (uentry_isInvalid (l)) return uentryList_undefined;

  switch (l->ukind)
    {
    case KFCN:  
    case KITER:
      {
	ctype ct = l->utype;

	if (ctype_isFunction (ct))
	  {
	    return (ctype_argsFunction (ct));
	  }
	else
	  {
	    return uentryList_undefined;
	  }
      }
    case KVAR:  
      {
	ctype ct = l->utype;

	llassert (ctype_isFunction (ct));
	return (ctype_argsFunction (ct));
      }
    BADDEFAULT;
    }
  BADEXIT;
}

/*@observer@*/ cstring
uentry_rawName (uentry e)
{
  if (uentry_isValid (e))
    {
      return (e->uname);
    }
  else
    {
      return cstring_undefined;
    }
}

static cstring
uentry_getOptName (uentry e)
{
  cstring s = uentry_getName (e);

  if (cstring_isDefined (s))
    {
      s = cstring_appendChar (s, ' ');
    }
  
  return s;
}

/*@only@*/ cstring
uentry_getName (uentry e)
{
  cstring ret = cstring_undefined;

  if (uentry_isValid (e))
    {
      if (uentry_isAnyTag (e))
	{
	  ret = fixTagName (e->uname);  
	}
      else if (uentry_isAnyParam (e))
	{
	  ret = cstring_copy (fixParamName (e->uname));
	}
      else
	{
	  ret = cstring_copy (e->uname);
	}
    }

  return ret;
}

cstring uentry_observeRealName (uentry e)
{
  cstring ret = cstring_undefined;

  if (uentry_isValid (e))
    {      
      if (uentry_isAnyTag (e))
	{
	  if (isFakeTag (e->uname))
	    {
	      ret = cstring_undefined;
	    }
	  else
	    {
	      ret = plainTagName (e->uname); 
	    }
	}
      else if (uentry_isAnyParam (e))
	{
	  ret = fixParamName (e->uname);
	}
      else
	{
	  ret = e->uname;
	}
    }

  return ret;
}

cstring uentry_getRealName (uentry e)
{
  if (uentry_isValid (e))
    {
      if (uentry_isAnyTag (e))
	{
	  return (cstring_undefined);
	}
      else
	{
	  return (e->uname);
	}
    }
  return cstring_undefined;
}

ctype uentry_getType (uentry e)
{
  if (uentry_isValid (e))
    {
      return e->utype;
    }
  else
    {
      return ctype_unknown;
    }
}

fileloc uentry_whereLast (uentry e)
{
  fileloc loc;

  if (uentry_isInvalid (e)) 
    {
      return fileloc_undefined;
    }
  
  loc = e->whereDefined;

  if (fileloc_isValid (loc) && !fileloc_isExternal (loc))
    {
      return loc;
    }

  loc = uentry_whereDeclared (e);

  if (fileloc_isValid (loc) && !fileloc_isExternal (loc))
    {
      return loc;
    }

  loc = uentry_whereSpecified (e);
  return loc;
}

fileloc uentry_whereEither (uentry e)
{
  if (uentry_isInvalid (e)) return fileloc_undefined;

  if (fileloc_isDefined (e->whereDefined) 
      && !fileloc_isExternal (e->whereDefined))
    {
      return e->whereDefined;
    }
  else if (fileloc_isDefined (e->whereDeclared))
    {
      return e->whereDeclared;
    }
  else
    {
      return e->whereSpecified;
    }
}

fileloc uentry_whereSpecified (uentry e)
{
  if (uentry_isInvalid (e)) return fileloc_undefined;

  return (e->whereSpecified);
}

fileloc uentry_whereDefined (uentry e)
{
  if (uentry_isInvalid (e)) return fileloc_undefined;

  return (e->whereDefined);
}

fileloc uentry_whereDeclared (uentry e)
{
  if (uentry_isInvalid (e)) return fileloc_undefined;

  return (e->whereDeclared);
}

/*@observer@*/ fileloc
uentry_whereEarliest (uentry e)
{
  if (uentry_isInvalid (e)) return fileloc_undefined;
  
  if (fileloc_isDefined (e->whereSpecified))
    {
      return (e->whereSpecified);
    }
  else if (fileloc_isDefined (e->whereDeclared))
    {
      return (e->whereDeclared);
    }
  else
    {
      return e->whereDefined;
    }
}

void
uentry_setFunctionDefined (uentry e, fileloc loc)
{
  if (uentry_isValid (e))
    {
      llassert (uentry_isFunction (e));

      if (fileloc_isUndefined (e->whereDeclared))
	{
	  e->whereDeclared = fileloc_update (e->whereDeclared, loc);
	}
      
      if (!fileloc_isDefined (e->whereDefined))
	{
	  e->whereDefined = fileloc_update (e->whereDefined, loc);
	}
    }
}

void
uentry_setDeclDef (uentry e, fileloc f)
{
  uentry_setDeclared (e, f);
  
  if (!uentry_isFunction (e)
      && !(uentry_isVariable (e) && uentry_isExtern (e)))
    {
      uentry_setDefined (e, f);
    }
}

void
uentry_setDeclaredForce (uentry e, fileloc f)
{
  llassert (uentry_isValid (e));
  e->whereDeclared = fileloc_update (e->whereDeclared, f);
}

void
uentry_setDeclaredForceOnly (uentry e, fileloc f)
{
  llassert (uentry_isValid (e));
  fileloc_free (e->whereDeclared);
  e->whereDeclared = f;
}

void
uentry_setDeclaredOnly (uentry e, /*@only@*/ fileloc f)
{
  fileloc oldloc;

  llassert (uentry_isValid (e));
  oldloc = e->whereDeclared;  

  if (fileloc_isDefined (oldloc))
    {
      if (fileloc_isLib (oldloc) || fileloc_isImport (oldloc))
	{
	  e->whereDeclared = f;
	  fileloc_free (oldloc);
	}
      else
	{
	  fileloc_free (f);
	}
    }
  else
    {
      e->whereDeclared = f;
      fileloc_free (oldloc);
    }
}
  
void
uentry_setDeclared (uentry e, fileloc f)
{
  fileloc oldloc;

  llassert (uentry_isValid (e));
  oldloc = e->whereDeclared;  

  if (fileloc_isDefined (oldloc))
    {
      if (fileloc_isLib (oldloc) || fileloc_isImport (oldloc))
	{
	  e->whereDeclared = fileloc_update (e->whereDeclared, f);
	}
      else
	{
	  ;
	}
    }
  else
    {
      e->whereDeclared = fileloc_update (e->whereDeclared, f);
    }
}

void
uentry_clearDefined (uentry e)
{
  if (uentry_isValid (e))
    {
      e->whereDefined = fileloc_update (e->whereDefined, fileloc_undefined);
    }
}

void
uentry_setDefined (uentry e, fileloc f)
{
  fileloc oldloc;

  llassert (uentry_isValid (e));
  oldloc = e->whereDefined;

  if (fileloc_isDefined (oldloc))
    {
      if (fileloc_isLib (oldloc) 
	  || fileloc_isImport (oldloc)
	  || fileloc_isBuiltin (oldloc) 
	  || fileloc_isPreproc (oldloc))
	{
	  e->whereDefined = fileloc_update (e->whereDefined, f);
	}
      else
	{
	  if (fileloc_equal (oldloc, f) || context_processingMacros ())
	    {
	      ; /* okay */
	    }
	  else
	    {
	      if (optgenerror (FLG_REDEF,
			       message ("%s %q redefined", 
					ekind_capName (e->ukind),
					uentry_getName (e)),
			       f))
		{
		  llgenindentmsg (message ("Previous definition of %q", 
					   uentry_getName (e)),
				  e->whereDefined);
		}
	    }
	}
    }
  else
    {
      e->whereDefined = fileloc_update (e->whereDefined, f);
    }
}

bool
uentry_isCodeDefined (uentry e)
{
  llassert (uentry_isValid (e));

  return (fileloc_isDefined (e->whereDefined));
}

bool
uentry_isDeclared (uentry e)
{
  if (uentry_isValid (e))
    {
      return (fileloc_isDefined (e->whereDeclared));
    }

  return FALSE;
}

sRef uentry_getSref (uentry e)
{
  /* not true, used for functions too (but shouldn't be? */
  /* llassertprint (e->ukind == KVAR, ("uentry_getSref: not variable!")); */

  if (uentry_isInvalid (e)) return sRef_undefined;
  
  return (e->sref);
}

sRef uentry_getOrigSref (uentry e)
{
  /*@i523*/ /* evans 2001-09-09 - need to fix this 
  if (uentry_isValid (e))
    {
      if (uentry_isVariable (e))
	{
	  return e->info->var->origsref;
	}
      else
	{
	  sRef sr = sRef_copy (uentry_getSref (e));
	  
	  sRef_resetState (sr);
	  sRef_clearDerived (sr);
	  return (sr);
	}
    }
  else
    {
      return sRef_undefined;
    }
  */

  if (uentry_isValid (e))
    {
      sRef sr = sRef_copy (uentry_getSref (e));
      
      sRef_resetState (sr);
      sRef_clearDerived (sr);
      
      if (uentry_isVariable (e))
	{
	  sRef_setDefState (sr, e->info->var->defstate, fileloc_undefined);
	  sRef_setNullState (sr, e->info->var->nullstate, fileloc_undefined);
	}
      
      return (sr);
    }
  else
    {
      return sRef_undefined;
    }
}

/*
** requires: uentry e is not in a hashed symbol table
*/

void 
uentry_setName (uentry e, /*@only@*/ cstring n)
{
  llassert (uentry_isValid (e));

  cstring_free (e->uname);
  e->uname = n;
}

void
uentry_setType (uentry e, ctype t)
{
  if (uentry_isValid (e)) 
    {
      e->utype = t;
      sRef_setType (e->sref, t);
    }
}

void
uentry_resetParams (uentry ue, /*@only@*/ uentryList pn)
{
  ctype rct;
  ctype rettype = ctype_unknown;
  
  llassert (uentry_isValid (ue));

  uentry_convertVarFunction (ue);
  llassert (uentry_isFunction (ue));

  rct = ctype_realType (ue->utype);

  if (ctype_isFunction (rct))
    {
      rettype = ctype_getReturnType (rct);
    }

  ue->utype = ctype_makeNFParamsFunction (rettype, pn);      
}

void
uentry_setRefParam (uentry e)
{
  if (!uentry_isVar (e))
    {
      llbug (message ("uentry_setParam: not variable: %q", uentry_unparse (e)));
    }
  else
    {
      if (e->info->var->kind == VKSEFPARAM)
	{
	  e->info->var->kind = VKREFSEFPARAM;
	}
      else if (e->info->var->kind == VKSEFRETPARAM)
	{
	  e->info->var->kind = VKREFSEFRETPARAM;
	}
      else if (e->info->var->kind == VKYIELDPARAM)
	{
	  e->info->var->kind = VKREFYIELDPARAM;
	}
      else
	{
	  e->info->var->kind = VKREFPARAM;
	}
    }
}

void
uentry_setParam (uentry e)
{
  if (!uentry_isVar (e))
    {
      if (uentry_isElipsisMarker (e))
	{

	}
      else
	{
	  llbug (message ("uentry_setParam: not variable: %q", uentry_unparse (e)));
	}
    }
  else
    {
      cstring oldname;

      if (e->info->var->kind == VKYIELDPARAM 
	  || e->info->var->kind == VKSEFPARAM
	  || e->info->var->kind == VKSEFRETPARAM)
	{
	  ;
	}
      else
	{
	  e->info->var->kind = VKPARAM;
	}

      oldname = e->uname;
      e->uname = makeParam (e->uname);
      cstring_free (oldname);
    }
}

void
uentry_setSref (uentry e, sRef s)
{
  if (uentry_isValid (e))
    {
      if (sRef_isValid (e->sref))
	{
	  sRef_mergeStateQuietReverse (e->sref, s);
	}
      else
	{
	  e->sref = sRef_saveCopy (s);
	}
    }
}

ctype
uentry_getAbstractType (uentry e)
{
  llassert (uentry_isDatatype (e));

  /*
  ** This assertion removed.
  ** Okay to have undefined type, for system types
  
  llassertprintret (!ctype_isUndefined (e->info->datatype->type),
		    ("uentry_getAbstractType %q: undefined", uentry_unparseFull (e)),
		    e->utype);
		    
  */

  if (ctype_isUndefined (e->info->datatype->type))
    {
      return ctype_unknown;
    }

  /*
  ** Sadly, a kludge...
  */

  if (ctype_isUserBool (e->info->datatype->type)) {
    return ctype_bool;
  }

  return e->info->datatype->type;
}

ctype uentry_getRealType (uentry e)
{
  ctype ct;
  typeId uid = USYMIDINVALID;

  if (uentry_isInvalid (e))
    {
      return ctype_unknown;
    }

  llassertprint (uentry_isDatatype (e), ("not datatype: %s", uentry_unparse (e)));

  if (uentry_isAnyTag (e))
    {
      return (e->utype);
    }
  
  if (uentry_isAbstractType (e))
    {
      ct = uentry_getAbstractType (e);      

      if (ctype_isManifestBool (ct)) {
	return ct;
      }

      llassert (ctype_isUA (ct));
      
      uid = ctype_typeId (ct);
      
      if (!context_hasAccess (uid))
	{
	  return (ct);
	}
    }

  ct = uentry_getType (e);

  /* if (ctype_isUserBool (ct)) return ct; */

  if (ctype_isManifestBool (ct)) {
    return ctype_bool;
  }
  
  if (ctype_isUA (ct))
    {
      usymId iid = ctype_typeId (ct);
      
      if (usymId_equal (iid, uid))
	{	  
	  llcontbug (message ("uentry_getRealType: recursive type! %s",
			      ctype_unparse (ct)));
	  return ct;
	}
      else
	{
	  /* evs 2000-07-25: possible infinite recursion ? */
	  uentry ue2 = usymtab_getTypeEntry (iid);

	  if (ue2 == e)
	    {
	      llcontbug (message ("Bad recursion: %q", uentry_unparseFull (e)));
	      return ctype_unknown;
	    }

	  return uentry_getRealType (ue2);
	}
    }
  else
    {
      return ct;
    }
}

ctype uentry_getForceRealType (uentry e)
{
  ctype   ct;
  typeId uid = USYMIDINVALID;

  if (uentry_isInvalid (e))
    {
      return ctype_unknown;
    }

  llassertprint (uentry_isDatatype (e), ("not datatype: %s", uentry_unparse (e)));
  
  if (uentry_isAnyTag (e))
    {
      return (e->utype);
    }
  
  if (uentry_isAbstractType (e))
    {
      ct = uentry_getAbstractType (e);      
      llassert (ctype_isUA (ct));
      
      uid = ctype_typeId (ct);
      /* no check for access! */
    }
  
  ct = uentry_getType (e);

  /* evs 2000-07-25 */
  /* if (ctype_isUserBool (ct)) return ct; */

  if (ctype_isManifestBool (ct)) {
    return ctype_bool;
  }
  
  if (ctype_isUA (ct))
    {
      usymId iid = ctype_typeId (ct);
      
      if (usymId_equal (iid, uid))
	{	  
	  llcontbug (message ("uentry_getRealType: recursive type! %s",
			      ctype_unparse (ct)));
	  return ct;
	}
      else
	{
	  return uentry_getForceRealType (usymtab_getTypeEntry (iid));
	}
    }
  else
    {
      return ct;
    }
}

uentry uentry_nameCopy (cstring name, uentry e)
{
  uentry enew = uentry_alloc ();

  llassert (uentry_isValid (e));

  /* enew->shallowCopy = FALSE; */
  enew->ukind = e->ukind;
  enew->uname = name;
  enew->utype = e->utype;
  enew->whereSpecified = fileloc_copy (e->whereSpecified);
  enew->whereDefined = fileloc_copy (e->whereDefined);
  enew->whereDeclared = fileloc_copy (e->whereDeclared);
  enew->sref = sRef_copy (e->sref); 
  enew->used = e->used;
  enew->lset = FALSE;
  enew->isPrivate = e->isPrivate;
  enew->hasNameError = FALSE;

  enew->uses = filelocList_new ();
  enew->warn = warnClause_undefined; 

  enew->storageclass = e->storageclass;
  enew->info = uinfo_copy (e->info, e->ukind);

  return enew;
}

void
uentry_setDatatype (uentry e, usymId uid)
{
  llassert (uentry_isDatatype (e));

  if (uentry_isAbstractType (e))
    {
      e->info->datatype->type = ctype_createAbstract (uid);
    }
  else
    {
      e->info->datatype->type = ctype_createUser (uid);
    }
}

static void 
uentry_setSpecDef (/*@special@*/ uentry e, /*@keep@*/ fileloc f)
   /*@defines e->whereSpecified, e->whereDeclared, e->whereDefined@*/
   /*@modifies e@*/
{
  llassert (uentry_isValid (e));

  if (fileloc_isSpec (f) || fileloc_isImport (f))
    {
      e->whereSpecified = f;
      e->whereDeclared  = fileloc_undefined;
      e->whereDefined  = fileloc_undefined;
    }
  else
    {
      e->whereSpecified = fileloc_undefined;
      e->whereDeclared  = f;
      e->whereDefined  = fileloc_undefined;
    }

  llassert (fileloc_storable (f));
}

static void
ucinfo_free (/*@only@*/ ucinfo u)
{
  sfree (u);
}

static void
uvinfo_free (/*@only@*/ uvinfo u)
{
  /*drl7x added 6/29/01 */
  free (u->bufinfo); /* evans - 2001-07-19 fixed this bug */
  sfree (u);
}

static void
udinfo_free (/*@only@*/ udinfo u)
{
  sfree (u);
}

static void
ufinfo_free (/*@only@*/ ufinfo u)
{
  globSet_free (u->globs);
  sRefSet_free (u->mods);
  stateClauseList_free (u->specclauses);
  sfree (u);
}

static void
uiinfo_free (/*@only@*/ uiinfo u)
{
  sfree (u);
}

static void
ueinfo_free (/*@only@*/ ueinfo u)
{
  sfree (u);
}

static /*@only@*/ ucinfo
ucinfo_copy (ucinfo u)
{
  ucinfo ret = (ucinfo) dmalloc (sizeof (*ret));
  ret->access = u->access;
  ret->macro = u->macro;
  return ret;
}

static /*@only@*/ uvinfo
uvinfo_copy (uvinfo u)
{
  uvinfo ret = (uvinfo) dmalloc (sizeof (*ret));
  
  ret->kind = u->kind;
  ret->nullstate = u->nullstate;
  ret->defstate = u->defstate;
  ret->checked = u->checked;

  /*@i523 ret->origsref = sRef_copy (u->origsref); */

  /* drl added 07-02-001 */
  /* copy null terminated information */

  if (u->bufinfo != NULL)
    {
      ret->bufinfo = (bbufinfo) dmalloc (sizeof( * u->bufinfo ) );
      ret->bufinfo->bufstate = u->bufinfo->bufstate;
      ret->bufinfo->size     = u->bufinfo->size;
      ret->bufinfo->len      = u->bufinfo->len;
      return ret;
    }
  else
    {
      ret->bufinfo = NULL;
      return ret;
    }
    
}

static /*@only@*/ udinfo
udinfo_copy (udinfo u)
{
  udinfo ret = (udinfo) dmalloc (sizeof (*ret));

  ret->abs = u->abs;
  ret->mut = u->mut;
  ret->type = u->type;

  return ret;
}

static /*@only@*/ ufinfo
ufinfo_copy (ufinfo u)
{
  ufinfo ret = (ufinfo) dmalloc (sizeof (*ret));

  ret->hasGlobs = u->hasGlobs;
  ret->hasMods = u->hasMods;
  ret->exitCode = u->exitCode;
  ret->specialCode = u->specialCode;
  ret->nullPred = u->nullPred;
  ret->access = u->access;
  ret->globs = globSet_newCopy (u->globs);
  ret->mods = sRefSet_newCopy (u->mods);
  ret->defparams = u->defparams;
  ret->specclauses = stateClauseList_copy (u->specclauses);

  ret->preconditions = functionConstraint_copy (u->preconditions);
  ret->postconditions = functionConstraint_copy (u->postconditions);
  
  return ret;
}

static /*@only@*/ uiinfo
uiinfo_copy (uiinfo u)
{
  uiinfo ret = (uiinfo) dmalloc (sizeof (*ret));

  ret->access = u->access;
  ret->globs = globSet_newCopy (u->globs);
  ret->mods = sRefSet_newCopy (u->mods);

  return (ret);
}

static /*@only@*/ ueinfo
ueinfo_copy (ueinfo u)
{
  ueinfo ret = (ueinfo) dmalloc (sizeof (*ret));

  ret->access = u->access;
  return ret;
}

static void
uinfo_free (uinfo u, ekind kind)
{
  switch (kind)
    {
    case KENUMCONST:
    case KCONST:       ucinfo_free (u->uconst); break;
    case KVAR:         uvinfo_free (u->var); break;
    case KSTRUCTTAG:
    case KUNIONTAG:
    case KENUMTAG:
    case KDATATYPE:    udinfo_free (u->datatype); break;
    case KFCN:         ufinfo_free (u->fcn); break;
    case KITER:        uiinfo_free (u->iter); break;
    case KENDITER:     ueinfo_free (u->enditer); break;
    case KELIPSMARKER: break;
    case KINVALID:     break;
    }
  
    sfree (u);
}

static /*@only@*/ /*@null@*/ uinfo
uinfo_copy (uinfo u, ekind kind)
{
  if (kind == KELIPSMARKER || kind == KINVALID)
    {
      return NULL;
    }
  else
    {
      uinfo ret = (uinfo) dmalloc (sizeof (*ret));
      
      switch (kind)
	{
	case KENUMCONST:
	case KCONST:    ret->uconst = ucinfo_copy (u->uconst); break;
	case KVAR:      ret->var = uvinfo_copy (u->var); break;
	case KSTRUCTTAG:
	case KUNIONTAG:
	case KENUMTAG:
	case KDATATYPE: ret->datatype = udinfo_copy (u->datatype); break;
	case KFCN:      ret->fcn = ufinfo_copy (u->fcn); break;
	case KITER:     ret->iter = uiinfo_copy (u->iter); break;
	case KENDITER:  ret->enditer = ueinfo_copy (u->enditer); break;
	BADDEFAULT;
	}
      return ret;
    }
}

static void
uentry_reallyFree (/*@notnull@*/ /*@only@*/ uentry e)
{
  filelocList_free (e->uses);
  cstring_free (e->uname);
  
  uinfo_free (e->info, e->ukind);
  
  fileloc_free (e->whereSpecified); 
  fileloc_free (e->whereDefined); 
  fileloc_free (e->whereDeclared); 

  warnClause_free (e->warn);

  nuentries--;
  sfree (e);
  }

extern void uentry_markOwned (/*@owned@*/ uentry u)
{
  sfreeEventually (u);
}

void
uentry_free (/*@only@*/ uentry e)
{
  if (uentry_isValid (e) && !uentry_isElipsisMarker (e))
    {
      uentry_reallyFree (e);
    }
}

/*
** For uentry's in the global or file scope
*/

void
uentry_freeComplete (/*@only@*/ uentry e)
{
  if (uentry_isValid (e) && !uentry_isElipsisMarker (e))
    {
      DPRINTF (("Free complete: %s", sRef_unparseFull (e->sref)));
      /*@i@*/ sRef_free (e->sref);
      e->sref = sRef_undefined;
      uentry_reallyFree (e);
    }
}

/*
** requires old->kind != new->kind, old->uname = new->uname
*/

static void
KindConformanceError (/*@unique@*/ uentry old, uentry unew, bool mustConform)
{
  llassert (uentry_isValid (old));
  llassert (uentry_isValid (unew));

  if (uentry_isEitherConstant (unew)
      && (fileloc_isPreproc (uentry_whereDeclared (old))
	  || ctype_isUnknown (old->utype))
      && !uentry_isSpecified (old))
    {
      ; /* no error */
    }
  else 
    {
      if (mustConform)
	{
	  if (!uentry_isDeclared (old))
	    {
	      if (uentry_isSpecified (old))
		{
		  if (uentry_isSpecified (unew))
		    {
		      llbuglit ("Respecification!");
		    }
		  else if (uentry_isDeclared (unew))
		    {
		      if (optgenerror
			  (FLG_INCONDEFS,
			   message ("%s %q inconsistently declared as %s: %t",
				    ekind_capName (old->ukind),
				    uentry_getName (unew),
				    ekind_unparseLong (unew->ukind),
				    unew->utype),
			   uentry_whereLast (unew)))  /* evans 2001-12-30: was uentry_whereDeclared */
			{
			  uentry_showWhereLastKind (old);
			}
		    }
		  else
		    {
		      BADEXIT;
		    }
		}
	      else
		{
		  if (optgenerror
		      (FLG_INCONDEFS,
		       message ("%s %q inconsistently declared as %s: %t",
				ekind_capName (old->ukind),
				uentry_getName (unew),
				ekind_unparseLong (unew->ukind),
				unew->utype),
		       uentry_whereLast (unew))) /* evans 2001-12-30: was uentry_whereDeclared */
		    {
		      uentry_showWhereLastKind (old);
		    }
		}
	    }
	  else
	    {
	      llassert (uentry_isDeclared (unew));

	      DPRINTF (("Old: \n\t%s", uentry_unparseFull (old)));
	      DPRINTF (("New: \n\t%s", uentry_unparseFull (unew)));

	      if (optgenerror
		  (FLG_INCONDEFS,
		   message ("%s %q inconsistently redeclared as %s",
			    ekind_capName (old->ukind),
			    uentry_getName (unew),
			    ekind_unparseLong (unew->ukind)),
		   uentry_whereLast (unew))) /* evans 2001-12-30: was uentry_whereDeclared */
		{
		  uentry_showWhereLastKind (old);
		}
	    }
	}
    }

  uentry_updateInto (old, unew);
}

/*
** def is the definition of spec, modifies spec
**
** reports any inconsistencies
** returns the summary of all available information
** if spec and def are inconsistent, def is returned
*/

void
uentry_showWhereLast (uentry spec)
{
  if (uentry_isValid (spec))
    {
      if (fileloc_isDefined (spec->whereDefined)
	  && !fileloc_isLib (spec->whereDefined)
	  /*!! && !fileloc_isPreproc (spec->whereDefined) */ )
	{
	  llgenindentmsg (message ("Previous definition of %q: %t", 
				   uentry_getName (spec),
				   uentry_getType (spec)),
			  uentry_whereDefined (spec));
	}
      else if (uentry_isDeclared (spec))
	{
	  llgenindentmsg (message ("Previous declaration of %q: %t", 
				   uentry_getName (spec),
				   uentry_getType (spec)),
			  uentry_whereDeclared (spec));
	}
      else if (uentry_isSpecified (spec))
	{
	  if (uentry_hasName (spec))
	    {
	      llgenindentmsg (message ("Specification of %q: %t", 
				       uentry_getName (spec),
				       uentry_getType (spec)),
			      uentry_whereSpecified (spec));
	    }
	  else
	    {
	      llgenindentmsg (message ("Specification: %t", uentry_getType (spec)),
			      uentry_whereSpecified (spec));
	    }
	}
      else
	{
	  /* nothing to show */
	}
    }
}

static void
uentry_showWhereLastKind (uentry spec)
{
  if (uentry_isValid (spec))
    {
      if (fileloc_isDefined (spec->whereDefined)
	  && !fileloc_isLib (spec->whereDefined)
	  /*!! && !fileloc_isPreproc (spec->whereDefined) */ )
	{
	  llgenindentmsg (message ("Previous definition of %q as %s: %t", 
				   uentry_getName (spec),
				   ekind_unparseLong (spec->ukind),
				   uentry_getType (spec)),
			  uentry_whereDefined (spec));
	}
      else if (uentry_isDeclared (spec))
	{
	  llgenindentmsg (message ("Previous declaration of %q as %s: %t", 
				   uentry_getName (spec),
				   ekind_unparseLong (spec->ukind),
				   uentry_getType (spec)),
			  uentry_whereDeclared (spec));
	}
      else if (uentry_isSpecified (spec))
	{
	  if (uentry_hasName (spec))
	    {
	      llgenindentmsg (message ("Specification of %q as %s: %t", 
				       uentry_getName (spec),
				       ekind_unparseLong (spec->ukind),
				       uentry_getType (spec)),
			      uentry_whereSpecified (spec));
	    }
	  else
	    {
	      llgenindentmsg (message ("Specification as %s: %t",
				       ekind_unparseLong (spec->ukind),
				       uentry_getType (spec)),
			      uentry_whereSpecified (spec));
	    }
	}
      else
	{
	  /* nothing to show */
	}
    }
}

void
uentry_showDefSpecInfo (uentry ce, fileloc fwhere)
{
  fileloc loc = uentry_whereDefined (ce);
  
  if (fileloc_isUser (loc) && !fileloc_equal (loc, fwhere))
    {
      llgenindentmsg (message ("Definition of %q", uentry_getName (ce)),
		      loc);
    }

  loc = uentry_whereSpecified (ce);
  
  if (fileloc_isUser (loc) && !fileloc_equal (loc, fwhere))
    {
      llgenindentmsg (message ("Specification of %q", uentry_getName (ce)),
		      loc);
    }
}

void uentry_showWhereLastExtra (uentry spec, cstring extra)
{
  if (uentry_isDeclared (spec))
    {
      llgenindentmsg (message ("Previous declaration of %q: %q", 
			       uentry_getName (spec), extra),
		      uentry_whereDeclared (spec));
    }
  else if (uentry_isSpecified (spec))
    {
      llgenindentmsg (message ("Specification of %q: %q", 
			       uentry_getName (spec), extra),
		      uentry_whereSpecified (spec));
    }
  else
    {
      cstring_free (extra);
    }
}

void
uentry_showWhereDeclared (uentry spec)
{
  if (uentry_isDeclared (spec))
    {
      if (uentry_hasName (spec))
	{
	  llgenindentmsg (message ("Declaration of %q", uentry_getName (spec)),
			  uentry_whereDeclared (spec));
	}
      else
	{
	  llgenindentmsg (cstring_makeLiteral ("Declaration"), uentry_whereDeclared (spec));
	}
    }
  else if (uentry_isSpecified (spec))
    {
      if (uentry_hasName (spec))
	{
	  llgenindentmsg (message ("Specification of %q", uentry_getName (spec)),
			  uentry_whereSpecified (spec));
	}
      else
	{
	  llgenindentmsg (cstring_makeLiteral ("Specification"), uentry_whereSpecified (spec));
	}
    }
  else
    {
      /* nothing to show */
    }
    
}

void
uentry_showWhereAny (uentry spec)
{
  if (uentry_isDeclared (spec))
    {
      if (uentry_hasName (spec))
	{
	  llgenindentmsg (message ("Declaration of %q", uentry_getName (spec)),
			  uentry_whereDeclared (spec));
	}
      else
	{
	  llgenindentmsg (cstring_makeLiteral ("Declaration"), uentry_whereDeclared (spec));
	}
    }
  else if (uentry_isSpecified (spec))
    {
      if (uentry_hasName (spec))
	{
	  llgenindentmsg (message ("Specification of %q",
				   uentry_getName (spec)),
			  uentry_whereSpecified (spec));
	}
      else
	{
	  llgenindentmsg (cstring_makeLiteral ("Specification"), 
			  uentry_whereSpecified (spec));
	}
    }
  else if (fileloc_isDefined (uentry_whereDefined (spec))) 
    {
      if (uentry_hasName (spec))
	{
	  llgenindentmsg (message ("Definition of %q", uentry_getName (spec)),
			  uentry_whereDefined (spec));
	}
      else
	{
	  llgenindentmsg (cstring_makeLiteral ("Definition"), uentry_whereDefined (spec));
	}
    }
  else
    {
      /* nothing to show */
    }
}

void
uentry_showWhereDefined (uentry spec)
{
  if (uentry_isCodeDefined (spec))
    {
      llgenindentmsg (message ("Previous definition of %q", uentry_getName (spec)),
		      uentry_whereDefined (spec));
    }
}

void
uentry_showWhereLastPlain (uentry spec)
{
  if (uentry_isDeclared (spec))
    {
      llgenindentmsg (message ("Previous declaration of %q", uentry_getName (spec)),
		      uentry_whereDeclared (spec));
    }
  else if (uentry_isSpecified (spec))
    {
      llgenindentmsg (message ("Specification of %q", uentry_getName (spec)),
		      uentry_whereSpecified (spec));
    }
  else
    {
          }
}

static void
uentry_showWhereLastVal (uentry spec, cstring val)
{
  if (uentry_isDeclared (spec))
    {
      llgenindentmsg (message ("Previous declaration of %q: %s", 
			       uentry_getName (spec), val),
		      uentry_whereDeclared (spec));
    }
  else if (uentry_isSpecified (spec))
    {
      llgenindentmsg (message ("Specification of %q: %s", 
			       uentry_getName (spec), val),
		      uentry_whereSpecified (spec));
    }
  else
    {
    }
}

void
uentry_showWhereSpecified (uentry spec)
{
  if (uentry_isSpecified (spec))
    {
      if (uentry_hasName (spec))
	{
	  llgenindentmsg (message ("Specification of %q", uentry_getName (spec)),
			  uentry_whereSpecified (spec));
	}
      else
	{
	  llgenindentmsg (cstring_makeLiteral ("Specification"), 
			  uentry_whereSpecified (spec));
	}
    }
  else if (uentry_isDeclared (spec))
    {
      llgenindentmsg (message ("Declaration of %q", uentry_getName (spec)),
		      uentry_whereDeclared (spec));
    }
  else
    {
      /* nothing to show */
    }
}

void
uentry_showWhereSpecifiedExtra (uentry spec, cstring s)
{
  if (uentry_isSpecified (spec))
    {
      if (uentry_hasName (spec))
	{
	  llgenindentmsg (message ("Specification of %q: %q", 
				   uentry_getName (spec), s),
			  uentry_whereSpecified (spec));
	}
      else
	{
	  llgenindentmsg (message ("Specification: %q", s), 
			  uentry_whereSpecified (spec));
	}
    }
  else if (uentry_isDeclared (spec))
    {
      llgenindentmsg (message ("Declaration of %q: %q", 
			       uentry_getName (spec), s),
		      uentry_whereDeclared (spec));
    }
  else
    {
      llgenindentmsg (message ("Previous: %q", s),
		      uentry_whereLast (spec));
    }
}

/*
**
*/

static void
checkStructConformance (uentry old, uentry unew)
{
  ctype oldr, newr; 
  uentryList fold, fnew;

  /*
  ** requires: types of old and new are structs or unions
  */

  llassert (uentry_isValid (old));
  llassert (uentry_isValid (unew));

  oldr = ctype_realType (old->utype);
  fold =  ctype_getFields (oldr);

  newr = ctype_realType (unew->utype);
  fnew = ctype_getFields (newr);

  if (!uentryList_matchFields (fold, fnew))
    {
      if (fileloc_equal (uentry_whereLast (old),
			 uentry_whereLast (unew)))
	{
	  ; /* cheat! */
	}
      else 
	{
	  if (optgenerror 
	      (FLG_MATCHFIELDS,
	       message ("%q %q %rdeclared with fields { %q }, %s "
			"with fields { %q }",
			cstring_makeLiteral (ctype_isStruct (newr) ? "Structure": "Union"),
			uentry_getName (old), 
			uentry_isDeclared (old),
			uentryList_unparseAbbrev (fnew),
			uentry_specOrDefName (old),
			uentryList_unparseAbbrev (fold)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereLastPlain (old);
	      uentryList_showFieldDifference (fold, fnew);
	    }
	}

      old->utype = unew->utype;
    }
}

static void
checkEnumConformance (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew)
{
  /*
  ** requires old and new are enums
  */
  
  ctype        rold = ctype_realType (old->utype);
  ctype        rnew = ctype_realType (unew->utype);
  enumNameList eold = ctype_elist (rold);
  enumNameList enew = ctype_elist (rnew);
  
  if (!enumNameList_match (eold, enew))
    {
      if (optgenerror 
	  (FLG_MATCHFIELDS,
	   message ("Enum %q declared with members { %q } but "
		    "specified with members { %q }",
		    uentry_getName (old), 
		    enumNameList_unparse (enew),
		    enumNameList_unparse (eold)),
	   uentry_whereDeclared (unew)))
	{
	  uentry_showWhereSpecified (old);
	  old->utype = unew->utype;
	}
    }
}

/*
** either oldCurrent or newCurrent may be undefined!
*/

static void
paramTypeError (uentry old, uentry oldCurrent, ctype oldType,
		uentry unew, uentry newCurrent, ctype newType,
		int paramno)
{
  bool hasError = FALSE;

  if (uentry_isValid (newCurrent) && uentry_isDeclared (newCurrent))
    {
      if (uentry_hasName (newCurrent))
	{
	  hasError = optgenerror 
	    (FLG_TYPE,
	     message ("Parameter %d, %q, of function %q has inconsistent type: "
		      "declared %t, %s %t",
		      paramno + 1, uentry_getName (newCurrent), 
		      uentry_getName (unew),
		      newType, uentry_specOrDefName (old), oldType),
	     uentry_whereDeclared (newCurrent));
	}
      else
	{
	  hasError = optgenerror
	    (FLG_TYPE,
	     message ("Parameter %d of function %q has inconsistent type: "
		      "declared %t, %s %t",
		      paramno + 1, uentry_getName (unew),
		      newType, uentry_specOrDefName (old), oldType),
	     uentry_whereDeclared (newCurrent));

	  DPRINTF (("type: %s / %s",
		    ctype_unparse (newType),
		    ctype_unparse (ctype_realType (newType))));
	}
    }
  else 
    {
      if (uentry_isDeclared (unew))
	{
	  hasError = optgenerror 
	    (FLG_TYPE,
	     message ("Parameter %d of function %s has inconsistent type: "
		      "declared %t, %s %t",
		      paramno + 1, unew->uname, 
		      newType, uentry_specOrDefName (old), oldType),
	     uentry_whereDeclared (unew));
	}
      else
	{
	  hasError = optgenerror
	    (FLG_TYPE,
	     message ("Parameter %d of function %s has inconsistent type: "
		      "declared %t, %s %t",
		      paramno + 1, unew->uname, 
		      newType, uentry_specOrDefName (old), oldType),
	     uentry_whereDeclared (unew));
	}
    }
  
  if (hasError)
    {
      DPRINTF (("Here: %s / %s",
		uentry_unparseFull (oldCurrent),
		uentry_unparseFull (newCurrent)));

      if (!uentry_isUndefined (oldCurrent))
	{
	  if (!uentry_isUndefined (newCurrent) 
	      && cstring_equal (uentry_rawName (newCurrent), uentry_rawName (oldCurrent)))
	    {
	      uentry_showWhereLast (oldCurrent);
	    }
	  else
	    {
	      uentry_showWhereLastPlain (old);
	    }
	  
	  uentry_setType (oldCurrent, newType);
	}
      else
	{
	  uentry_showWhereLastPlain (old);
	}
    }
}

static void
nargsError (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew)
{
  if (optgenerror 
      (FLG_TYPE,
       message ("Function %s %rdeclared with %d arg%&, %s with %d",
		unew->uname, 
		uentry_isDeclared (old),
		uentryList_size (uentry_getParams (unew)),
		uentry_specOrDefName (old),
		uentryList_size (uentry_getParams (old))),
       uentry_whereDeclared (unew)))
    {
      uentry_showWhereLastPlain (old);
    }
}

static void
returnValueError (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew)
{
  if (optgenerror
      (FLG_INCONDEFS,
       message ("Function %s inconsistently %rdeclared to return %t",
		unew->uname,
		uentry_isDeclared (old),
		ctype_getReturnType (unew->utype)),
       uentry_whereDeclared (unew)))
    {
      uentry_showWhereLastVal (old, ctype_unparse (ctype_getReturnType (old->utype)));
    }
}

static cstring paramStorageName (uentry ue)
{
  return (cstring_makeLiteralTemp (uentry_isParam (ue) ? "param" : "storage"));
}

static cstring fcnErrName (uentry ue)
{
  return (cstring_makeLiteralTemp (uentry_isFunction (ue) ? "to return" : "as"));
}

extern /*@observer@*/ cstring uentry_checkedName (uentry ue)
{
  if (uentry_isVar (ue))
    {
      return (checkedName (ue->info->var->checked));
    }
  else
    {
      return (cstring_makeLiteralTemp ("<checked invalid>"));
    }
}

static cstring checkedName (chkind checked)
{
  switch (checked)
    {
    case CH_UNKNOWN:       return (cstring_makeLiteralTemp ("unknown"));
    case CH_UNCHECKED:     return (cstring_makeLiteralTemp ("unchecked"));
    case CH_CHECKED:       return (cstring_makeLiteralTemp ("checked"));
    case CH_CHECKMOD:      return (cstring_makeLiteralTemp ("checkmod"));
    case CH_CHECKEDSTRICT: return (cstring_makeLiteralTemp ("checkedstrict"));
    }
  BADEXIT;
}

static
void checkNullState (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew, bool mustConform, bool completeConform)
{
  nstate oldState;
  nstate newState;
  
  if (uentry_isVar (unew))
    {
      llassert (uentry_isVar (old));
      
      oldState = old->info->var->nullstate;
      newState = unew->info->var->nullstate;
    }
  else
    {
      oldState = sRef_getNullState (old->sref);
      newState = sRef_getNullState (unew->sref);
    }

  if (oldState == NS_ABSNULL)
    {
      if (uentry_isVar (old))
	{
	  old->info->var->nullstate = newState;
	}
      
      sRef_mergeNullState (old->sref, newState);
    }
  else if (newState == NS_UNKNOWN)
    {
      if (completeConform && newState != oldState
	  && uentry_isReallySpecified (old))
	{
	  if (optgenerror 
	      (FLG_NEEDSPEC,
	       message ("%s %q specified as %s, but declared without %s qualifier",
			ekind_capName (unew->ukind),
			uentry_getName (unew),
			nstate_unparse (oldState),
			nstate_unparse (oldState)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}
      
      if (uentry_isVar (unew))
	{
	  unew->info->var->nullstate = oldState;
	}

      sRef_mergeNullState (unew->sref, oldState);
    }
  else if (newState == NS_POSNULL)
    {
      if (oldState == NS_MNOTNULL 
	  && (ctype_isUA (unew->utype) 
	      || (uentry_isFunction (unew)
		  && ctype_isUA (ctype_getReturnType (unew->utype)))))
	{
	  if (uentry_isVar (unew))
	    {
	      unew->info->var->nullstate = oldState;
	    }

	  sRef_mergeNullState (unew->sref, oldState);
	}
      else 
	{
	  if (oldState == NS_NOTNULL || oldState == NS_MNOTNULL 
	      || oldState == NS_UNKNOWN)
	    {
	      if (mustConform)
		{
		  if (optgenerror 
		      (FLG_INCONDEFS,
		       message 
		       ("%s %q inconsistently %rdeclared %s possibly null storage, "
			"%s %q qualifier",
			uentry_ekindName (unew),
			uentry_getName (unew),
			uentry_isDeclared (old),
			fcnErrName (unew),
			uentry_specOrDefName (old),
			cstring_makeLiteral (oldState == NS_MNOTNULL ? "with notnull" : "without null")),
		       uentry_whereDeclared (unew)))
		    {
		      uentry_showWhereSpecified (old);
		    }
		}
	    }
	  
	  if (uentry_isVar (old))
	    {
	      old->info->var->nullstate = newState;
	    }

	  sRef_mergeNullState (old->sref, newState);
	}
    }
  else if (newState == NS_MNOTNULL)
    {
      if (oldState != NS_MNOTNULL)
	{
	  if (mustConform)
	    {
	      if (optgenerror 
		  (FLG_INCONDEFS,
		   message ("%s %q inconsistently %rdeclared %s notnull storage, "
			    "%s without notnull qualifier",
			    uentry_ekindName (unew),
			    uentry_getName (unew),
			    uentry_isDeclared (old),
			    fcnErrName (unew),
			    uentry_specOrDefName (old)),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereSpecified (old);
		}
	    }
	  
	  if (uentry_isVar (old))
	    {
	      old->info->var->nullstate = newState;
	    }

	  sRef_mergeNullState (old->sref, newState);
	}
    }
  else
    {
      if (uentry_isVar (unew)) 
	{
	  unew->info->var->nullstate = oldState;
	}

      sRef_mergeNullState (unew->sref, oldState);
    }
}

static
void checkDefState (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew, 
		    bool mustConform, bool completeConform)
{
  sstate oldState;
  sstate newState;
  bool vars = FALSE;

  if (uentry_isVar (old) && uentry_isVar (unew))
    {
      oldState = old->info->var->defstate;
      newState = unew->info->var->defstate;
      vars = TRUE;
    }
  else
    {
      oldState = sRef_getDefState (old->sref);
      newState = sRef_getDefState (unew->sref);
    }

  if (newState != oldState 
      && newState != SS_UNKNOWN 
      && newState != SS_DEFINED)
    {
      if (mustConform)
	{
	  if (optgenerror 
	      (FLG_INCONDEFS,
	       message ("%s %q inconsistently %rdeclared %s %s %s, "
			"%s %s %s %s",
			uentry_ekindName (unew),
			uentry_getName (unew),
			uentry_isDeclared (old),
			fcnErrName (unew),
			sstate_unparse (newState),
			paramStorageName (unew),
			uentry_specOrDefName (old),
			fcnErrName (unew),
			sstate_unparse (oldState),
			paramStorageName (unew)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}

      if (vars) old->info->var->defstate = newState;
      sRef_setDefState (old->sref, newState, uentry_whereDeclared (unew));
    }
  else
    {
      if (completeConform
	  && (newState != oldState) && (oldState != SS_DEFINED)
	  && uentry_isReallySpecified (old))
	{
	  if (optgenerror 
	      (FLG_NEEDSPEC,
	       message ("%s %q specified as %s, but declared without %s qualifier",
			ekind_capName (unew->ukind),
			uentry_getName (unew),
			sstate_unparse (oldState),
			sstate_unparse (oldState)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}
      
      if (vars) unew->info->var->defstate = oldState;
      sRef_setDefState (unew->sref, oldState, uentry_whereDeclared (unew));
    }
}

static void 
  checkAliasState (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew, 
		   bool mustConform, bool completeConform)
{
  alkind newKind;
  alkind oldKind;

  oldKind = sRef_getAliasKind (old->sref);
  newKind = sRef_getAliasKind (unew->sref);

  if (alkind_isImplicit (newKind) 
      || (alkind_isRefCounted (newKind) && !uentry_isDatatype (unew)))
    {
      if (completeConform && !alkind_equal (newKind, oldKind)
	  && uentry_isReallySpecified (old))
	{
	  if (optgenerror 
	      (FLG_NEEDSPEC,
	       message ("%s %q specified as %s, but declared without "
			"explicit alias qualifier",
			ekind_capName (unew->ukind),
			uentry_getName (unew),
			alkind_unparse (oldKind)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}

      /*  
      ** This really shouldn't be necessary, but it is!
      ** Function params (?) use new here.
      */

      sRef_setAliasKind (unew->sref, oldKind, uentry_whereDeclared (unew));
      return;
    }

  if (alkind_isKnown (newKind))
    {
      if (!alkind_equal (oldKind, newKind))
	{
	  if (alkind_isKnown (oldKind))
	    {
	      if (mustConform && 
		  optgenerror 
		  (FLG_INCONDEFS,
		   message ("%s %q inconsistently %rdeclared %s %s storage, "
			    "%s as %s storage",
			    uentry_ekindName (unew),
			    uentry_getName (unew),
			    uentry_isDeclared (old),
			    fcnErrName (unew),
			    alkind_unparse (newKind),
			    uentry_specOrDefName (old),
			    alkind_unparse (oldKind)),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereSpecified (old);

		  DPRINTF (("Old: %s", sRef_unparseFull (old->sref)));
		  DPRINTF (("New: %s", sRef_unparseFull (unew->sref)));
		  sRef_setAliasKind (old->sref, AK_ERROR, 
				     uentry_whereDeclared (unew));
		}
	      else
		{
		  sRef_setAliasKind (old->sref, newKind, 
				     uentry_whereDeclared (unew));
		}
	    }
	  else
	    {
	      if (!(alkind_isImplicit (newKind)))
		{
		  if (mustConform &&
		      !uentry_isFunction (unew) &&
		      optgenerror 
		      (FLG_INCONDEFS,
		       message ("%s %q inconsistently %rdeclared %s %s storage, "
				"implicitly %s as temp storage",
				uentry_ekindName (unew),
				uentry_getName (unew),
				uentry_isDeclared (old),
				fcnErrName (unew),
				alkind_unparse (newKind),
				uentry_specOrDefName (old)),
		       uentry_whereDeclared (unew)))
		    {
		      uentry_showWhereSpecified (old);
		      oldKind = AK_ERROR;
		    }
		  
		  sRef_setAliasKind (old->sref, newKind, 
				     uentry_whereDeclared (unew));
		}
	      else /* newKind is temp or refcounted */
		{
		  ;
		}
	    }
	}
    }
  else /* newKind unknown */
    {
      ;
    }
}

static void 
  checkExpState(/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew, 
		bool mustConform, bool completeConform)
{
  exkind newKind;
  exkind oldKind;
  
  oldKind = sRef_getExKind (old->sref);
  newKind = sRef_getExKind (unew->sref);

  if (exkind_isKnown (newKind))
    {
      if (oldKind != newKind)
	{
	  if (exkind_isKnown (oldKind))
	    {
	      if (mustConform && 
		  optgenerror 
		  (FLG_INCONDEFS,
		   message ("%s %q inconsistently %rdeclared %s %s, %s as %s",
			    uentry_ekindName (unew),
			    uentry_getName (unew),
			    uentry_isDeclared (old),
			    fcnErrName (unew),
			    exkind_unparse (newKind),
			    uentry_specOrDefName (old),
			    exkind_unparse (oldKind)),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereSpecified (old);
		}

	      sRef_setExKind (old->sref, newKind, uentry_whereDefined (unew));
	    }
	  else
	    {
	      if (mustConform &&
		  optgenerror 
		  (FLG_INCONDEFS,
		   message ("%s %q inconsistently %rdeclared %s %s, "
			    "implicitly %s without exposure qualifier",
			    uentry_ekindName (unew),
			    uentry_getName (unew),
			    uentry_isDeclared (old),
			    fcnErrName (unew),
			    exkind_unparse (newKind),
			    uentry_specOrDefName (old)),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereSpecified (old);
		}

	      sRef_setExKind (old->sref, newKind, uentry_whereDefined (unew));
	    }
	}
    }
  else
    {
      if (completeConform && exkind_isKnown (oldKind)
	  && uentry_isReallySpecified (old))
	{
	  if (optgenerror 
	      (FLG_NEEDSPEC,
	       message ("%s %q specified as %s, but declared without "
			"exposure qualifier",
			ekind_capName (unew->ukind),
			uentry_getName (unew),
			exkind_unparse (oldKind)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}

      /* yes, this is necessary! (if its a param) */
      sRef_setExKind (unew->sref, oldKind, fileloc_undefined);
    }
}

static void 
checkMetaState (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew, 
		bool mustConform, /*@unused@*/ bool completeConform)
{
  valueTable newvals = sRef_getValueTable (unew->sref);

  if (valueTable_isDefined (newvals))
    {
      DPRINTF (("Check meta state: %s -> %s",
		uentry_unparseFull (old),
		uentry_unparseFull (unew)));
      
      DPRINTF (("Check meta state refs: %s -> %s",
		sRef_unparseFull (old->sref),
		sRef_unparseFull (unew->sref)));
      
      DPRINTF (("Value table: %s", valueTable_unparse (newvals)));
      
      /*
      ** Copy the new values into the old ref
      */

      valueTable_elements (newvals, key, newval)
	{
	  metaStateInfo msinfo = context_lookupMetaStateInfo (key);
	  stateValue oldval = sRef_getMetaStateValue (old->sref, key);
            
	  llassert (metaStateInfo_isDefined (msinfo));

	  if (stateValue_isUndefined (oldval))
	    {
	      sRef_setMetaStateValue (old->sref, key, stateValue_getValue (newval), uentry_whereLast (unew));
	    }
	  else
	    {
	      if (stateValue_isError (oldval))
		{
		  if (!stateValue_isError (newval))
		    {
		      sRef_setMetaStateValue (old->sref, key, stateValue_getValue (newval), uentry_whereLast (unew));
		    }
		  else
		    {
		      ; /* No change necessary. */
		    }
		}
	      else
		{
		  if (stateValue_getValue (newval) != stateValue_getValue (oldval))
		    {
		      if (fileloc_isXHFile (uentry_whereDeclared (unew)))
			{
			  ;
			}
		      else
			{
			  if (!stateValue_isError (newval) 
			      && !stateValue_isImplicit (newval))
			    {
			      if (uentry_hasName (unew)
				  || !sRef_isParam (uentry_getSref (unew)))
				{
				  if (mustConform 
				      && optgenerror 
				      (FLG_INCONDEFS,
				       message ("%s %q inconsistently %rdeclared %s %q, %s as %q",
						uentry_ekindName (unew),
						uentry_getName (unew),
						uentry_isDeclared (old),
						fcnErrName (unew),
						stateValue_unparseValue (newval, msinfo),
						uentry_specOrDefName (old),
						stateValue_unparseValue (oldval, msinfo)),
				       uentry_whereDeclared (unew)))
				    {
				      uentry_showWhereSpecified (old);
				    }
				}
			      else
				{
				  if (mustConform 
				      && optgenerror 
				      (FLG_INCONDEFS,
				       message ("%s %d inconsistently %rdeclared %s %q, %s as %q",
						uentry_ekindName (unew),
						sRef_getParam (uentry_getSref (unew)),
						uentry_isDeclared (old),
						fcnErrName (unew),
						stateValue_unparseValue (newval, msinfo),
						uentry_specOrDefName (old),
						stateValue_unparseValue (oldval, msinfo)),
				       uentry_whereDeclared (unew)))
				    {
				      uentry_showWhereSpecified (old);
				    }
				}
			    }
			}
		      
		      DPRINTF (("Updating!"));
		      sRef_setMetaStateValue (old->sref, key, stateValue_getValue (newval), uentry_whereLast (unew));
		    }
		  else
		    {
		      DPRINTF (("Values match"));
		    }
		}
	    }
	} end_valueTable_elements ;
    }
}

static void
uentry_checkStateConformance (/*@notnull@*/ uentry old,
			      /*@notnull@*/ uentry unew,
			      bool mustConform, bool completeConform)
{
  checkDefState (old, unew, mustConform, completeConform);
  checkNullState (old, unew, mustConform, completeConform);
  checkAliasState (old, unew, mustConform, completeConform);
  checkExpState (old, unew, mustConform, completeConform);
  checkMetaState (old, unew, mustConform, completeConform);

  sRef_storeState (old->sref);
  sRef_storeState (unew->sref);
}

static void
checkVarConformance (uentry old, uentry unew, bool mustConform, bool completeConform)
{
  if (uentry_isElipsisMarker (old) || uentry_isElipsisMarker (unew))
    {
      return;
    }

  llassert (uentry_isVar (old));
  llassert (uentry_isVar (unew));

  if (cstring_isEmpty (old->uname)) 
    {
      cstring_free (old->uname);
      old->uname = cstring_copy (unew->uname);
    }

  if (unew->info->var->kind == VKRETPARAM
      || unew->info->var->kind == VKSEFRETPARAM)
    {
      if (old->info->var->kind != VKRETPARAM
	  && old->info->var->kind != VKSEFRETPARAM)
	{
	  if (optgenerror 
	      (FLG_INCONDEFS,
	       message ("Parameter %q inconsistently %rdeclared as "
			"returned parameter",
			uentry_getName (unew),
			uentry_isDeclared (old)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	      old->info->var->kind = unew->info->var->kind;
	    }
	}
    }


  if (unew->info->var->kind == VKSEFPARAM || unew->info->var->kind == VKSEFRETPARAM)
    {
      if (old->info->var->kind != VKSEFPARAM 
	  && old->info->var->kind != VKSEFRETPARAM)
	{
	  if (optgenerror 
	      (FLG_INCONDEFS,
	       message ("Parameter %qinconsistently %rdeclared as "
			"sef parameter",
			uentry_getOptName (unew),
			uentry_isDeclared (old)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	      old->info->var->kind = unew->info->var->kind;
	    }
	}
    }

  if (old->info->var->kind == VKSPEC)
    {
      old->info->var->kind = unew->info->var->kind;
    }
  else
    {
      unew->info->var->kind = old->info->var->kind;
    }

  if (unew->info->var->checked != CH_UNKNOWN
      && unew->info->var->checked != old->info->var->checked)
    {
      if (old->info->var->checked == CH_UNKNOWN
	  && !fileloc_isUser (uentry_whereLast (old)))
	{
	  ; /* no error */
	}
      else
	{
	  if (optgenerror 
	      (FLG_INCONDEFS,
	       message ("Variable %q inconsistently %rdeclared as "
			"%s parameter (was %s)",
			uentry_getName (unew),
			uentry_isDeclared (old),
			checkedName (unew->info->var->checked),
			checkedName (old->info->var->checked)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}
      
      old->info->var->checked = unew->info->var->checked;
    }
  else
    {
      if (completeConform 
	  && (old->info->var->checked != CH_UNKNOWN)
	  && uentry_isReallySpecified (old))
	{
	  if (optgenerror 
	      (FLG_NEEDSPEC,
	       message ("%s %q specified as %s, but declared without %s qualifier",
			ekind_capName (unew->ukind),
			uentry_getName (unew),
			checkedName (old->info->var->checked),
			checkedName (old->info->var->checked)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}
      
      unew->info->var->checked = old->info->var->checked;
    }

  uentry_checkStateConformance (old, unew, mustConform, completeConform);
}

void uentry_checkMatchParam (uentry u1, uentry u2, int paramno, exprNode e)
{
  if (uentry_isElipsisMarker (u1) || uentry_isElipsisMarker (u2))
    {
      return;
    }

  llassert (uentry_isVar (u1));
  llassert (uentry_isVar (u2));

  if (u1->info->var->kind != u2->info->var->kind) {
    if (u1->info->var->kind == VKSEFRETPARAM) {
      if (u2->info->var->kind == VKRETPARAM) {
	voptgenerror 
	  (FLG_TYPE,
	   message ("Function types are inconsistent. Parameter %d is "
		    "sef parameter, but non-sef parameter in "
		    "assigned function: %s",
		    paramno, exprNode_unparse (e)),
	   exprNode_loc (e));
      } else if (u2->info->var->kind == VKSEFPARAM) {
	voptgenerror 
	  (FLG_TYPE,
	   message ("Function types are inconsistent. Parameter %d is "
		    "returns parameter, but non-returns parameter in "
		    "assigned function: %s",
		    paramno, exprNode_unparse (e)),
	   exprNode_loc (e));
      } else {
	voptgenerror 
	  (FLG_TYPE,
	   message ("Function types are inconsistent. Parameter %d is "
		    "sef returns parameter, but non-sef returns parameter in "
		    "assigned function: %s",
		    paramno, exprNode_unparse (e)),
	   exprNode_loc (e));
      }
    } else if (u1->info->var->kind == VKRETPARAM) {
      voptgenerror 
	(FLG_TYPE,
	 message ("Function types are inconsistent. Parameter %d is "
		  "returns parameter, but non-returns parameter in "
		  "assigned function: %s",
		  paramno, exprNode_unparse (e)),
	 exprNode_loc (e));
    } else if (u1->info->var->kind == VKSEFPARAM) {
      voptgenerror 
	(FLG_TYPE,
	 message ("Function types are inconsistent. Parameter %d is "
		  "sef parameter, but non-sef parameter in "
		  "assigned function: %s",
		  paramno, exprNode_unparse (e)),
	 exprNode_loc (e));
    } else {
      if (u2->info->var->kind == VKSEFRETPARAM) {
	voptgenerror 
	  (FLG_TYPE,
	   message ("Function types are inconsistent. Parameter %d is "
		    "normal parameter, but sef returns parameter in "
		    "assigned function: %s",
		    paramno, exprNode_unparse (e)),
	   exprNode_loc (e));
      } else if (u2->info->var->kind == VKSEFPARAM) {
	voptgenerror 
	  (FLG_TYPE,
	   message ("Function types are inconsistent. Parameter %d is "
		    "normal parameter, but sef parameter in "
		    "assigned function: %s",
		    paramno, exprNode_unparse (e)),
	   exprNode_loc (e));
      } else if (u2->info->var->kind == VKRETPARAM) {
	voptgenerror 
	  (FLG_TYPE,
	   message ("Function types are inconsistent. Parameter %d is "
		    "normal parameter, but returns parameter in "
		    "assigned function: %s",
		    paramno, exprNode_unparse (e)),
	   exprNode_loc (e));
      } else {
	BADBRANCH;
      }
    }
  }

  if (u1->info->var->defstate != u2->info->var->defstate) 
    {
      voptgenerror 
	(FLG_TYPE,
	 message ("Function types are inconsistent. Parameter %d is "
		  "%s, but %s in assigned function: %s",
		  paramno, 
		  sstate_unparse (u1->info->var->defstate),
		  sstate_unparse (u2->info->var->defstate),
		  exprNode_unparse (e)),
	 exprNode_loc (e));
    }

  if (u1->info->var->nullstate != u2->info->var->nullstate) 
    {
      voptgenerror 
	(FLG_TYPE,
	 message ("Function types are inconsistent. Parameter %d is "
		  "%s, but %s in assigned function: %s",
		  paramno, 
		  nstate_unparse (u1->info->var->nullstate),
		  nstate_unparse (u2->info->var->nullstate),
		  exprNode_unparse (e)),
	 exprNode_loc (e));
    }
      
  if (sRef_getAliasKind (u1->sref) != sRef_getAliasKind (u2->sref))
    {
      voptgenerror 
	(FLG_TYPE,
	 message ("Function types are inconsistent. Parameter %d is "
		  "%s, but %s in assigned function: %s",
		  paramno, 
		  alkind_unparse (sRef_getAliasKind (u1->sref)),
		  alkind_unparse (sRef_getAliasKind (u2->sref)),
		  exprNode_unparse (e)),
	 exprNode_loc (e));
    }

  if (sRef_getExKind (u1->sref) != sRef_getExKind (u2->sref))
    {
      voptgenerror 
	(FLG_TYPE,
	 message ("Function types are inconsistent. Parameter %d is "
		  "%s, but %s in assigned function: %s",
		  paramno, 
		  exkind_unparse (sRef_getExKind (u1->sref)),
		  exkind_unparse (sRef_getExKind (u2->sref)),
		  exprNode_unparse (e)),
	 exprNode_loc (e));
    }
}

static void
checkFunctionConformance (/*@unique@*/ /*@notnull@*/ uentry old,
			  /*@notnull@*/ uentry unew, 
			  bool mustConform, /*@unused@*/ bool completeConform)
{
  uentryList oldParams  = uentry_getParams (old);
  uentryList newParams  = uentry_getParams (unew);
  ctype      newType    = unew->utype;
  ctype      oldType    = ctype_realType (old->utype);
  ctype      oldRetType = ctype_unknown;
  ctype      newRetType = ctype_unknown;

  DPRINTF (("Function conform: %s ==> %s",
	    uentry_unparseFull (old),
	    uentry_unparseFull (unew)));

  if (uentry_isForward (old))
    {
      mustConform = FALSE;
      uentry_updateInto (old, unew);
      return;
    }

  /*
  ** check return values
  */
  
  if (ctype_isKnown (oldType))
    {
      llassert (ctype_isFunction (oldType));
      oldRetType = ctype_getReturnType (oldType);
    }

  if (ctype_isKnown (newType))
    {
      llassert (ctype_isFunction (newType));
      newRetType = ctype_getReturnType (newType);
    }

  if (ctype_isKnown (oldRetType) && ctype_isKnown (newRetType)
      && !ctype_matchDef (newRetType, oldRetType))
    {
      if (mustConform) returnValueError (old, unew);
    }
  else 
    {
      if (ctype_isConj (newRetType))
	{
	  if (ctype_isConj (oldRetType))
	    {
	      if (!ctype_sameAltTypes (newRetType, oldRetType))
		{
		  if (optgenerror 
		      (FLG_INCONDEFS,
		       message ("Function %q inconsistently %rdeclared to "
				"return alternate types %s "
				"(types match, but alternates are not identical, "
				"so checking may not be correct)",
				uentry_getName (unew),
				uentry_isDeclared (old),
				ctype_unparse (newRetType)),
		       uentry_whereDeclared (unew)))
		    {
		      uentry_showWhereLastVal (old, ctype_unparse (oldRetType));
		    }
		}
	    }
	  else
	    {
	      old->utype = ctype_makeFunction (oldRetType, uentryList_copy (newParams));
	    }
	}
    }

  DPRINTF (("Before state: %s",
	    uentry_unparseFull (old)));
  uentry_checkStateConformance (old, unew, mustConform, completeConform);
  DPRINTF (("After state: %s",
	    uentry_unparseFull (old)));

  if (!exitkind_equal (unew->info->fcn->exitCode, old->info->fcn->exitCode))
    {
      if (exitkind_isKnown (unew->info->fcn->exitCode))
	{
	  if (optgenerror 
	      (FLG_INCONDEFS,
	       message ("Function %q inconsistently %rdeclared using %s",
			uentry_getName (unew),
			uentry_isDeclared (old),
			exitkind_unparse (unew->info->fcn->exitCode)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}
      else
	{
	  unew->info->fcn->exitCode = old->info->fcn->exitCode;
	}
    }

  if (!qual_isUnknown (unew->info->fcn->nullPred))
    {
      if (!qual_match (old->info->fcn->nullPred, unew->info->fcn->nullPred))
	{
	  if (optgenerror
	      (FLG_INCONDEFS,
	       message ("Function %q inconsistently %rdeclared using %s",
			uentry_getName (unew),
			uentry_isDeclared (old),
			qual_unparse (unew->info->fcn->nullPred)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}
    }
  else
    {
      unew->info->fcn->nullPred = old->info->fcn->nullPred;
    }

  if (unew->info->fcn->specialCode != SPC_NONE)
    {
      if (old->info->fcn->specialCode != unew->info->fcn->specialCode)
	{
	  if (optgenerror
	      (FLG_INCONDEFS,
	       message ("Function %q inconsistently %rdeclared using %s",
			uentry_getName (unew),
			uentry_isDeclared (old),
			specCode_unparse (unew->info->fcn->specialCode)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereSpecified (old);
	    }
	}
    }
  else
    {
      unew->info->fcn->specialCode = old->info->fcn->specialCode;
    }
	  
  /*
  ** check parameters
  */
  
  if (!uentryList_sameObject (oldParams, newParams)
      && (!uentryList_isMissingParams (oldParams)))
    {
      if (!uentryList_isMissingParams (newParams))
	{
	  int paramno = 0;
	  int nparams = uentryList_size (oldParams);
	  bool checknames = context_maybeSet (FLG_DECLPARAMMATCH);

	  if (nparams != uentryList_size (newParams))
	    {
	      nargsError (old, unew);
	    }
	  
	  if (uentryList_size (newParams) < nparams) 
	    {
	      nparams = uentryList_size (newParams);
	    }

	  while (paramno < nparams)
	    {
	      uentry oldCurrent = uentryList_getN (oldParams, paramno);
	      uentry newCurrent  = uentryList_getN (newParams, paramno);
	      ctype  oldCurrentType = uentry_getType (oldCurrent);
	      ctype  newCurrentType = uentry_getType (newCurrent);

	      llassert (uentry_isValid (oldCurrent)
			&& uentry_isValid (newCurrent));
	      
	      if (!uentry_isElipsisMarker (oldCurrent)
		  && !uentry_isElipsisMarker (newCurrent))
		{
		  checkVarConformance (oldCurrent, newCurrent, 
				       mustConform, completeConform);
		}

	      if (checknames)
		{
		  if (uentry_hasName (oldCurrent) 
		      && uentry_hasName (newCurrent))
		    {
		      cstring oldname = uentry_getName (oldCurrent);
		      cstring pfx = context_getString (FLG_DECLPARAMPREFIX);
		      cstring oname;
		      cstring nname = uentry_getName (newCurrent);
		      cstring nnamefix;

		      if (cstring_isDefined (pfx)
			  && cstring_equalPrefix (oldname, pfx))
			{
			  oname = cstring_suffix (oldname, cstring_length (pfx));
			}
		      else
			{
			  oname = oldname;
			/*@-branchstate@*/ } /*@=branchstate@*/

		      if (cstring_isDefined (pfx)
			  && cstring_equalPrefix (nname, pfx))
			{
			  nnamefix = cstring_suffix (nname, cstring_length (pfx));
			}
		      else
			{
			  nnamefix = nname;
			/*@-branchstate@*/ } /*@=branchstate@*/

		      if (!cstring_equal (oname, nnamefix))
			{
			  if (optgenerror
			      (FLG_DECLPARAMMATCH, 
			       message ("Definition parameter name %s does not match "
					"name of corresponding parameter in "
					"declaration: %s",
					nnamefix, oname),
			       uentry_whereLast (newCurrent)))
			    {
			      uentry_showWhereLastPlain (oldCurrent);
			    }
			}
		      
		      cstring_free (oldname);
		      cstring_free (nname);
		    }
		}

	      if (!ctype_match (oldCurrentType, newCurrentType))
		{
		  paramTypeError (old, oldCurrent, oldCurrentType,
				  unew, newCurrent, newCurrentType, paramno);
		}
	      else
		{
		  if (ctype_isMissingParamsMarker (newCurrentType)
		      || ctype_isElips (newCurrentType)
		      || ctype_isMissingParamsMarker (oldCurrentType)
		      || ctype_isElips (oldCurrentType))
		    {
		      ;
		    }
		  else
		    {
		      if (ctype_isConj (newCurrentType))
			{
			  if (ctype_isConj (oldCurrentType))
			    {
			      if (!ctype_sameAltTypes (newCurrentType, oldCurrentType))
				{
				  if (optgenerror 
				      (FLG_INCONDEFS,
				       message ("Parameter %q inconsistently %rdeclared with "
						"alternate types %s "
						"(types match, but alternates are not identical, "
						"so checking may not be correct)",
						uentry_getName (newCurrent),
						uentry_isDeclared (oldCurrent),
						ctype_unparse (newCurrentType)),
				       uentry_whereDeclared (unew)))
				    {
				      uentry_showWhereLastVal (oldCurrent,
							       ctype_unparse (oldCurrentType));
				    }
				}
			    }
			  else
			    {
			      if (optgenerror 
				  (FLG_INCONDEFS,
				   message ("Parameter %q inconsistently %rdeclared with "
					    "alternate types %s",
					    uentry_getName (newCurrent),
					    uentry_isDeclared (oldCurrent),
					    ctype_unparse (newCurrentType)),
				   uentry_whereDeclared (unew)))
				{
				  uentry_showWhereLastVal (oldCurrent,
							   ctype_unparse (oldCurrentType));
				  
				}
			    }
			}
		      else 
			{
			  if (ctype_isConj (oldCurrentType))
			    {
			      uentry_setType (newCurrent, oldCurrentType);
			    }
			}
		    }
		}

	      paramno++;  
	      /*
	       ** Forgot this!  detected by splint:
	       ** uentry.c:1257,15: Suspected infinite loop
	       */
	    }
	}
    }

  if (!uentryList_isMissingParams (newParams))
    {
      if (ctype_isConj (oldRetType))
	{
	  old->utype = ctype_makeFunction (oldRetType, 
					   uentryList_copy (newParams));
	}
      else
	{
	  old->utype = unew->utype;
	}
    }

  checkGlobalsConformance (old, unew, mustConform, completeConform);
  checkModifiesConformance (old, unew, mustConform, completeConform);

  DPRINTF (("Before list: %s",
	    uentry_unparseFull (old)));

  if (stateClauseList_isDefined (unew->info->fcn->specclauses))
    {
      if (!stateClauseList_isDefined (old->info->fcn->specclauses))
	{
	  /*
	  if (optgenerror
	      (FLG_INCONDEFS,
	       message ("Function %q redeclared using special clauses (can only "
			"be used in first declaration)",
			uentry_getName (unew)),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereLast (old);
	    }
	  */

	  /*@i23 need checking @*/ 

	  old->info->fcn->specclauses = unew->info->fcn->specclauses;
	}
      else
	{
	  /*@i43 should be able to append? @*/

	  stateClauseList_checkEqual (old, unew);
	  stateClauseList_free (unew->info->fcn->specclauses);
	  unew->info->fcn->specclauses = stateClauseList_undefined;
	  /*@-branchstate@*/ 
	}
    }
  /*@=branchstate@*/ /*@i23 shouldn't need this@*/

  if (fileloc_isUndefined (old->whereDeclared))
    {
      old->whereDeclared = fileloc_copy (unew->whereDeclared);
    }
  else if (fileloc_isUndefined (unew->whereDeclared))
    {
      unew->whereDeclared = fileloc_copy (old->whereDeclared);
    }
  else
    {
      /* no change */
    }
/*@i523 @*/ }

void
uentry_mergeConstantValue (uentry ue, /*@only@*/ multiVal m)
{
  multiVal uval;

  llassert (uentry_isValid (ue));
  llassert (uentry_isEitherConstant (ue));

  DPRINTF (("Constant value: %s / %s", uentry_unparse (ue), multiVal_unparse (m)));
  uval = uentry_getConstantValue (ue);

  if (multiVal_isDefined (uval))
    {
      if (multiVal_isDefined (m))
	{
	  if (!multiVal_equiv (uval, m))
	    {
	      if (optgenerror 
		  (FLG_INCONDEFS,
		   message ("%s %q defined with inconsistent value: %q",
			    ekind_capName (ue->ukind),
			    uentry_getName (ue), 
			    multiVal_unparse (m)),
		   g_currentloc))
		{
		  uentry_showWhereLastExtra (ue, multiVal_unparse (uval));
		}
	    }
	}
      multiVal_free (m);
    }
  else
    {
      uentry_setConstantValue (ue, m);
    }
}

static
bool checkTypeConformance (/*@notnull@*/ uentry old, /*@notnull@*/ uentry unew, 
			   bool mustConform)
{
  bool typeError = FALSE;

  if (uentry_isStructTag (old) || uentry_isUnionTag (old))
    {
      if (ctype_isSU (old->utype) && ctype_isSU (unew->utype))
	{
	  if (mustConform)
	    {
	      DPRINTF (("Check struct conformance: %s / %s",
			uentry_unparseFull (old),
			uentry_unparseFull (unew)));
	      checkStructConformance (old, unew); 
	    }
	}
      else
	{
	  if (!(ctype_isBogus (old->utype) || ctype_isBogus (unew->utype)))
	    {
	      llbug (message ("struct tags: bad types: %t / %t", 
			      old->utype, unew->utype));
	    }
	}
    }
  else if (uentry_isEnumTag (old))
    {
      if (ctype_isEnum (old->utype) && ctype_isEnum (unew->utype))
	{
	  if (mustConform) checkEnumConformance (old, unew);
	}
      else 
	{
	  if (!(ctype_isBogus (old->utype) || ctype_isBogus (unew->utype)))
	    {
	      llbug (message ("enum! bad type: %s / %s", ctype_unparse (old->utype),
			      ctype_unparse (unew->utype)));
	    }
	}
    }
  else if (!ctype_match (old->utype, unew->utype))
    {
      DPRINTF (("Type mismatch: %s / %s",
		ctype_unparse (old->utype),
		ctype_unparse (unew->utype)));

      if (cstring_equal (uentry_rawName (old), context_getBoolName ()))
	{
	  ctype realt = ctype_realType (unew->utype);
	  
	  if (ctype_isRealInt (realt) || ctype_isChar (realt))
	    {
	      unew->utype = ctype_bool;
	    }
	  else
	    {
	      if (mustConform)
		{
		  typeError = optgenerror
		    (FLG_INCONDEFS,
		     message ("%q defined as %s", uentry_getName (old), 
			      ctype_unparse (realt)),
		     uentry_whereDeclared (unew));
		}
	    }
	} 
      else 
	{
	  if (mustConform)
	    {
	      ctype oldr = ctype_realType (old->utype);
	      ctype newr = ctype_realType (unew->utype);
	      
	      if (ctype_isStruct (oldr) && ctype_isStruct (newr))
		{
		  checkStructConformance (old, unew);
		}
	      else if (ctype_isUnion (oldr) && ctype_isUnion (newr))
		{
		  checkStructConformance (old, unew);
		}
	      else if (ctype_isEnum (oldr) && ctype_isEnum (newr))
		{
		  checkEnumConformance (old, unew);
		}
	      else if (uentry_isConstant (old) 
		       && (ctype_isAbstract (oldr) && ctype_isEnum (newr)))
		{
		  /* okay...for now! (should check the type is reset later... */
		}
	      else
		{
		  DPRINTF (("YABA!"));
		  if (optgenerror 
		      (FLG_INCONDEFS,
		       message ("%s %q %rdeclared with inconsistent type: %t",
				ekind_capName (unew->ukind),
				uentry_getName (unew), 
				uentry_isDeclared (old),
				unew->utype),
		       uentry_whereDeclared (unew)))
		    {
		      uentry_showWhereLast (old);
		      typeError = TRUE;
		    }
		}
	    }
	}
    }
  else
    {
      /* no error */
    }

  return typeError;
}

static void
uentry_checkDatatypeConformance (/*@notnull@*/ uentry old,
				 /*@notnull@*/ uentry unew,
				 bool mustConform, bool completeConform)
{
  if (ctype_isDefined (unew->info->datatype->type))
    {
      /*
      ** bool is hard coded here, since it is built into LCL.
      ** For now, we're stuck with LCL's types.
      */

      if (ctype_isDirectBool (old->utype) &&
	  cstring_equalLit (unew->uname, "bool"))
	{
	  /* if (!context_getFlag (FLG_ABSTRACTBOOL))
	     evs 2000-07-25: removed
	  */
	      unew->utype = ctype_bool;
	}
      
      if (ctype_isUnknown (old->info->datatype->type))
	{
	  old->info->datatype->type = unew->info->datatype->type;
	}
      else
	{
	  DPRINTF (("Old: %s / New: %s",
		    uentry_unparseFull (old),
		    uentry_unparseFull (unew)));
	  DPRINTF (("Types: %s / %s",
		    ctype_unparse (old->info->datatype->type),
		    ctype_unparse (unew->info->datatype->type)));

	  if (ctype_matchDef (old->info->datatype->type,
			      unew->info->datatype->type))
	    {
	      ;
	    }
	  else
	    {
	      if (optgenerror 
		  (FLG_INCONDEFS,
		   message
		   ("Type %q %s with inconsistent type: %t",
		    uentry_getName (unew), 
		    uentry_reDefDecl (old, unew),
		    unew->info->datatype->type),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereLastExtra 
		    (old, cstring_copy (ctype_unparse (old->info->datatype->type)));
		}

	      old->info->datatype->type = unew->info->datatype->type;
	    }
	}
    }
  
  if (unew->info->datatype->abs != MAYBE)
    {
      if (ynm_isOff (old->info->datatype->abs)
	  && ynm_isOn (unew->info->datatype->abs))
	{
	  if (!ctype_isDirectBool (old->utype))
	    {
	      if (optgenerror 
		  (FLG_INCONDEFS,
		   message 
		   ("Datatype %q inconsistently %rdeclared as abstract type",
		    uentry_getName (unew), 
		    uentry_isDeclared (old)),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereLastPlain (old);
		}
	    }
	}
      else if (ynm_isOn (old->info->datatype->abs)
	       && ynm_isOff (unew->info->datatype->abs))
	{
	  if (!ctype_isDirectBool (old->utype))
	    {
	      if (optgenerror 
		  (FLG_INCONDEFS,
		   message 
		   ("Datatype %q inconsistently %rdeclared as concrete type",
		    uentry_getName (unew), 
		    uentry_isDeclared (old)),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereLastPlain (old);
		}
	    }
	}
      else
	{
	  ;
	}
    }
  else 
    {
      if (ynm_isOn (old->info->datatype->abs))
	{
	  old->sref = unew->sref;
	  unew->info->datatype->mut = old->info->datatype->mut;
	  
	  if (completeConform
	      && uentry_isReallySpecified (old))
	    {
	      if (optgenerror 
		  (FLG_NEEDSPEC,
		   message 
		   ("Datatype %q specified as abstract, "
		    "but abstract annotation not used in declaration",
		    uentry_getName (unew)), 
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereLastPlain (old);
		}
	    }
	}
    }
  
  unew->info->datatype->abs = old->info->datatype->abs;	  
  
  if (ynm_isMaybe (unew->info->datatype->mut))
    {
      if (completeConform && ynm_isOff (old->info->datatype->mut)
	  && uentry_isReallySpecified (old))
	{
	  if (optgenerror 
	      (FLG_NEEDSPEC,
	       message 
	       ("Datatype %q specified as immutable, "
		"but immutable annotation not used in declaration",
		uentry_getName (unew)), 
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereLastPlain (old);
	    }
	}
      
      unew->info->datatype->mut = old->info->datatype->mut;
    }
  else if (ynm_isMaybe (old->info->datatype->mut))
    {
      old->info->datatype->mut = unew->info->datatype->mut;
    }
  else
    {
      if (ynm_isOn (old->info->datatype->abs))
	{
	  if (ynm_isOn (old->info->datatype->mut) && ynm_isOff (unew->info->datatype->mut))
	    {
	      if (optgenerror
		  (FLG_INCONDEFS,
		   message ("Datatype %q inconsistently %rdeclared as immutable",
			    uentry_getName (unew), 
			    uentry_isDeclared (old)),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereLastPlain (old);
		}
	    }
	  else 
	    {
	      if (ynm_isOff (old->info->datatype->mut)
		  && ynm_isOn (unew->info->datatype->mut))
		{
		  if (optgenerror
		      (FLG_INCONDEFS,
		       message ("Datatype %q inconsistently %rdeclared as mutable",
				uentry_getName (unew), 
				uentry_isDeclared (old)),
		       uentry_whereDeclared (unew)))
		    {
		      uentry_showWhereLastPlain (old);
		    }
		}
	    }
	}
      old->info->datatype->mut = unew->info->datatype->mut;	  
    }

  uentry_checkStateConformance (old, unew, mustConform, completeConform);
}

static void
uentry_checkConstantConformance (/*@notnull@*/ uentry old,
				 /*@notnull@*/ uentry unew,
				 bool mustConform, 
				 /*@unused@*/ bool completeConform)
{
  multiVal oldval = uentry_getConstantValue (old);
  multiVal newval = uentry_getConstantValue (unew);
  
  if (multiVal_isDefined (oldval))
    {
      if (multiVal_isDefined (newval))
	{
	  if (!multiVal_equiv (oldval, newval))
	    {
	      if (mustConform
		  && optgenerror 
		  (FLG_INCONDEFS,
		   message ("%s %q %rdeclared with inconsistent value: %q",
			    ekind_capName (unew->ukind),
			    uentry_getName (unew), 
			    uentry_isDeclared (old),
			    multiVal_unparse (newval)),
		   uentry_whereDeclared (unew)))
		{
		  uentry_showWhereLastExtra (old, multiVal_unparse (oldval));
		}
	    }
	  
	  uentry_setConstantValue (unew, multiVal_copy (oldval));
	}
      else
	{
	  ;
	}
    }
  else
    {
      uentry_setConstantValue (old, multiVal_copy (newval));
    }
}

static void 
uentry_checkConformance (/*@unique@*/ /*@notnull@*/ uentry old, 
			 /*@notnull@*/ uentry unew, bool mustConform,
			 bool completeConform)
{
  bool typeError = FALSE;
  bool fcnConformance = FALSE;

  if (!ekind_equal (unew->ukind, old->ukind))
    {
      /*
      ** okay, only if one is a function and the other is
      ** a variable of type function.
      */

      if (unew->ukind == KENUMCONST
	  && old->ukind == KCONST)
	{
	  old->ukind = KENUMCONST;
	  goto nokinderror;
	}

      if (unew->ukind == KFCN 
	  && old->ukind == KCONST
	  && ctype_isUnknown (old->utype))
	{
	  /*
	  ** When a function is defined with an unparam macro
	  */

	  uentry_updateInto (old, unew);
	  return;
	}

      if (uentry_isExpandedMacro (old) 
	  && uentry_isEitherConstant (unew))
	{
	  uentry_updateInto (old, unew);
	  return;
	}

      if (uentry_isEndIter (unew))
	{
	  if (ctype_isUnknown (old->utype))
	    {
	      if (!uentry_isSpecified (old)
		  && uentry_isCodeDefined (unew))
		{
		  if (!fileloc_withinLines (uentry_whereDefined (old),
					    uentry_whereDeclared (unew), 2))
		    { /* bogus!  will give errors if there is too much whitespace */
		      voptgenerror
			(FLG_SYNTAX,
			 message
			 ("Iterator finalized name %q does not match name in "
			  "previous iter declaration (should be end_%q).  This iter "
			  "is declared at %q", 
			  uentry_getName (unew),
			  uentry_getName (old),
			  fileloc_unparse (uentry_whereDefined (old))),
			 uentry_whereDeclared (old));
		    }
		}

	      uentry_updateInto (old, unew);
	      return;
	    }
	  else
	    {
	      KindConformanceError (old, unew, mustConform);
	    }
	}

      if (uentry_isFunction (unew))
	{
	  if (uentry_isVariable (old))
	    {
	      if (!ctype_isUnknown (old->utype))
		{
		  if (ctype_isFunction (old->utype))
		    {
		      uentry_makeVarFunction (old);
		      checkFunctionConformance (old, unew, mustConform,
						completeConform);
		      fcnConformance = TRUE;
		    }
		  else
		    {
		      KindConformanceError (old, unew, mustConform);
		    }
		}
	      else
		{
		  if (uentry_isExpandedMacro (old))
		    {
		      if (fileloc_isUndefined (unew->whereDefined))
			{
			  unew->whereDefined = fileloc_update (unew->whereDefined, 
							      old->whereDefined);
			}

		      uentry_updateInto (old, unew);
		      old->used = unew->used = TRUE;
		      return;
		    }
		  else
		    {
		      /* undeclared identifier */
		      old->utype = unew->utype;
		      uentry_makeVarFunction (old);
		      checkFunctionConformance (old, unew, FALSE, FALSE);
		      fcnConformance = TRUE;
		    }
		}
	    }
	  else
	    {
	      KindConformanceError (old, unew, mustConform);
	    }
	}
      else if (uentry_isFunction (old) && uentry_isVariable (unew))
	{
	  if (!ctype_isUnknown (unew->utype))
	    {
	      if (ctype_isFunction (unew->utype))
		{
		  uentry_makeVarFunction (unew);
		  checkFunctionConformance (old, unew, mustConform, completeConform);
		  fcnConformance = TRUE;
		}
	      else
		{
		  KindConformanceError (old, unew, mustConform);
		}
	    }
	  else
	    {
	      KindConformanceError (old, unew, mustConform);
	    }
	}
      else
	{
	  KindConformanceError (old, unew, mustConform);
	}
    }
  else
    {
      /*
      ** check parameter lists for functions 
      ** (before type errors, to get better messages
      */

      if (uentry_isFunction (old))
	{
	  checkFunctionConformance (old, unew, mustConform, completeConform);
	  fcnConformance = TRUE;
	}
      else 
	{
	  if (!ctype_isUndefined (old->utype))
	    {
	      typeError = checkTypeConformance (old, unew, mustConform);
	    }
	}
    }

 nokinderror:

  if (uentry_isEitherConstant (old) && uentry_isEitherConstant (unew))
    {
      uentry_checkConstantConformance (old, unew, mustConform, completeConform);
    }

  if (uentry_isDatatype (old) && uentry_isDatatype (unew))
    {
      DPRINTF (("Check datatype: %s / %s",
		uentry_unparseFull (old),
		uentry_unparseFull (unew)));

      uentry_checkDatatypeConformance (old, unew, mustConform, completeConform);
    }

  if (uentry_isVariable (old) && uentry_isVariable (unew))
    {
      if (!typeError && 
	  !ctype_matchDef (old->utype, unew->utype))
	{
	  if (optgenerror 
	      (FLG_INCONDEFS,
	       message
	       ("Variable %q %s with inconsistent type (arrays and pointers are "
		"not identical in variable declarations): %t",
		uentry_getName (unew), 
		uentry_reDefDecl (old, unew),
		unew->utype),
	       uentry_whereDeclared (unew)))
	    {
	      uentry_showWhereLast (old);
	      
	      /*
	      ** Avoid repeated errors.
	      */

	      if (uentry_isCodeDefined (old) && uentry_isCodeDefined (unew))
		{
		  old->whereDefined = fileloc_update (old->whereDefined,
						      fileloc_undefined);
		}

	      typeError = TRUE;
	    }
	}

      checkVarConformance (old, unew, mustConform, completeConform);
    }

  if (fcnConformance)
    {
      /* old->utype = unew->utype; */
    }
  else
    {
      if (ctype_isConj (old->utype))
	{
	  if (ctype_isConj (unew->utype))
	    {
	      if (!ctype_sameAltTypes (old->utype, unew->utype))
		{
		  if (optgenerror 
		      (FLG_INCONDEFS,
		       message ("%s %q inconsistently %rdeclared with "
				"alternate types %s "
				"(types match, but alternates are not identical, "
				"so checking may not be correct)",
				ekind_capName (uentry_getKind (old)),
				uentry_getName (unew),
				uentry_isDeclared (old),
				ctype_unparse (unew->utype)),
		       uentry_whereDeclared (unew)))
		    {
		      uentry_showWhereLastVal (old, ctype_unparse (old->utype));
		    }
		  else
		    {
		      old->utype = unew->utype;
		    }
		}
	    }
	}
      else
	{
	  if (ctype_isUnknown (old->utype))
	    {
	      old->utype = unew->utype;
	    }
	}
    }  

  if (unew->ukind == old->ukind) 
    {
      sfree (unew->info);
      unew->info = uinfo_copy (old->info, old->ukind);
    }

  sRef_storeState (old->sref);
  sRef_storeState (unew->sref);
}

static void uentry_mergeConstraints (uentry spec, uentry def)
{
  if (uentry_isFunction (def))
    {
      DPRINTF (("Here: %s / %s",
		uentry_unparseFull (spec),
		uentry_unparseFull (def)));
      /* evans 2001-07-21 */
      llassert (uentry_isFunction (spec));

      if (functionConstraint_isDefined (def->info->fcn->preconditions))
	{
	  if (fileloc_isXHFile (uentry_whereLast (def)))
	    {
	      llassert (uentry_isFunction (spec));
	      spec->info->fcn->preconditions = functionConstraint_conjoin (spec->info->fcn->preconditions,
									   def->info->fcn->preconditions);
	    }
	  else if (fileloc_equal (uentry_whereLast (spec), uentry_whereLast (def)))
	    {
	      ;
	    }
	  else
	    {
	      /* Check if the constraints are identical */

	      if (optgenerror 
		  (FLG_INCONDEFS,
		   message
		   ("Preconditions for %q redeclared. Dropping previous precondition: %q",
		    uentry_getName (spec),
		    functionConstraint_unparse (spec->info->fcn->preconditions)),
		   uentry_whereLast (def)))
		{
		  uentry_showWhereSpecified (spec);
		}

	      functionConstraint_free (spec->info->fcn->preconditions);
	      spec->info->fcn->preconditions = def->info->fcn->preconditions;
	    }
	  
	  def->info->fcn->preconditions = functionConstraint_undefined;
	}

      if (functionConstraint_isDefined (def->info->fcn->postconditions))
	{
	  if (fileloc_isXHFile (uentry_whereLast (def)))
	    {
	      llassert (uentry_isFunction (spec));
	      DPRINTF (("Post: %s /++/ %s",
			functionConstraint_unparse (spec->info->fcn->postconditions),
			functionConstraint_unparse (def->info->fcn->postconditions)));
	      spec->info->fcn->postconditions = functionConstraint_conjoin (spec->info->fcn->postconditions,
									    def->info->fcn->postconditions);
	      def->info->fcn->postconditions = functionConstraint_undefined;
	      DPRINTF (("Conjoined post: %s", functionConstraint_unparse (spec->info->fcn->postconditions)));
	    }
	  else
	    {
	      if (optgenerror 
		  (FLG_INCONDEFS,
		   message
		   ("Postconditions for %q redeclared. Dropping previous postcondition: %q",
		    uentry_getName (spec),
		    functionConstraint_unparse (spec->info->fcn->postconditions)),
		   uentry_whereLast (def)))
		{
		  uentry_showWhereSpecified (spec);
		}
	      
	      functionConstraint_free (spec->info->fcn->postconditions);
	      spec->info->fcn->postconditions = def->info->fcn->postconditions;
	      def->info->fcn->postconditions = functionConstraint_undefined;
	    }
	}
    }
}

/*
** modifies spec to reflect def, reports any inconsistencies
*/

void
uentry_mergeEntries (uentry spec, /*@only@*/ uentry def)
{
  llassert (uentry_isValid (spec));
  llassert (uentry_isValid (def));
  llassert (cstring_equal (spec->uname, def->uname));

  if (uentry_isFunction (def))
    {
      if (uentry_isConstant (spec))
	{
	  llassert (ctype_isUnknown (spec->utype) || ctype_isFunction (spec->utype));
	  uentry_makeConstantFunction (spec);
	}
      else
	{
	  uentry_convertVarFunction (spec);
	}

      llassert (uentry_isFunction (spec));
    }
  
  DPRINTF (("Merge entries: %s / %s",
	    uentry_unparseFull (spec),
	    uentry_unparseFull (def)));

  uentry_mergeConstraints (spec, def);

  uentry_checkConformance (spec, def, TRUE, 
			   context_getFlag (FLG_NEEDSPEC));

  DPRINTF (("Merge entries after conform: %s / %s",
	    uentry_unparseFull (spec),
	    uentry_unparseFull (def)));

  /* was: !(fileloc_isImport (uentry_whereSpecified (spec)))); */

  /*
  ** okay, declarations conform.  Propagate extra information.
  */

  uentry_setDefined (spec, uentry_whereDefined (def));
  uentry_setDeclared (spec, uentry_whereDeclared (def));

  if (uentry_isStatic (def))
    {
      if (optgenerror 
	  (FLG_INCONDEFS,
	   message ("%s %q specified, but declared as static",
		    ekind_capName (def->ukind),
		    uentry_getName (def)),
	   uentry_whereDeclared (def)))
	{
	  uentry_showWhereSpecified (spec);
	}
    }
  else 
    {
      spec->storageclass = def->storageclass;
    }

  sRef_storeState (spec->sref);

  spec->used = def->used || spec->used;
  spec->hasNameError |= def->hasNameError;

  uentry_free (def);

  if (!spec->hasNameError)
    {
      uentry_checkName (spec);
    }
  else
    {
      ;
    }
}

/*
** Can't generate function redeclaration errors when the 
** entries are merged, since we don't yet know if its the
** definition of the function.
*/

void
uentry_clearDecl (void)
{
  posRedeclared = uentry_undefined;
  fileloc_free (posLoc);
  posLoc = fileloc_undefined;
}

void
uentry_checkDecl (void)
{
  if (uentry_isValid (posRedeclared) && !fileloc_isXHFile (posLoc))
    {
      llassert (fileloc_isDefined (posLoc));

      if (uentry_isCodeDefined (posRedeclared))
	{
	  if (optgenerror (FLG_REDECL,
			   message ("%s %q declared after definition", 
				    ekind_capName (posRedeclared->ukind),
				    uentry_getName (posRedeclared)),
			   posLoc))
	    {
	      llgenindentmsg (message ("Definition of %q", 
				       uentry_getName (posRedeclared)),
			      posRedeclared->whereDeclared);
	    }
	}
      else
	{
	  if (optgenerror (FLG_REDECL,
			   message ("%s %q declared more than once", 
				    ekind_capName (posRedeclared->ukind),
				    uentry_getName (posRedeclared)),
			   posLoc))
	    {
	      llgenindentmsg (message ("Previous declaration of %q", 
				       uentry_getName (posRedeclared)),
			      posRedeclared->whereDeclared);
	    }
	}
    }

  fileloc_free (posLoc);
  posLoc = fileloc_undefined;
  posRedeclared = uentry_undefined;
}

/*
** Redefinition of old as unew.
** modifies old to reflect unew, reports any inconsistencies
*/

void
uentry_mergeDefinition (uentry old, /*@only@*/ uentry unew)
{
  fileloc olddef = uentry_whereDeclared (old); 
  fileloc unewdef = uentry_whereDeclared (unew);
  bool mustConform;
  bool wasForward;

  DPRINTF (("uentry merge: %s / %s",
	    uentry_unparseFull (old),
	    uentry_unparseFull (unew)));
 
  wasForward = 
    fileloc_isUndefined (olddef) 
    && fileloc_isDefined (uentry_whereDefined (old)) 
    && !uentry_isExpandedMacro (old);
  
  if (!context_getFlag (FLG_INCONDEFSLIB)
      && (fileloc_isLib (olddef) || fileloc_isImport (olddef)))
    {
      mustConform = FALSE;
    }
  else
    {
      mustConform = TRUE;
    }
  
  llassert (uentry_isValid (old));
  llassert (uentry_isValid (unew));
  llassert (cstring_equal (old->uname, unew->uname));

  if (uentry_isFunction (unew) && !uentry_isFunction (old))
    {
      if (uentry_isConstant (old))
	{
	  llassert (ctype_isUnknown (old->utype) || ctype_isFunction (old->utype));
	  uentry_makeConstantFunction (old);
	}
      else
	{
	  uentry_convertVarFunction (old);
	}

      llassert (uentry_isFunction (old));
    }

  DPRINTF (("uentry merge: %s / %s",
	    uentry_unparseFull (old),
	    uentry_unparseFull (unew)));

  if (uentry_isExtern (unew))
    {
      uentry_setUsed (old, unewdef);
    }

  /*
  ** should check old one was extern!
  */

  if (uentry_isStatic (old))
    {
      if (!(uentry_isStatic (unew)))
	{
	  if (optgenerror 
	      (FLG_SHADOW,
	       message ("%s %q shadows static declaration",
			ekind_capName (unew->ukind),
			uentry_getName (unew)),
	       unewdef))
	    {
	      uentry_showWhereLast (old);
	    }
	}
      else
	{
	  uentry_setDeclDef (old, unewdef);
	}
    }
  else if (uentry_isStatic (unew))
    {
      uentry_setDeclDef (old, unewdef);
    }
  else if (uentry_isExtern (old))
    {
      uentry_setDeclared (old, unewdef);
    }
  else
    {
      if (!uentry_isExtern (unew) 
	  && !uentry_isForward (old)
	  && !fileloc_equal (olddef, unewdef)
	  && !fileloc_isUndefined (olddef)
	  && !fileloc_isUndefined (unewdef)
	  && !fileloc_isBuiltin (olddef)
	  && !fileloc_isBuiltin (unewdef)
	  && !uentry_isYield (old)
	  && !(fileloc_isLib (olddef) || fileloc_isImport (olddef)))
	{
	  if (uentry_isVariable (old) || uentry_isVariable (unew))
	    {
	      ; /* will report redeclaration error later */
	    }
	  else
	    {
	      if (fileloc_isDefined (uentry_whereDefined (old)))
		{
		  if (optgenerror
		      (FLG_REDEF,
		       message ("%s %q defined more than once", 
				ekind_capName (unew->ukind),
				uentry_getName (unew)),
		       uentry_whereLast (unew)))
		    {
		      llgenindentmsg
			(message ("Previous definition of %q", 
				  uentry_getName (old)),
			 uentry_whereLast (old));
		    }
		  /*
		  if (uentry_isDatatype (old) || uentry_isAnyTag (old))
		    {
		      uentry_updateInto (old, unew);
		      old->sref = sRef_saveCopy (old->sref);
		    }
		    */
		}
	    }
	}
      else
	{
	  if (fileloc_isLib (olddef)
	      || fileloc_isUndefined (olddef)
	      || fileloc_isImport (olddef))
	    {
	      if (uentry_isExtern (unew)) 
		{
		  if (uentry_isExtern (old)
		      || (fileloc_isDefined (uentry_whereDeclared (old))
			  && (!fileloc_equal (uentry_whereDeclared (old),
					      uentry_whereDefined (old)))))
		    {
		      if (optgenerror
			  (FLG_REDECL,
			   message ("%s %q declared more than once", 
				    ekind_capName (unew->ukind),
				    uentry_getName (unew)),
			   unew->whereDeclared))
			{
			  llgenindentmsg
			    (message ("Previous declaration of %q", 
				      uentry_getName (old)),
			     old->whereDeclared);
			}
		    }
		  
		  uentry_setExtern (old);
		}
	      else
		{
		  uentry_setDeclared (old, unewdef); /* evans 2001-07-23 was setDefined */
		}
	    }
	}
    }

  DPRINTF (("uentry merge: %s / %s",
	    uentry_unparseFull (old),
	    uentry_unparseFull (unew)));

  uentry_mergeConstraints (old, unew);
  DPRINTF (("uentry merge: %s / %s",
	    uentry_unparseFull (old),
	    uentry_unparseFull (unew)));

  uentry_checkConformance (old, unew, mustConform, FALSE);
  DPRINTF (("uentry merge: %s / %s",
	    uentry_unparseFull (old),
	    uentry_unparseFull (unew)));

  old->used = old->used || unew->used;
  old->uses = filelocList_append (old->uses, unew->uses);
  unew->uses = filelocList_undefined; 

  sRef_storeState (old->sref); 
  sRef_storeState (unew->sref);

  if (wasForward)
    {
      old->whereDefined = fileloc_update (old->whereDefined,
					  fileloc_undefined);
    }

  DPRINTF (("here: %s", uentry_unparseFull (old)));

  /*
  ** No redeclaration errors for functions here, since we
  ** don't know if this is the definition of the function.
  */

  if (fileloc_isUser (old->whereDeclared)
      && fileloc_isUser (unew->whereDeclared)
      && !fileloc_equal (old->whereDeclared, unew->whereDeclared)
      && !fileloc_isDefined (unew->whereDefined))
    {
      if (uentry_isFunction (old))
	{
	  /*@-temptrans@*/ posRedeclared = old; /*@=temptrans@*/
	  posLoc = fileloc_update (posLoc, unew->whereDeclared);
	}
      else
	{
	  if (optgenerror (FLG_REDECL,
			   message ("%s %q declared more than once", 
				    ekind_capName (unew->ukind),
				    uentry_getName (unew)),
			   unew->whereDeclared))
	    {
	      llgenindentmsg (message ("Previous declaration of %q", 
				       uentry_getName (old)),
			      old->whereDeclared);
	    }
	}
    }

  if (fileloc_isUndefined (old->whereDefined))
    {
      old->whereDefined = fileloc_update (old->whereDefined, unew->whereDefined);
    }
  else
    {
      if (!context_processingMacros ()
	  && fileloc_isUser (old->whereDefined) 
	  && fileloc_isUser (unew->whereDefined)
	  && !fileloc_equal (old->whereDefined, unew->whereDefined))
	{
	  if (uentry_isVariable (unew) || uentry_isFunction (unew))
	    {
	      if (uentry_isVariable (unew) 
		  && uentry_isExtern (unew))
		{
		  if (optgenerror (FLG_REDECL,
				   message ("%s %q declared after definition", 
					    ekind_capName (unew->ukind),
					    uentry_getName (unew)),
				   unew->whereDeclared))
		    {
		      llgenindentmsg (message ("Definition of %q", 
					       uentry_getName (old)),
				      old->whereDefined);
		    }
		}
	      else
		{
		  if (optgenerror (FLG_REDEF,
				   message ("%s %q redefined", 
					    ekind_capName (unew->ukind),
					    uentry_getName (unew)),
				   unew->whereDefined))
		    {
		      llgenindentmsg (message ("Previous definition of %q", 
					       uentry_getName (old)),
				      old->whereDefined);
		    }
		}
	    }
	}
    }

  if (uentry_isExternal (unew))
    {
      old->whereDefined = fileloc_createExternal ();
    }

  if (unew->hasNameError)
    {
      old->hasNameError = TRUE;
    }

  uentry_free (unew);

  if (!old->hasNameError)
    {
      uentry_checkName (old);
    }

  DPRINTF (("After: %s", uentry_unparseFull (old)));
  llassert (!ctype_isUndefined (old->utype));
}

void
uentry_copyState (uentry res, uentry other)
{
  llassert (uentry_isValid (res));
  llassert (uentry_isValid (other));

  res->used = other->used;

  res->info->var->kind = other->info->var->kind;
  res->info->var->defstate = other->info->var->defstate;
  res->info->var->nullstate = other->info->var->nullstate;
  res->info->var->checked = other->info->var->checked;

  sRef_copyState (res->sref, other->sref);
}

bool
uentry_sameKind (uentry u1, uentry u2)
{
  if (uentry_isValid (u1) && uentry_isValid (u2))
    {
      if (uentry_isVar (u1) && uentry_isVar (u2))
	{
	  ctype c1 = u1->utype;
	  ctype c2 = u2->utype;

	  if (ctype_isUnknown (c1) || ctype_isUnknown (c2)) return FALSE;

	  /*
	  ** both functions, or both not functions
	  */

	  return (bool_equal (ctype_isFunction (c1), ctype_isFunction (c2)));
	}
      else
	{
	  return ((u1->ukind == u2->ukind));
	}
    }
  
  return FALSE;
}
   
static void uentry_updateInto (/*@unique@*/ uentry unew, uentry old)
{
  ekind okind = unew->ukind;
  llassert (uentry_isValid (unew));
  llassert (uentry_isValid (old));

  DPRINTF (("Update into: %s / %s", uentry_unparseFull (unew), uentry_unparseFull (old)));

  unew->ukind = old->ukind;
  llassert (cstring_equal (unew->uname, old->uname));
  unew->utype = old->utype;

  if (fileloc_isDefined (unew->whereSpecified) 
      && !fileloc_isDefined (old->whereSpecified))
    {
      ; /* Keep the old value */
    }
  else
    {
      fileloc_free (unew->whereSpecified); /*@i523 why no error without this? */
      unew->whereSpecified = fileloc_copy (old->whereSpecified);
    }

  if (fileloc_isDefined (unew->whereDefined) 
      && !fileloc_isDefined (old->whereDefined))
    {
      ; /* Keep the old value */
    }
  else
    {
      fileloc_free (unew->whereDefined); /*@i523 why no error without this? */
      unew->whereDefined = fileloc_copy (old->whereDefined);
    }

  if (fileloc_isDefined (unew->whereDeclared) 
      && !fileloc_isDefined (old->whereDeclared))
    {
      ; /* Keep the old value */
    }
  else
    {
      fileloc_free (unew->whereDeclared); /*@i523 why no error without this? */
      unew->whereDeclared = fileloc_copy (old->whereDeclared);
    }

  DPRINTF (("Update into: %s / %s", uentry_unparseFull (unew), uentry_unparseFull (old)));

  unew->sref = sRef_saveCopy (old->sref); /* Memory leak! */
  unew->used = old->used;
  unew->lset = FALSE;
  unew->isPrivate = old->isPrivate;
  unew->hasNameError = old->hasNameError;
  unew->uses = filelocList_append (unew->uses, old->uses);
  old->uses = filelocList_undefined;

  unew->storageclass = old->storageclass;
  uinfo_free (unew->info, okind);
  unew->info = uinfo_copy (old->info, old->ukind);
}


uentry
uentry_copy (uentry e)
{
  if (uentry_isValid (e))
    {
      uentry enew = uentry_alloc ();
      DPRINTF (("copy: %s", uentry_unparseFull (e)));
      enew->ukind = e->ukind;
      enew->uname = cstring_copy (e->uname);
      enew->utype = e->utype;
      
      enew->whereSpecified = fileloc_copy (e->whereSpecified);
      enew->whereDefined = fileloc_copy (e->whereDefined);
      enew->whereDeclared = fileloc_copy (e->whereDeclared);
      
      enew->sref = sRef_saveCopy (e->sref); /* Memory leak! */
      enew->used = e->used;
      enew->lset = FALSE;
      enew->isPrivate = e->isPrivate;
      enew->hasNameError = e->hasNameError;
      enew->uses = filelocList_undefined;
      
      enew->storageclass = e->storageclass;
      enew->info = uinfo_copy (e->info, e->ukind);
      enew->warn = warnClause_copy (e->warn);

      DPRINTF (("Here we are..."));
      DPRINTF (("original: %s", uentry_unparseFull (e)));
      DPRINTF (("copy: %s", uentry_unparse (enew)));
      DPRINTF (("copy: %s", uentry_unparseFull (enew)));
      return enew;
    }
  else
    {
      return uentry_undefined;
    }
}

void
uentry_setState (uentry res, uentry other)
{
  llassert (uentry_isValid (res));
  llassert (uentry_isValid (other));

  llassert (res->ukind == other->ukind);
  llassert (res->ukind == KVAR);

  res->sref = sRef_saveCopy (other->sref);
  res->used = other->used;
  filelocList_free (res->uses); 
  res->uses = other->uses; 
  other->uses = filelocList_undefined; 
  res->lset = other->lset;
}

void
uentry_mergeUses (uentry res, uentry other)
{
  llassert (uentry_isValid (res));
  llassert (uentry_isValid (other));

  res->used = other->used || res->used;
  res->lset = other->lset || res->lset;
  res->uses = filelocList_append (res->uses, other->uses);
  other->uses = filelocList_undefined;
}


/*
** This is a really ugly routine.
**
** gack...fix this one day.
*/

/*
** flip == TRUE
**   >> res is the false branch, other is the true branch (or continuation)
** flip == FALSE
**   >> res is the true branch, other is the false branch (or continutation)
**
** opt == TRUE if,
**
** <other>
** if <res> ;
**
** References not effected by res are propagated from other.
*/

static void
  branchStateError (/*@notnull@*/ uentry res, /*@notnull@*/ uentry other, 
		    bool flip, clause cl, fileloc loc)
{
  if (optgenerror 
      (FLG_BRANCHSTATE,
       message ("%s %q is %s %s, but %s %s.",
		ekind_capName (res->ukind), uentry_getName (res),
		sRef_stateVerb (res->sref), clause_nameFlip (cl, flip),
		sRef_stateAltVerb (res->sref), clause_nameFlip (cl, !flip)),
       loc))
    {
      if (sRef_isDead (res->sref))
	{
	  sRef_showStateInfo (res->sref);
	}
      else if (sRef_isKept (res->sref))
	{
	  sRef_showAliasInfo (res->sref);
	}
      else /* dependent */
	{
	  sRef_showAliasInfo (res->sref);
	  sRef_showAliasInfo (other->sref);
	}
      
      sRef_setAliasKind (res->sref, AK_ERROR, fileloc_undefined);
    }
}

static bool uentry_incompatibleMemoryStates (sRef rs, sRef os)
{
  alkind rk = sRef_getAliasKind (rs);
  alkind ok = sRef_getAliasKind (os);

  if (alkind_isError (rk) || alkind_isError (ok))
    {
      return FALSE;
    }
  else
    {
      return ((sRef_isDead (rs)
	       || (alkind_isKept (rk) && !alkind_isKept (ok))
	       || (alkind_isDependent (rk) 
		   && !alkind_isDependent (ok) && !alkind_isTemp (ok)))
	      && (sRef_isAllocated (os) || sRef_isStateDefined (os)));
    }
}

static void
  branchStateAltError (/*@notnull@*/ uentry res,
		       /*@notnull@*/ uentry other, bool flip,
		       clause cl, fileloc loc)
{
  if (optgenerror 
      (FLG_BRANCHSTATE,
       message ("%s %q is %s %s, but %s %s.",
		ekind_capName (res->ukind), uentry_getName (res),
		sRef_stateVerb (other->sref), clause_nameFlip (cl, flip),
		sRef_stateAltVerb (other->sref), clause_nameFlip (cl, !flip)),
       loc))
    {
      if (sRef_isDead (other->sref))
	{
	  sRef_showStateInfo (other->sref);
	}
      else /* kept */
	{
	  sRef_showAliasInfo (other->sref);
	}
      
      sRef_setAliasKind (res->sref, AK_ERROR, fileloc_undefined);
      sRef_setDefinedComplete (res->sref, fileloc_undefined);
      
      sRef_setAliasKind (other->sref, AK_ERROR, fileloc_undefined);
      sRef_setDefinedComplete (other->sref, fileloc_undefined);
    }
}

/*
** A reference is relevant for certain checks, only if it 
** is not definitely null on this path (but not declared
** to always be null.)
*/

static bool uentry_relevantReference (sRef sr, bool flip)
{
  if (sRef_isKept (sr) || sRef_isDependent (sr))
    {
      return FALSE;
    }
  else
    {
      if (flip)
	{
	  return !sRef_definitelyNullContext (sr);
	}
      else
	{
	  return !sRef_definitelyNullAltContext (sr);
	}
    }
}

static void
uentry_mergeAliasStates (uentry res, uentry other, fileloc loc,
			 bool mustReturn, bool flip, bool opt,
			 clause cl)    
{
  sRef rs = res->sref;
  sRef os = other->sref;

  DPRINTF (("Merge alias states: %s / %s",
	    uentry_unparseFull (res),
	    uentry_unparseFull (other)));

  if (sRef_isValid (rs))
    {
      if (!mustReturn)
	{
	  if (uentry_incompatibleMemoryStates (rs, os))
	    {
	      DPRINTF (("Incompatible: \n\t%s / \n\t%s",
			sRef_unparseFull (rs), sRef_unparseFull (os)));

	      if (sRef_isThroughArrayFetch (rs)
		  && !context_getFlag (FLG_STRICTBRANCHSTATE))
		{
		  if (sRef_isKept (rs) || sRef_isKept (os))
		    {
		      sRef_maybeKill (rs, loc);
		    }
		  else if (sRef_isPossiblyDead (os))
		    {
		      sRef_maybeKill (rs, loc);
		    }
		  else
		    {
		      ;
		    }
		}
	      else
		{
		  if (uentry_relevantReference (os, flip))
		    {
		      if (sRef_isLocalParamVar (rs) 
			  && (sRef_isLocalState (os) 
			      || sRef_isDependent (os)))
			{
			  if (sRef_isDependent (rs))
			    {
			      sRef_setDependent (os, loc);
			    }
			  else
			    {
			      sRef_setDefState (rs, SS_UNUSEABLE, loc);
			    }
			}
		      else 
			{
			  branchStateError (res, other, flip, cl, loc);
			}
		    }
		}
	      
	      if (sRef_isKept (rs))
		{
		  DPRINTF (("Setting kept: %s", sRef_unparseFull (os)));
		  sRef_setKept (os, loc);
		}
	    }
	  else
	    {
	      if (uentry_incompatibleMemoryStates (os, rs))
		{
		  if (uentry_relevantReference (rs, !flip))
		    {
		      if (sRef_isLocalParamVar (rs) 
			  && (sRef_isDependent (rs)
			      || sRef_isLocalState (rs)))
			{
			  if (sRef_isDependent (os))
			    {
			      sRef_setDependent (rs, loc);
			    }
			  else
			    {
			      sRef_setDefState (rs, SS_UNUSEABLE, loc);
			    }
			}
		      else
			{
			  if (sRef_isParam (os))
			    {
			      /* 
		              ** If the local variable associated
			      ** with the param has the correct state,
			      ** its okay.
			      ** (e.g., free (s); s = new(); ...
			      */
			      
			      uentry uvar = usymtab_lookupSafe (other->uname);
			      
			      if (uentry_isValid (uvar)
				  && ((sRef_isDead (os) 
				       && sRef_isOnly (uvar->sref))
				      || (sRef_isDependent (os)
					  && sRef_isOwned (uvar->sref))))
				{
				  /* no error */
				}
			      else
				{
				  branchStateAltError (res, other,
						       flip, cl, loc);
				}
			    }
			  else
			    {
			      DPRINTF (("Here: %s / %s",
					uentry_unparseFull (res),
					uentry_unparseFull (other)));

			      branchStateAltError (res, other, 
						   flip, cl, loc);
			    }
			}
		    }
		}
	      
	      if (sRef_isKept (os))
		{
		  sRef_setKept (rs, loc);
		}
	    }
	  
	  if (opt)
	    {
	      DPRINTF (("Merge opt..."));
	      sRef_mergeOptState (rs, os, cl, loc);
	      DPRINTF (("Done!"));
	    }
	  else
	    {
	      DPRINTF (("Merging states: \n\t%s / \n\t%s", sRef_unparseFull (rs), sRef_unparseFull (os)));
	      sRef_mergeState (rs, os, cl, loc);
	      DPRINTF (("After merging : \n\t%s / \n\t%s", sRef_unparseFull (rs), sRef_unparseFull (os)));
	    }
	}
      else
	{
	  if (sRef_isModified (os))
	    {
	      sRef_setModified (rs);
	    }
	}
    }

  DPRINTF (("After merge: %s", sRef_unparseFull (res->sref)));
}

static void
uentry_mergeValueStates (uentry res, uentry other, fileloc loc, bool mustReturn, /*@unused@*/ bool flip)
{
  valueTable rvalues;
  valueTable ovalues;

  DPRINTF (("Merge values: %s / %s", sRef_unparseFull (res->sref), sRef_unparseFull (other->sref)));
  
  if (mustReturn)
    {
      return;
    }
  /* flip? */

  rvalues = sRef_getValueTable (res->sref);
  ovalues = sRef_getValueTable (other->sref);
  
  if (valueTable_isUndefined (ovalues))
    {
      DPRINTF (("No value table: %s", sRef_unparseFull (other->sref)));
      ;
    }
  else if (valueTable_isUndefined (rvalues))
    {
      /*
      ** Copy values from other
      */
      
      /*@i$@#@*/
      DPRINTF (("Has value table: %s", sRef_unparseFull (other->sref)));
      DPRINTF (("No value table: %s", sRef_unparseFull (res->sref)));
      ;
    }
  else
    {
      valueTable_elements (ovalues, fkey, fval) {
	stateValue tval;
	metaStateInfo minfo;
	stateCombinationTable sctable;
	cstring msg;
	int nval;

	tval = valueTable_lookup (rvalues, fkey);
	
	DPRINTF (("Merge value: %s / %s X %s", fkey, 
		  stateValue_unparse (fval), stateValue_unparse (tval)));

	minfo = context_lookupMetaStateInfo (fkey);
	llassert (stateValue_isDefined (tval));
	
	if (metaStateInfo_isUndefined (minfo) || !stateValue_isDefined (tval)) 
	  {
	    DPRINTF (("Cannot find meta state for: %s", fkey));
	    BADBRANCH;
	  }
	else
	  {
	    llassert (metaStateInfo_isDefined (minfo));

	    if (stateValue_isError (fval)
		|| sRef_definitelyNullContext (res->sref))
	      {
		sRef_setMetaStateValueComplete (res->sref, 
						fkey, stateValue_getValue (fval), 
						stateValue_getLoc (fval));
		DPRINTF (("Setting res: %s", sRef_unparseFull (res->sref)));
	      }
	    else if (stateValue_isError (tval)
		     || sRef_definitelyNullAltContext (other->sref))
	      {
		DPRINTF (("Other branch is definitely null!"));
	      }
	    else if (sRef_isStateUndefined (res->sref)
		     || sRef_isDead (res->sref))
	      {
		; /* Combination state doesn't matter if it is undefined or dead */
	      }
	    else 
	      {
		DPRINTF (("Check: %s / %s / %s / %s", fkey,
			  metaStateInfo_unparse (minfo),
			  stateValue_unparse (fval),
			  stateValue_unparse (tval)));
		
		DPRINTF (("state values: %d / %d",
			  stateValue_getValue (fval), stateValue_getValue (tval)));
		
		sctable = metaStateInfo_getMergeTable (minfo);

		DPRINTF (("Merge table: %s",
			  stateCombinationTable_unparse (sctable)));
		
		msg = cstring_undefined;
		
		nval = stateCombinationTable_lookup (sctable, 
						     stateValue_getValue (fval), 
						     stateValue_getValue (tval), 
						     &msg);

		DPRINTF (("nval: %d / %d / %d", nval,
			  stateValue_getValue (fval), stateValue_getValue (tval)));

		if (nval == stateValue_error)
		  {
		    /*@i32 print extra info for assignments@*/

		    if (uentry_isGlobalMarker (res))
		      {
			if (optgenerror 
			    (FLG_STATEMERGE,
			     message
			     ("Control branches merge with incompatible global states (%s and %s)%q",
			      metaStateInfo_unparseValue (minfo, stateValue_getValue (fval)),
			      metaStateInfo_unparseValue (minfo, stateValue_getValue (tval)),
			      cstring_isDefined (msg) 
			      ? message (": %s", msg) : cstring_undefined),
			     loc))
			  {
			    sRef_showMetaStateInfo (res->sref, fkey);
			    sRef_showMetaStateInfo (other->sref, fkey);
			  }
		      }
		    else
		      {
			if (optgenerror 
			    (FLG_STATEMERGE,
			     message
			     ("Control branches merge with incompatible states for %q (%s and %s)%q",
			      uentry_getName (res),
			      metaStateInfo_unparseValue (minfo, stateValue_getValue (fval)),
			      metaStateInfo_unparseValue (minfo, stateValue_getValue (tval)),
			      cstring_isDefined (msg) 
			      ? message (": %s", msg) : cstring_undefined),
			     loc))
			  {
			    sRef_showMetaStateInfo (res->sref, fkey);
			    sRef_showMetaStateInfo (other->sref, fkey);
			    DPRINTF (("Res: %s", sRef_unparseFull (res->sref)));
			    DPRINTF (("Other: %s", sRef_unparseFull (other->sref)));
 			    DPRINTF (("Null: %s / %s",
				      bool_unparse (usymtab_isDefinitelyNull (res->sref)),
				      bool_unparse (usymtab_isDefinitelyNull (other->sref))));

			  }
		      }
		  }

		if (nval == stateValue_getValue (fval)
		    && nval != stateValue_getValue (tval))
		  {
		    loc = stateValue_getLoc (fval);
		  }
		else if (nval == stateValue_getValue (tval)
			 && nval != stateValue_getValue (fval))
		  {
		    loc = stateValue_getLoc (tval);
		  }
		else
		  {
		    ;
		  }

		if (stateValue_getValue (sRef_getMetaStateValue (res->sref, fkey)) == nval
		    && nval == stateValue_getValue (fval)
		    && nval == stateValue_getValue (tval))
		  {
		    ;
		  }
		else
		  {
		    sRef_setMetaStateValueComplete (res->sref, fkey, nval, loc);
		  }
	      }
	  }
      } end_valueTable_elements ;
    } 
}


static void
uentry_mergeSetStates (uentry res, uentry other, /*@unused@*/ fileloc loc,
		       bool flip, clause cl)
{
  if (cl == DOWHILECLAUSE)
    {
      res->used = other->used || res->used;
      res->lset = other->lset || res->lset;
      res->uses = filelocList_append (res->uses, other->uses);
      other->uses = filelocList_undefined;
    }
  else
    {
      if (sRef_isMacroParamRef (res->sref)
	  && !uentry_isSefParam (other)
	  && !uentry_isSefParam (res))
	{
	  bool hasError = FALSE;
	  
	  if (bool_equal (res->used, other->used))
	    {
	      res->used = other->used;
	    }
	  else
	    {
	      if (other->used && !flip)
		{
		  hasError = 
		    optgenerror 
		    (FLG_MACROPARAMS,
		     message ("Macro parameter %q used in true clause, "
			      "but not in false clause",
			      uentry_getName (res)),
		     uentry_whereDeclared (res));
		}
	      else
		{	
		  hasError = 
		    optgenerror 
		    (FLG_MACROPARAMS,
		     message ("Macro parameter %q used in false clause, "
			      "but not in true clause",
			      uentry_getName (res)),
		     uentry_whereDeclared (res));
		}
	      res->used = TRUE;
	      
	      if (hasError)
		{
		  /* make it sef now, prevent more errors */
		  res->info->var->kind = VKREFSEFPARAM;
		}
	    }
	}
      else
	{
	  res->used = other->used || res->used;
	  res->lset = other->lset || res->lset;
	  res->uses = filelocList_append (res->uses, other->uses);
	  other->uses = filelocList_undefined;
	}
    }
}

void
uentry_mergeState (uentry res, uentry other, fileloc loc,
		   bool mustReturn, bool flip, bool opt,
		   clause cl)
{
  llassert (uentry_isValid (res));
  llassert (uentry_isValid (other));

  llassert (res->ukind == other->ukind);
  llassert (res->ukind == KVAR);

  DPRINTF (("Merge state: %s / %s", uentry_unparseFull (res),
	    uentry_unparseFull (other)));
  
  uentry_mergeAliasStates (res, other, loc, mustReturn, flip, opt, cl);
  uentry_mergeValueStates (res, other, loc, mustReturn, flip);
  uentry_mergeSetStates (res, other, loc, flip, cl);

  DPRINTF (("Merge ==> %s", uentry_unparseFull (res)));
}

void uentry_setUsed (uentry e, fileloc loc)
{
  static bool firstTime = TRUE;
  static bool showUses = FALSE;
  static bool exportLocal = FALSE;

  DPRINTF (("Used: %s / %s", uentry_unparse (e), fileloc_unparse (loc)));

  if (firstTime)
    {
      /* need to track uses is FLG_SHOWUSES or FLG_EXPORTLOCAL is true */

      showUses = context_getFlag (FLG_SHOWUSES); 
      exportLocal = context_maybeSet (FLG_EXPORTLOCAL);

      firstTime = FALSE;
    }

  if (uentry_isValid (e))
    {
      int dp;

      if (warnClause_isDefined (e->warn))
	{
	  flagSpec flg = warnClause_getFlag (e->warn);
	  cstring msg;

	  if (warnClause_hasMessage (e->warn))
	    {
	      msg = cstring_copy (warnClause_getMessage (e->warn));
	    }
	  else
	    {
	      msg = message ("Use of possibly dangerous %s",
			     uentry_ekindNameLC (e));
	    }

	  vfsgenerror (flg, 
		       message ("%q: %q", msg, uentry_getName (e)),
		       loc);
	}

      if (sRef_isMacroParamRef (e->sref))
	{
	  if (uentry_isYield (e) || uentry_isSefParam (e))
	    {
	      ;
	    }
	  else 
	    {
	      if (context_inConditional ())
		{
		  if (optgenerror
		      (FLG_MACROPARAMS,
		       message ("Macro parameter %q used in conditionally "
				"executed code (may or may not be "
				"evaluated exactly once)", 
				uentry_getName (e)),
		       loc))
		    {
		      e->info->var->kind = VKREFSEFPARAM;
		    }
		}
	      else
		{
		  if ((e)->used)
		    {
		      if (optgenerror
			  (FLG_MACROPARAMS,
			   message ("Macro parameter %q used more than once", 
				    uentry_getName (e)),
			   uentry_whereDeclared (e)))
			{
			  e->info->var->kind = VKREFSEFPARAM;
			}
		    }
		}
	    }
	}
      
      if ((dp = uentry_directParamNo (e)) >= 0)
	{
	  uentry_setUsed (usymtab_getParam (dp), loc);
	}
      
      e->used = TRUE;

      if (!sRef_isLocalVar (e->sref))
	{
	  if (showUses)
	    {
	      e->uses = filelocList_add (e->uses, fileloc_copy (loc));
	    }
	  else 
	    {
	      if (exportLocal)
		{
		  if (context_inMacro ())
		    {
		      e->uses = filelocList_addUndefined (e->uses);
		    }
		  else 
		    {
		      e->uses = filelocList_addDifferentFile
			(e->uses, 
			 uentry_whereDeclared (e),
			 loc);
		    }
		}
	    }
	}
    }
}

bool uentry_isReturned (uentry u)
{
  return (uentry_isValid (u) && uentry_isVar (u) 
	  && (u->info->var->kind == VKRETPARAM
	      || u->info->var->kind == VKSEFRETPARAM));
}

/*@exposed@*/ sRef uentry_returnedRef (uentry u, exprNodeList args)
{
  llassert (uentry_isRealFunction (u));

  if (ctype_isFunction (u->utype) && sRef_isStateSpecial (uentry_getSref (u)))
    {
      stateClauseList clauses = uentry_getStateClauseList (u);
      sRef res = sRef_makeNew (ctype_getReturnType (u->utype), u->sref, u->uname);

      DPRINTF (("Returned: %s", sRef_unparseFull (res)));
      sRef_setAllocated (res, g_currentloc);

      DPRINTF (("ensures clause: %s / %s", uentry_unparse (u), 
		stateClauseList_unparse (clauses)));

      /*
      ** This should be in exprNode_reflectEnsuresClause
      */

      stateClauseList_postElements (clauses, cl)
	{
	  if (!stateClause_isGlobal (cl))
	    {
	      sRefSet refs = stateClause_getRefs (cl);
	      sRefMod modf = stateClause_getEffectFunction (cl);
	      
	      sRefSet_elements (refs, el)
		{
		  sRef base = sRef_getRootBase (el);
		  
		  if (sRef_isResult (base))
		    {
		      if (modf != NULL)
			{
			  sRef sr = sRef_fixBase (el, res);
			  modf (sr, g_currentloc);
			}
		    }
		  else
		    {
		      ;
		    }
		} end_sRefSet_elements ;
	    }
	} end_stateClauseList_postElements ;
	
      return res;
    }
  else
    {
      uentryList params;
      alkind ak;
      sRefSet prefs = sRefSet_new ();
      sRef res = sRef_undefined;
      int paramno = 0;
      
      params = uentry_getParams (u);
      
      uentryList_elements (params, current)
	{
	  if (uentry_isReturned (current))
	    {
	      if (exprNodeList_size (args) >= paramno)
		{
		  exprNode ecur = exprNodeList_nth (args, paramno);
		  sRef tref = exprNode_getSref (ecur);
		  
		  DPRINTF (("Returned reference: %s", sRef_unparseFull (tref)));

		  if (sRef_isValid (tref))
		    {
		      sRef tcref = sRef_copy (tref);
		      
		      usymtab_addForceMustAlias (tcref, tref); /* evans 2001-05-27 */

		      if (sRef_isDead (tcref))
			{
			  sRef_setDefined (tcref, g_currentloc);
			  sRef_setOnly (tcref, g_currentloc);
			}
		      
		      if (sRef_isRefCounted (tcref))
			{
			  /* could be a new ref now (but only if its returned) */
			  sRef_setAliasKindComplete (tcref, AK_ERROR, g_currentloc);
			}
		      
		      sRef_makeSafe (tcref);
		      prefs = sRefSet_insert (prefs, tcref);
		    }
		}
	    }
	  
	  paramno++;
	} end_uentryList_elements ;
      
      if (sRefSet_size (prefs) > 0)
	{
	  nstate n = sRef_getNullState (u->sref);
	  
	  if (sRefSet_size (prefs) == 1)
	    {
	      res = sRefSet_choose (prefs);
	    }
	  else
	    {
	      /* should this ever happen? */ /*@i534 evans 2001-05-27 */
	      res = sRefSet_mergeIntoOne (prefs);
	    }
	  
	  if (nstate_isKnown (n))
	    {
	      sRef_setNullState (res, n, g_currentloc);
	    }
	}
      else
	{
	  if (ctype_isFunction (u->utype))
	    {
	      DPRINTF (("Making new from %s  -->", uentry_unparseFull (u)));
	      res = sRef_makeNew (ctype_getReturnType (u->utype), u->sref, u->uname);
	    }
	  else
	    {
	      res = sRef_makeNew (ctype_unknown, u->sref, u->uname);
	    }
	  
	  if (sRef_isRefCounted (res))
	    {
	      sRef_setAliasKind (res, AK_NEWREF, g_currentloc);
	    }
	}
      

      if (sRef_getNullState (res) == NS_ABSNULL)
	{
	  ctype ct = ctype_realType (u->utype);
	  
	  if (ctype_isAbstract (ct))
	    {
	      sRef_setNotNull (res, g_currentloc);
	    }
	  else
	    {
	      if (ctype_isUser (ct))
		{
		  sRef_setStateFromUentry (res, usymtab_getTypeEntry (ctype_typeId (ct)));
		}
	      else
		{
		  sRef_setNotNull (res, g_currentloc);
		}
	    }
	}
      
      if (sRef_isRefCounted (res))
	{
	  sRef_setAliasKind (res, AK_NEWREF, g_currentloc);
	}
      else if (sRef_isKillRef (res))
	{
	  sRef_setAliasKind (res, AK_REFCOUNTED, g_currentloc);
	}
      else
	{
	  ;
	}
      
      ak = sRef_getAliasKind (res);
      
      if (alkind_isImplicit (ak))
	{
	  sRef_setAliasKind (res, 
			     alkind_fixImplicit (ak),
			     g_currentloc);
	}
      
      sRefSet_free (prefs);
      
      DPRINTF (("Returns ref: %s", sRef_unparseFull (res)));
      return res;
    }
}

static bool uentry_isRefCounted (uentry ue)
{
  ctype ct = uentry_getType (ue);

  if (ctype_isFunction (ct))
    {
      return (ctype_isRefCounted (ctype_getReturnType (ct)));
    }
  else
    {
      return (ctype_isRefCounted (ct));
    }
}

/*
** old was declared yield in the specification.  
** new is declared in the iter implementation.
*/

void uentry_checkYieldParam (uentry old, uentry unew)
{
  cstring name;

  llassert (uentry_isVariable (old));
  llassert (uentry_isVariable (unew));

  unew->info->var->kind = VKYIELDPARAM;
  (void) checkTypeConformance (old, unew, TRUE);
  checkVarConformance (old, unew, TRUE, FALSE);

  /* get rid of param marker */

  name = uentry_getName (unew);
  cstring_free (unew->uname);
  unew->uname = name;
  unew->info->var->kind = VKREFYIELDPARAM;

  uentry_setUsed (old, fileloc_undefined);
  uentry_setUsed (unew, fileloc_undefined);
}

/*@observer@*/ cstring
uentry_ekindName (uentry ue)
{
  if (uentry_isValid (ue))
    {
      switch (ue->ukind)
	{
	case KINVALID:
	  return cstring_makeLiteralTemp ("<Error: invalid uentry>");
	case KDATATYPE: 
	  return cstring_makeLiteralTemp ("Datatype");
	case KENUMCONST:
	  return cstring_makeLiteralTemp ("Enum member");
	case KCONST:  
	  return cstring_makeLiteralTemp ("Constant");
	case KVAR:      
	  if (uentry_isParam (ue))
	    {
	      return cstring_makeLiteralTemp ("Parameter");
	    }
	  else if (uentry_isExpandedMacro (ue))
	    {
	      return cstring_makeLiteralTemp ("Expanded macro");
	    }
	  else
	    {
	      return cstring_makeLiteralTemp ("Variable");
	    }
	case KFCN:   
	  return cstring_makeLiteralTemp ("Function");
	case KITER: 
	  return cstring_makeLiteralTemp ("Iterator");
	case KENDITER:
	  return cstring_makeLiteralTemp ("Iterator finalizer");
	case KSTRUCTTAG:
	  return cstring_makeLiteralTemp ("Struct tag");
	case KUNIONTAG:
	  return cstring_makeLiteralTemp ("Union tag");
	case KENUMTAG: 
	  return cstring_makeLiteralTemp ("Enum tag");
	case KELIPSMARKER: 
	  return cstring_makeLiteralTemp ("Optional parameters");
	}
    }
  else
    {
      return cstring_makeLiteralTemp ("<Undefined>");
    }

  BADEXIT;
}

/*@observer@*/ cstring
uentry_ekindNameLC (uentry ue)
{
  if (uentry_isValid (ue))
    {
      switch (ue->ukind)
	{
	case KINVALID:
	  return cstring_makeLiteralTemp ("<error: invalid uentry>");
	case KDATATYPE: 
	  return cstring_makeLiteralTemp ("datatype");
	case KENUMCONST:
	  return cstring_makeLiteralTemp ("enum member");
	case KCONST:  
	  return cstring_makeLiteralTemp ("constant");
	case KVAR:      
	  if (uentry_isParam (ue))
	    {
	      return cstring_makeLiteralTemp ("parameter");
	    }
	  else if (uentry_isExpandedMacro (ue))
	    {
	      return cstring_makeLiteralTemp ("expanded macro");
	    }
	  else
	    {
	      return cstring_makeLiteralTemp ("variable");
	    }
	case KFCN:   
	  return cstring_makeLiteralTemp ("function");
	case KITER: 
	  return cstring_makeLiteralTemp ("iterator");
	case KENDITER:
	  return cstring_makeLiteralTemp ("iterator finalizer");
	case KSTRUCTTAG:
	  return cstring_makeLiteralTemp ("struct tag");
	case KUNIONTAG:
	  return cstring_makeLiteralTemp ("union tag");
	case KENUMTAG: 
	  return cstring_makeLiteralTemp ("enum tag");
	case KELIPSMARKER: 
	  return cstring_makeLiteralTemp ("optional parameters");
	}
    }
  else
    {
      return cstring_makeLiteralTemp ("<Undefined>");
    }

  BADEXIT;
}

void uentry_setHasNameError (uentry ue)
{
  llassert (uentry_isValid (ue));

  ue->hasNameError = TRUE;
}

void uentry_checkName (uentry ue)
{
  DPRINTF (("Checking name: %s / %s / %s", uentry_unparse (ue),
	    uentry_observeRealName (ue),
	    bool_unparse (uentry_isVisibleExternally (ue))));
  
  if (uentry_isValid (ue) 
      && !context_inXHFile ()
      && uentry_hasName (ue)
      && !uentry_isElipsisMarker (ue)
      && context_getFlag (FLG_NAMECHECKS)
      && !ue->hasNameError 
      && !uentry_isEndIter (ue)
      && !fileloc_isBuiltin (uentry_whereLast (ue))
      && (uentry_isExpandedMacro (ue) || !uentry_isForward (ue)))
    {      
      DPRINTF (("Here..."));

      if (uentry_isPriv (ue))
	{
	  ; /* any checks here? */
	}
      else if (fileloc_isExternal (uentry_whereDefined (ue)))
	{
	  ; /* no errors for externals */
	}
      else
	{
	  int scope;
	  
	  if (uentry_isExpandedMacro (ue))
	    {
	      scope = globScope;
	    }
	  else
	    {
	      if (uentry_isExpandedMacro (ue))
		{
		  scope = fileScope;
		}
	      else if (uentry_isVariable (ue))
		{
		  sRef sr = uentry_getSref (ue);

		  if (sRef_isValid (sr))
		    {
		      scope = sRef_getScope (sr);
		    }
		  else
		    {
		      scope = fileScope; 
		    }
		}
	      else if (uentry_isFunction (ue)
		       || uentry_isIter (ue)
		       || uentry_isEndIter (ue)
		       || uentry_isConstant (ue))
		{
		  scope = uentry_isStatic (ue) ? fileScope : globScope;
		}
	      else /* datatypes, etc. must be global */
		{
		  scope = globScope;
		}
	      
	      usymtab_checkDistinctName (ue, scope);
	    }
	
	  if (context_getFlag (FLG_CPPNAMES)) 
	    {
	      checkCppName (ue);
	    }

	  if (scope == globScope)
	    {
	      checkExternalName (ue);
	    }
	  else if (scope == fileScope)
	    {
	      checkFileScopeName (ue);
	    }
	  else 
	    {
	      checkLocalName (ue);
	    }

	  checkPrefix (ue);
	  checkAnsiName (ue);
	}
    }
}

/*@exposed@*/ uentry uentry_makeUnrecognized (cstring c, /*@only@*/ fileloc loc)
{
  uentry ue;
  fileloc tloc;

  /*
  ** Can't but unrecognized ids in macros in global scope, because srefs will break! 
  */

  if (!context_inMacro ())
    {
      sRef_setGlobalScopeSafe ();
    }

  ue = uentry_makeVariable (c, ctype_unknown, loc, FALSE);
  uentry_setUsed (ue, loc);		  
  
  tloc = fileloc_createExternal ();
  uentry_setDefined (ue, tloc);
  fileloc_free (tloc);
  uentry_setHasNameError (ue);
  
  if (context_getFlag (FLG_REPEATUNRECOG) || (context_inOldSytleScope() ) )
    {
      uentry_markOwned (ue);
    }
  else
    {
      ue = usymtab_supReturnFileEntry (ue);
    }
  
  if (!context_inMacro ())
    {
      sRef_clearGlobalScopeSafe ();
    }

  return ue;
}

uentry uentry_makeGlobalMarker ()
{
  uentry ue;
  fileloc tloc;

  llassert (sRef_inGlobalScope ());
  
  ue = uentry_makeVariableAux
    (GLOBAL_MARKER_NAME, ctype_unknown, fileloc_undefined, 
     sRef_makeGlobalMarker (),
     FALSE, VKNORMAL);

  tloc = fileloc_createExternal ();
  uentry_setUsed (ue, tloc);		  
  uentry_setDefined (ue, tloc);
  fileloc_free (tloc);
  uentry_setHasNameError (ue);  

  return ue;
}


bool uentry_isGlobalMarker (uentry ue)
{
  return (uentry_isValid (ue)
	  && (cstring_equal (uentry_rawName (ue), GLOBAL_MARKER_NAME)));
}

/* new start modifications */

/* start modifications */
/*
requires: p_e is defined, is a ptr/array variable 
modifies: p_e
effects: sets the state of the variable
*/


void uentry_setPossiblyNullTerminatedState (uentry p_e)  {
  /*@access sRef@*/ /*i523 shouldn't do this! */
  if( uentry_isValid(p_e) ) {
    if( p_e->info != NULL) {
      if( p_e->info->var != NULL) {
         p_e->info->var->bufinfo->bufstate = BB_POSSIBLYNULLTERMINATED;
         p_e->sref->bufinfo.bufstate = BB_POSSIBLYNULLTERMINATED;
         return;
      }
    }
  }
  /*@noaccess sRef@*/

  fprintf(stderr, "uentry:Error in setPossiblyNullTerminatedState\n");
}

/*
requires: p_e is defined, is a ptr/array variable 
modifies: p_e
effects: sets the size of the buffer
*/

void uentry_setNullTerminatedState (uentry p_e)  {
  if( uentry_isValid(p_e) ) {
    if( p_e->info != NULL) {
      if( p_e->info->var != NULL) {
        p_e->info->var->bufinfo->bufstate = BB_NULLTERMINATED;
	/*@access sRef@*/ /*@i523 bad!*/
        p_e->sref->bufinfo.bufstate = BB_NULLTERMINATED;
	/*@noaccess sRef@*/ 
        return;
      }
    }
  }

  fprintf(stderr, "uentry:Error in setNullTerminatedState\n");
}

/*
requires: p_e is defined, is a ptr/array variable 
modifies: p_e
effects: sets the size of the buffer
*/

void uentry_setSize (uentry p_e, int size)  {
  if( uentry_isValid(p_e) ) {
    if( p_e->info != NULL) {
      if( p_e->info->var != NULL) {
        p_e->info->var->bufinfo->size = size;
	/*@access sRef@*/ /*@i523 bad!*/
        p_e->sref->bufinfo.size = size;
	/*@noaccess sRef@*/
        return;
      }
    }
  }

  fprintf(stderr, "uentry:Error in setSize\n");
}


/*
requires: p_e is defined, is a ptr/array variable 
modifies: p_e
effects: sets the length of the buffer
*/

void uentry_setLen (uentry p_e, int len)  {
  if( uentry_isValid(p_e) ) {
    if( p_e->info != NULL) {
      if( p_e->info->var != NULL) {
        p_e->info->var->bufinfo->len = len;
	/*@access sRef@*/ /*@i523 bad!*/
        p_e->sref->bufinfo.len = len;
	/*@noaccess sRef@*/
        return;
      }
    }
  }
  
  fprintf(stderr, "uentry:Error in setLen\n");
}

/*@=type*/

bool uentry_hasMetaStateEnsures (uentry e)
{
  if (uentry_isValid (e) && uentry_isFunction (e))
    {
      return functionConstraint_hasMetaStateConstraint (e->info->fcn->postconditions);
    }
  else
    {
      return FALSE;
    }
}

metaStateConstraintList uentry_getMetaStateEnsures (uentry e)
{
  llassert (uentry_isValid (e) && uentry_isFunction (e));
  return functionConstraint_getMetaStateConstraints (e->info->fcn->postconditions);
}
