/* ;-*-C-*-; ** Splint - annotation-assisted static program checker ** Copyright (C) 1994-2003 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: splint@cs.virginia.edu ** To report a bug: splint-bug@cs.virginia.edu ** For more information: http://www.splint.org */ /* ** ctbase.i ** ** NOTE: This is not a stand-alone source file, but is included in ctype.c. ** (This is necessary because there is no other way in C to have a ** hidden scope, besides at the file level.) */ /*@access cprim*/ abst_typedef /*@null@*/ struct s_ctbase *ctbase; /*@function static bool ctuid_isAnyUserType (sef ctuid p_cid) @*/ /*@-macrofcndecl@*/ /*@-macroparams@*/ # define ctuid_isAnyUserType(cid) \ ((cid) == CT_ABST || (cid) == CT_USER || (cid) == CT_NUMABST) /*@=macrofcndecl@*/ /*@=macroparams@*/ /*:private:*/ typedef struct { ctkind kind; ctbase ctbase; ctype base; /* type I point to (or element of array) */ ctype ptr; /* type of pointer to me */ ctype array; /* type of array of me */ cstring unparse; /* unparse me, if memoized */ } *ctentry ; typedef /*@only@*/ ctentry o_ctentry; typedef struct { int size; int nspace; /*@relnull@*/ /*@only@*/ o_ctentry *entries; /* memoize matches...maybe in context? */ } cttable ; extern bool ctentry_isBogus (/*@sef@*/ ctentry p_c) /*@*/; # define ctentry_isBogus(c) \ ((c)->kind == CTK_INVALID || (c)->kind == CTK_DNE) static cttable cttab = { 0, 0, NULL }; static /*@notnull@*/ /*@only@*/ ctbase ctbase_createAbstract (typeId p_u); static /*@notnull@*/ /*@only@*/ ctbase ctbase_createNumAbstract (typeId p_u); static /*@observer@*/ cstring ctentry_doUnparse (ctentry p_c) /*@modifies p_c@*/; static /*@only@*/ ctentry ctentry_make (ctkind p_ctk, /*@keep@*/ ctbase p_c, ctype p_base, ctype p_ptr, ctype p_array, /*@keep@*/ cstring p_unparse); static /*@only@*/ ctentry ctentry_makeNew (ctkind p_ctk, /*@only@*/ ctbase p_c); static /*@only@*/ cstring ctentry_unparse (ctentry p_c) /*@*/ ; static void cttable_grow (void); static ctype cttable_addDerived (ctkind p_ctk, /*@keep@*/ ctbase p_cnew, ctype p_base); static ctype cttable_addFull (/*@keep@*/ ctentry p_cnew); static bool ctentry_isInteresting (ctentry p_c) /*@*/; static /*@notnull@*/ /*@only@*/ ctbase ctbase_makeFixedArray (ctype p_b, size_t p_size) /*@*/ ; static bool ctbase_isAnytype (/*@notnull@*/ ctbase p_b) /*@*/ ; /* ** These are file-static macros (used in ctype.c). No way to ** declare them as static in C. */ /*@-allmacros@*/ /*@-macrospec@*/ /*@-namechecks@*/ # define ctentry_getBase(c) ((c)->base) # define ctentry_getKind(c) ((c)->kind) # define ctentry_getArray(c) ((c)->array) # define ctentry_getPtr(c) ((c)->ptr) # define ctentry_isArray(c) ((c)->kind == CTK_ARRAY) # define ctentry_isComplex(c) ((c)->kind == CTK_COMPLEX) # define ctentry_isPlain(c) ((c)->kind == CTK_PLAIN) # define ctentry_isPointer(c) ((c)->kind == CTK_PTR) # define ctentry_setArray(c,b) ((c)->array = (b)) # define ctentry_setPtr(c,b) ((c)->ptr = (b)) # define ctbase_fixUser(c) (c = ctbase_realType(c)) /*@=allmacros@*/ /*@=macrospec@*/ /*@=namechecks@*/ static ctype cttable_addComplex (/*@notnull@*/ /*@only@*/ ctbase p_cnew); static /*@observer@*/ ctbase ctype_getCtbase (ctype p_c) /*@*/ ; static ctype ctype_makeConjAux (ctype p_c1, ctype p_c2, bool p_isExplicit) /*@*/ ; static /*@notnull@*/ /*@observer@*/ ctbase ctype_getCtbaseSafe (ctype p_c) /*@*/ ; static /*@observer@*/ ctentry ctype_getCtentry (ctype p_c) /*@*/ ; static /*@observer@*/ /*@notnull@*/ ctbase ctbase_realType (/*@notnull@*/ ctbase p_c) /*@*/ ; static bool ctbase_isPointer (/*@notnull@*/ /*@dependent@*/ ctbase p_c) /*@*/ ; static bool ctbase_isEitherArray (/*@notnull@*/ /*@dependent@*/ ctbase p_c) /*@*/ ; static /*@observer@*/ enumNameList ctbase_elist (ctbase p_c) /*@*/ ; static /*@only@*/ cstring ctbase_unparse (ctbase p_c) /*@*/ ; static /*@only@*/ cstring ctbase_unparseDeep (ctbase p_c) /*@*/ ; static /*@only@*/ /*@notnull@*/ ctbase ctbase_copy (/*@notnull@*/ ctbase p_c) /*@*/ ; static void ctbase_free (/*@only@*/ ctbase p_c); static /*@notnull@*/ /*@only@*/ ctbase ctbase_createPrim (cprim p_p) /*@*/ ; static /*@notnull@*/ /*@only@*/ ctbase ctbase_createBool (void) /*@*/ ; static /*@notnull@*/ /*@observer@*/ ctbase ctbase_getBool (void) /*@*/ ; static /*@notnull@*/ /*@only@*/ ctbase ctbase_createUser (typeId p_u) /*@*/ ; static /*@notnull@*/ /*@only@*/ ctbase ctbase_createStruct (/*@only@*/ cstring p_n, /*@only@*/ uentryList p_f); static /*@notnull@*/ /*@only@*/ ctbase ctbase_createUnion (/*@keep@*/ cstring p_n, /*@only@*/ uentryList p_f); static /*@notnull@*/ /*@only@*/ ctbase ctbase_createEnum (/*@keep@*/ cstring p_etag, /*@keep@*/ enumNameList p_emembers); static /*@notnull@*/ /*@only@*/ ctbase ctbase_createUnknown (void); static bool ctbase_match (ctbase p_c1, ctbase p_c2) /*@modifies nothing@*/; static bool ctbase_matchDef (ctbase p_c1, ctbase p_c2) /*@modifies nothing@*/; static bool ctbase_genMatch (ctbase p_c1, ctbase p_c2, bool p_force, bool p_arg, bool p_def, bool p_deep); static bool ctbase_isAbstract (/*@notnull@*/ ctbase p_c) /*@*/ ; static /*@notnull@*/ /*@only@*/ ctbase ctbase_makePointer (ctype p_b) /*@*/ ; static /*@notnull@*/ /*@only@*/ ctbase ctbase_makeArray (ctype p_b) /*@*/ ; static /*@notnull@*/ ctype ctbase_makeFunction (ctype p_b, /*@only@*/ uentryList p_p) /*@*/ ; static /*@notnull@*/ /*@observer@*/ ctbase ctbase_realFunction (/*@notnull@*/ /*@dependent@*/ ctbase p_c) /*@*/ ; static ctype ctbase_baseArrayPtr (/*@notnull@*/ ctbase p_c) /*@*/ ; static ctype ctbase_baseFunction (/*@notnull@*/ ctbase p_c) /*@*/ ; static /*@observer@*/ uentryList ctbase_argsFunction (/*@notnull@*/ ctbase p_c) /*@*/ ; static /*@observer@*/ uentryList ctbase_getuentryList (/*@notnull@*/ ctbase p_c) /*@*/ ; static ctype ctbase_newBase (ctype p_c, ctype p_p) /*@*/ ; static ctype ctbase_newBaseExpFcn (ctype p_c, ctype p_p) /*@*/ ; static bool ctbase_isFixedArray (/*@notnull@*/ ctbase p_c) /*@*/ ; /*@-macroundef@*/ extern int cttable_lastIndex(); # define cttable_lastIndex() (cttab.size - 1) /*@=macroundef@*/ typedef struct { ctype rval; /*@only@*/ uentryList params; } *cfcn; typedef struct { cstring name; uentryList fields; } *tsu; typedef struct { ctype a; ctype b; bool isExplicit; } *tconj; typedef struct { cstring tag; enumNameList members; } *tenum; typedef struct { ctype base; size_t size; } *tfixed; typedef union { cprim prim; /* primitive */ typeId tid; /* abstract, user */ ctype base; /* ptr, array */ cfcn fcn; /* function */ tsu su; /* struct union */ tenum cenum; /* enum */ tconj conj; /* conj */ tfixed farray; /* fixed array */ } uconts; struct s_ctbase { ctuid type; uconts contents; } ; static /*@falsenull@*/ bool ctbase_isUA (ctbase p_c) /*@*/ ; static bool ctbase_isBaseUA(ctbase p_c) /*@*/ ; static typeId ctbase_typeBaseUid(ctbase p_c) /*@*/ ; static bool ctbase_isKind (/*@notnull@*/ ctbase p_c, ctuid p_kind) /*@*/ ; static bool ctbase_isKind2 (/*@notnull@*/ ctbase p_c, ctuid p_kind1, ctuid p_kind2) /*@*/ ; static /*@only@*/ /*@notnull@*/ ctbase ctbase_getBaseType (/*@notnull@*/ ctbase p_c) /*@*/ ; static /*@falsenull@*/ bool ctbase_isFunction(ctbase p_c) /*@*/ ; /*@constant null ctbase ctbase_undefined; @*/ # define ctbase_undefined ((ctbase)0) static /*@owned@*/ ctbase ctbase_bool = ctbase_undefined; static /*@owned@*/ ctbase ctbase_unknown = ctbase_undefined; static /*@falsenull@*/ bool ctbase_isDefined (ctbase c) /*@*/ { return ((c) != ctbase_undefined); } static /*@truenull@*/ bool ctbase_isUndefined (ctbase c) { return ((c) == ctbase_undefined); } static ctkind ctype_getCtKind (ctype c) { ctentry ce = ctype_getCtentry (c); return ctentry_getKind (ce); } static bool ctbase_isUser (ctbase c) { if (ctbase_isDefined (c)) { return (ctbase_isKind (c, CT_USER)); } else { return FALSE; } } static bool ctbase_isEnum (ctbase c) { if (ctbase_isDefined (c)) { return (ctbase_isKind (c, CT_ENUM)); } else { return FALSE; } } static bool ctbase_isExpFcn (ctbase c) { if (ctbase_isDefined (c)) { return (c->type == CT_EXPFCN); } else { return FALSE; } } static /*@falsenull@*/ bool ctbase_isConj (ctbase c) { if (ctbase_isDefined (c)) { return (c->type == CT_CONJ); } else { return FALSE; } } static bool ctuid_isAP (ctuid c) /*@*/ { return (c == CT_ARRAY || c == CT_PTR); } static typeId ctbase_typeId (ctbase p_c); static /*@only@*/ cstring ctbase_dump (ctbase p_c); static /*@only@*/ ctbase ctbase_undump (char **p_c) /*@requires maxRead(*p_c) >= 2 @*/; static int ctbase_compare (ctbase p_c1, ctbase p_c2, bool p_strict); static bool ctbase_matchArg (ctbase p_c1, ctbase p_c2); static /*@notnull@*/ /*@only@*/ ctbase ctbase_makeConj (ctype p_c1, ctype p_c2, bool p_isExplicit) /*@*/ ; static ctype ctbase_getConjA (/*@notnull@*/ ctbase p_c) /*@*/ ; static ctype ctbase_getConjB (/*@notnull@*/ ctbase p_c) /*@*/ ; static bool ctbase_isExplicitConj (/*@notnull@*/ ctbase p_c) /*@*/ ; static bool ctbase_forceMatch (ctbase p_c1, ctbase p_c2) /*@modifies p_c1, p_c2@*/ ; static /*@notnull@*/ /*@only@*/ ctbase ctbase_expectFunction (ctype p_c); static bool ctbase_isVoidPointer(/*@notnull@*/ /*@dependent@*/ ctbase p_c) /*@*/ ; static bool ctbase_isUnion (/*@notnull@*/ /*@temp@*/ ctbase p_c) /*@*/ ; static bool ctbase_isStruct (/*@notnull@*/ /*@temp@*/ ctbase p_c) /*@*/ ; static /*@observer@*/ cstring ctbase_enumTag (/*@notnull@*/ ctbase p_ct) /*@*/ ; static /*@only@*/ cstring ctbase_unparseNotypes (ctbase p_c) /*@*/ ; static /*@out@*/ /*@notnull@*/ /*@only@*/ ctbase ctbase_new (void) /*@*/ ; static int nctbases = 0; static /*@notnull@*/ /*@only@*/ ctbase ctbase_makeLiveFunction (ctype p_b, /*@only@*/ uentryList p_p); static bool ctbase_isUnnamedSU (ctbase c) { return (ctbase_isDefined (c) && (ctbase_isStruct (c) || ctbase_isUnion (c)) && isFakeTag (c->contents.su->name)); } static /*@observer@*/ ctbase ctbase_realType (ctbase c) { if (ctbase_isUA (c)) { typeId uid = ctbase_typeId (c); if (usymtab_isBoolType (uid)) { return ctbase_getBool (); } else { ctbase ret = ctype_getCtbase (uentry_getRealType (usymtab_getTypeEntry (ctbase_typeId (c)))); llassert (ret != ctbase_undefined); return ret; } } else { return c; } } static bool ctbase_isVoidPointer (/*@dependent@*/ /*@notnull@*/ ctbase c) { ctbase r = ctbase_realType (c); return (ctbase_isKind (r, CT_PTR) && ctype_isVoid (r->contents.base)); } static bool ctbase_isPointer (/*@notnull@*/ /*@dependent@*/ ctbase c) { ctbase r = ctbase_realType (c); return (ctbase_isKind (r, CT_PTR)); } static bool ctbase_isEitherArray (/*@notnull@*/ ctbase c) { ctbase r = ctbase_realType (c); return (ctbase_isKind (r, CT_ARRAY) || ctbase_isKind (r, CT_FIXEDARRAY)); } static bool ctbase_isFixedArray (/*@notnull@*/ ctbase c) { ctbase r = ctbase_realType (c); return (ctbase_isKind (r, CT_FIXEDARRAY)); } static bool ctbase_isStruct (/*@notnull@*/ ctbase c) { ctbase r = ctbase_realType (c); return (ctbase_isKind (r, CT_STRUCT)); } static bool ctbase_isUnion (/*@notnull@*/ ctbase c) { ctbase r = ctbase_realType (c); return (ctbase_isKind (r, CT_UNION)); } /* ** clean this up -> typeTable should store ctype */ static typeId ctbase_typeBaseUid (ctbase c) { ctuid ct; if (ctbase_isDefined (c)) { ct = c->type; if (ctuid_isAP (ct)) { return ctbase_typeBaseUid (ctype_getCtbase (c->contents.base)); } else if (ct == CT_USER || ct == CT_ABST || ct == CT_NUMABST) { return c->contents.tid; } else if (ct == CT_FIXEDARRAY) { return ctbase_typeBaseUid (ctype_getCtbase (c->contents.farray->base)); } else { llcontbuglit ("ctbase_typeBaseUid: bad call"); return typeId_invalid; } } return typeId_invalid; } static bool ctbase_isBaseUA (ctbase c) { ctuid ct; if (ctbase_isDefined (c)) { ct = c->type; if (ctuid_isAP (ct)) { return ctbase_isBaseUA (ctype_getCtbase (c->contents.base)); } else if (ct == CT_FIXEDARRAY) { return ctbase_isBaseUA (ctype_getCtbase (c->contents.farray->base)); } else return (ct == CT_USER || ct == CT_ABST || ct == CT_NUMABST); } return FALSE; } static typeId ctbase_typeId (ctbase c) { if (ctbase_isUA (c)) { return c->contents.tid; } else { if (ctbase_isConj (c)) { if (ctype_isUA (ctbase_getConjA (c))) { return ctbase_typeId (ctype_getCtbase (ctbase_getConjA (c))); } else if (ctype_isUA (ctbase_getConjB (c))) { return ctbase_typeId (ctype_getCtbase (ctbase_getConjB (c))); } else { llcontbug (message ("ctbase_typeId: bad call: %q", ctbase_unparse (c))); return typeId_invalid; } } else { llcontbug (message ("ctbase_typeId: bad call: %q", ctbase_unparse (c))); return typeId_invalid; } } } static /*@only@*/ cstring ctbase_unparse (ctbase c) { if (ctbase_isUndefined (c)) { return cstring_makeLiteral ("<>"); } switch (c->type) { case CT_UNKNOWN: return cstring_makeLiteral ("?"); case CT_BOOL: return cstring_copy (context_printBoolName ()); case CT_PRIM: return (cprim_unparse (c->contents.prim)); case CT_USER: case CT_ABST: case CT_NUMABST: return (usymtab_getTypeEntryName (c->contents.tid)); case CT_EXPFCN: return (message ("", c->contents.base)); case CT_PTR: /* no spaces for multiple pointers */ if (ctype_isPointer (c->contents.base)) { return (cstring_appendChar (cstring_copy (ctype_unparse (c->contents.base)), '*')); } else { return (message ("%t *", c->contents.base)); } case CT_FIXEDARRAY: /* ** C prints out array declarations backwards, if ** base is an array need to print out in reverse order. */ if (ctype_isArray (c->contents.farray->base)) { ctype base = c->contents.farray->base; cstring res = message ("[%d]", (int) c->contents.farray->size); while (ctype_isArray (base)) { if (ctype_isFixedArray (base)) { res = message ("%q[%d]", res, (int) ctype_getArraySize (base)); } else { res = message ("%q[]", res); } base = ctype_baseArrayPtr (base); } return (message ("%t %q", base, res)); } else { return (message ("%t [%d]", c->contents.farray->base, (int) c->contents.farray->size)); } case CT_ARRAY: if (ctype_isArray (c->contents.base)) { ctype base = c->contents.base; cstring res = cstring_makeLiteral ("[]"); while (ctype_isArray (base)) { if (ctype_isFixedArray (base)) { res = message ("%q[%d]", res, (int) ctype_getArraySize (base)); } else { res = message ("%q[]", res); } base = ctype_baseArrayPtr (base); } return (message ("%t %q", base, res)); } else { return (message ("%t []", c->contents.base)); } case CT_FCN: return (message ("[function (%q) returns %t]", uentryList_unparseParams (c->contents.fcn->params), c->contents.fcn->rval)); case CT_STRUCT: if (cstring_isDefined (c->contents.su->name) && !cstring_isEmpty (c->contents.su->name) && !isFakeTag (c->contents.su->name)) { return (message ("struct %s", c->contents.su->name)); } else { return (message ("struct { %q }", uentryList_unparseAbbrev (c->contents.su->fields))); } case CT_UNION: if (cstring_isDefined (c->contents.su->name) && !cstring_isEmpty (c->contents.su->name) && !isFakeTag (c->contents.su->name)) { return (message ("union %s", c->contents.su->name)); } else { return (message ("union { %q }", uentryList_unparseAbbrev (c->contents.su->fields))); } case CT_ENUM: if (isFakeTag (c->contents.cenum->tag)) { return (message ("enum { %q }", enumNameList_unparseBrief (c->contents.cenum->members))); } else { return (message ("enum %s { %q }", c->contents.cenum->tag, enumNameList_unparseBrief (c->contents.cenum->members))); } case CT_CONJ: if (ctbase_isAnytype (c)) { return (cstring_makeLiteral ("")); } else if (c->contents.conj->isExplicit || context_getFlag (FLG_SHOWALLCONJS)) { if (!ctype_isSimple (c->contents.conj->a) || !ctype_isSimple (c->contents.conj->b)) { return (message ("<%t> | <%t>", c->contents.conj->a, c->contents.conj->b)); } else { return (message ("%t | %t", c->contents.conj->a, c->contents.conj->b)); } } else { return (cstring_copy (ctype_unparse (c->contents.conj->a))); } BADDEFAULT; } BADEXIT; } static /*@only@*/ cstring ctbase_unparseDeep (ctbase c) { if (ctbase_isUndefined (c)) { return cstring_makeLiteral ("<>"); } switch (c->type) { case CT_UNKNOWN: return cstring_makeLiteral ("?"); case CT_BOOL: return cstring_copy (context_printBoolName ()); case CT_PRIM: return (cprim_unparse (c->contents.prim)); case CT_ENUM: if (cstring_isNonEmpty (c->contents.cenum->tag)) { return (message ("enum %s { %q }", c->contents.cenum->tag, enumNameList_unparse (c->contents.cenum->members))); } else { return (message ("enum { %q }", enumNameList_unparse (c->contents.cenum->members))); } case CT_USER: case CT_ABST: case CT_NUMABST: return (usymtab_getTypeEntryName (c->contents.tid)); case CT_EXPFCN: return (message ("", c->contents.base)); case CT_PTR: return (message ("%t *", c->contents.base)); case CT_FIXEDARRAY: return (message ("%t [%d]", c->contents.farray->base, (int) c->contents.farray->size)); case CT_ARRAY: return (message ("%t []", c->contents.base)); case CT_FCN: return (message ("[function (%q) returns %t]", uentryList_unparse (c->contents.fcn->params), c->contents.fcn->rval)); case CT_STRUCT: return (message ("struct %s { ... } ", c->contents.su->name)); case CT_UNION: return (message ("union %s { ... }", c->contents.su->name)); case CT_CONJ: if (ctbase_isAnytype (c)) { return (cstring_makeLiteral ("")); } else { return (message ("%t", c->contents.conj->a)); } BADDEFAULT; } BADEXIT; } static /*@only@*/ cstring ctbase_unparseNotypes (ctbase c) { llassert (ctbase_isDefined (c)); switch (c->type) { case CT_UNKNOWN: return cstring_makeLiteral ("?"); case CT_BOOL: return cstring_copy (context_printBoolName ()); case CT_PRIM: return (cprim_unparse (c->contents.prim)); case CT_ENUM: if (typeId_isInvalid (c->contents.tid)) { return cstring_makeLiteral ("enum"); } else { return (message ("T#%d", c->contents.tid)); } case CT_USER: return (message ("uT#%d", c->contents.tid)); case CT_ABST: return (message ("aT#%d", c->contents.tid)); case CT_NUMABST: return (message ("nT#%d", c->contents.tid)); case CT_EXPFCN: return (message ("", ctbase_unparseNotypes (ctype_getCtbase (c->contents.base)))); case CT_PTR: return (message ("%q *", ctbase_unparseNotypes (ctype_getCtbase (c->contents.base)))); case CT_ARRAY: return (message ("%q []", ctbase_unparseNotypes (ctype_getCtbase (c->contents.base)))); case CT_FCN: return (message ("[function (%d) returns %q]", uentryList_size (c->contents.fcn->params), ctbase_unparseNotypes (ctype_getCtbase (c->contents.fcn->rval)))); case CT_STRUCT: return (message ("struct %s", c->contents.su->name)); case CT_UNION: return (message ("union %s", c->contents.su->name)); case CT_ENUMLIST: return (message ("[enumlist]")); case CT_CONJ: if (ctbase_isAnytype (c)) { return (cstring_makeLiteral ("")); } else { return (message ("%q/%q", ctbase_unparseNotypes (ctype_getCtbase (c->contents.conj->a)), ctbase_unparseNotypes (ctype_getCtbase (c->contents.conj->b)))); } BADDEFAULT; } BADEXIT; } static /*@only@*/ cstring ctbase_unparseDeclaration (ctbase c, /*@only@*/ cstring name) /*@*/ { if (ctbase_isUndefined (c)) { return name; } switch (c->type) { case CT_UNKNOWN: return (message ("? %q", name)); case CT_BOOL: return (message ("%s %q", context_printBoolName (), name)); case CT_PRIM: return (message ("%q %q", cprim_unparse (c->contents.prim), name)); case CT_USER: case CT_ABST: case CT_NUMABST: return (message ("%q %q", usymtab_getTypeEntryName (c->contents.tid), name)); case CT_EXPFCN: llcontbuglit ("ctbase_unparseDeclaration: expfcn"); return name; case CT_PTR: if (ctype_isFunction (c->contents.base)) { return ctbase_unparseDeclaration (ctype_getCtbase (c->contents.base), name); } else { cstring s = cstring_prependChar ('*', name); cstring ret = ctbase_unparseDeclaration (ctype_getCtbase (c->contents.base), s); cstring_free (name); return (ret); } case CT_FIXEDARRAY: return (message ("%q[%d]", ctbase_unparseDeclaration (ctype_getCtbase (c->contents.farray->base), name), (int) c->contents.farray->size)); case CT_ARRAY: return (message ("%q[]", ctbase_unparseDeclaration (ctype_getCtbase (c->contents.base), name))); case CT_FCN: { cstring s = message ("%q(%q)", name, uentryList_unparseParams (c->contents.fcn->params)); return (ctbase_unparseDeclaration (ctype_getCtbase (c->contents.fcn->rval), s)); } case CT_STRUCT: if (cstring_isDefined (c->contents.su->name) && !cstring_isEmpty (c->contents.su->name) && !isFakeTag (c->contents.su->name)) { return (message ("struct %s %q", c->contents.su->name, name)); } else { return (message ("struct { %q } %q", uentryList_unparseAbbrev (c->contents.su->fields), name)); } case CT_UNION: if (cstring_isDefined (c->contents.su->name) && !cstring_isEmpty (c->contents.su->name) && !isFakeTag (c->contents.su->name)) { return (message ("union %s %q", c->contents.su->name, name)); } else { return (message ("union { %q } %q", uentryList_unparseAbbrev (c->contents.su->fields), name)); } case CT_ENUM: if (isFakeTag (c->contents.cenum->tag)) { return (message ("enum { %q } %q", enumNameList_unparseBrief (c->contents.cenum->members), name)); } else { return (message ("enum %s { %q } %q", c->contents.cenum->tag, enumNameList_unparseBrief (c->contents.cenum->members), name)); } case CT_CONJ: if (ctbase_isAnytype (c)) { return (message (" %q", name)); } else if (c->contents.conj->isExplicit || context_getFlag (FLG_SHOWALLCONJS)) { if (!ctype_isSimple (c->contents.conj->a) || !ctype_isSimple (c->contents.conj->b)) { cstring name1 = cstring_copy (name); return (message ("<%q> | <%q>", ctbase_unparseDeclaration (ctype_getCtbase (c->contents.conj->a), name1), ctbase_unparseDeclaration (ctype_getCtbase (c->contents.conj->b), name))); } else { cstring s1 = ctbase_unparseDeclaration (ctype_getCtbase (c->contents.conj->a), cstring_copy (name)); return (message ("%q | %q", s1, ctbase_unparseDeclaration (ctype_getCtbase (c->contents.conj->b), name))); } } else { cstring_free (name); return (cstring_copy (ctype_unparse (c->contents.conj->a))); } BADDEFAULT; } BADEXIT; } static ctbase ctbase_undump (d_char *c) /*@requires maxRead(*c) >= 2 @*/ { ctbase res; char p = **c; (*c)++; switch (p) { case '?': return (ctbase_undefined); case 'u': return (ctbase_createUnknown ()); case 'b': return (ctbase_createBool ()); case 'p': res = ctbase_createPrim (cprim_fromInt (reader_getInt (c))); reader_checkChar (c, '|'); return res; case 's': res = ctbase_createUser (typeId_fromInt (reader_getInt (c))); reader_checkChar (c, '|'); return res; case 'a': res = ctbase_createAbstract (typeId_fromInt (reader_getInt (c))); reader_checkChar (c, '|'); return res; case 'n': res = ctbase_createNumAbstract (typeId_fromInt (reader_getInt (c))); reader_checkChar (c, '|'); return res; case 't': res = ctbase_makePointer (ctype_undump (c)); reader_checkChar (c, '|'); return res; case 'y': res = ctbase_makeArray (ctype_undump (c)); reader_checkChar (c, '|'); return res; case 'F': { ctype ct = ctype_undump (c); size_t size; reader_checkChar (c, '/'); size = size_fromInt (reader_getInt (c)); reader_checkChar (c, '|'); return (ctbase_makeFixedArray (ct, size)); } case 'f': { ctype ct; char *lp = strchr (*c, '('); llassertfatal (lp != NULL); *lp = '\0'; ct = ctype_undump (c); *c = lp + 1; return (ctbase_makeLiveFunction (ct, uentryList_undump (c))); } case 'S': { uentryList fields; ctbase ctb; char *sname; char *lc = strchr (*c, '{'); llassert (lc != NULL); *lc = '\0'; sname = mstring_copy (*c); *c = lc + 1; if (*sname == '!') { unsigned int i; i = (unsigned) atoi (sname + 1); setTagNo (i); } fields = uentryList_undumpFields (c, g_currentloc); ctb = ctbase_createStruct (cstring_fromCharsO (sname), fields); return ctb; } case 'U': { char *sname; char *lc = strchr (*c, '{'); llassert (lc != NULL); *lc = '\0'; sname = mstring_copy (*c); llassert (sname != NULL); *c = lc + 1; if (*sname == '!') { unsigned int i; i = (unsigned) atoi (sname + 1); setTagNo (i); } return (ctbase_createUnion (cstring_fromCharsO (sname), uentryList_undumpFields (c, g_currentloc))); } case 'e': { ctbase ret; char *sname; char *lc = strchr (*c, '{'); llassert (lc != NULL); *lc = '\0'; sname = mstring_copy (*c); *c = lc + 1; if (*sname == '!') { unsigned int i; i = (unsigned) atoi (sname + 1); setTagNo (i); } ret = ctbase_createEnum (cstring_fromCharsO (sname), enumNameList_undump (c)); return ret; } case 'C': { bool isExplicit; ctype c1, c2; isExplicit = bool_fromInt (reader_getInt (c)); reader_checkChar (c, '.'); c1 = ctype_undump (c); reader_checkChar (c, '/'); c2 = ctype_undump (c); reader_checkChar (c, '|'); return (ctbase_makeConj (c1, c2, isExplicit)); } default: (*c)--; llerror (FLG_SYNTAX, message ("Bad Library line (type): %s", cstring_fromChars (*c))); /*drl bee: pbr*/ while (**c != '\0') { (*c)++; } return ctbase_createUnknown (); } } /* first letter of c encodes type: */ /* u unknown */ /* b bool */ /* p prim */ /* e enum */ /* l enumList */ /* s uSer */ /* a abstract */ /* t poinTer */ /* y arraY */ /* F Fixed array */ /* f function */ /* S structure */ /* U union */ /* C conj */ static /*@only@*/ cstring ctbase_dump (ctbase c) { if (!ctbase_isDefined (c)) { return cstring_makeLiteral ("?"); } switch (c->type) { case CT_UNKNOWN: return cstring_makeLiteral ("u"); case CT_BOOL: return cstring_makeLiteral ("b"); case CT_PRIM: return (message ("p%d|", c->contents.prim)); case CT_USER: return (message ("s%d|", usymtab_convertTypeId (c->contents.tid))); case CT_ABST: return (message ("a%d|", usymtab_convertTypeId (c->contents.tid))); case CT_NUMABST: return (message ("n%d|", usymtab_convertTypeId (c->contents.tid))); case CT_PTR: return (message ("t%q|", ctype_dump (c->contents.base))); case CT_ARRAY: return (message ("y%q|", ctype_dump (c->contents.base))); case CT_FIXEDARRAY: return (message ("F%q/%d|", ctype_dump (c->contents.farray->base), (int) c->contents.farray->size)); case CT_FCN: DPRINTF (("Dump function: %s", ctbase_unparse (c))); return (message ("f%q (%q)", ctype_dump (c->contents.fcn->rval), uentryList_dumpParams (c->contents.fcn->params))); case CT_STRUCT: return (message ("S%s{%q}", c->contents.su->name, uentryList_dumpFields (c->contents.su->fields))); case CT_UNION: return (message ("U%s{%q}", c->contents.su->name, uentryList_dumpFields (c->contents.su->fields))); case CT_ENUM: { cstring s; if (cstring_isNonEmpty (c->contents.cenum->tag)) { s = message ("e%s{%q}", c->contents.cenum->tag, enumNameList_dump (c->contents.cenum->members)); } else { s = message ("e{%q}", enumNameList_dump (c->contents.cenum->members)); } return (s); } case CT_CONJ: return (message ("C%d.%q/%q|", bool_toInt (c->contents.conj->isExplicit), ctype_dump (c->contents.conj->a), ctype_dump (c->contents.conj->b))); case CT_EXPFCN: /* should clean them up! */ return (cstring_makeLiteral ("?")); case CT_ENUMLIST: llcontbug (message ("Cannot dump: %q", ctbase_unparse (c))); return (message ("u")); BADDEFAULT; } BADEXIT; } static /*@only@*/ ctbase ctbase_copy (/*@notnull@*/ ctbase c) { switch (c->type) { case CT_UNKNOWN: return (ctbase_createUnknown ()); case CT_BOOL: return (ctbase_createBool ()); case CT_ENUM: return (ctbase_createEnum (cstring_copy (c->contents.cenum->tag), enumNameList_copy (c->contents.cenum->members))); case CT_PRIM: return (ctbase_createPrim (c->contents.prim)); case CT_USER: return (ctbase_createUser (c->contents.tid)); case CT_ABST: return (ctbase_createAbstract (c->contents.tid)); case CT_NUMABST: return (ctbase_createNumAbstract (c->contents.tid)); case CT_EXPFCN: return (ctbase_expectFunction (c->contents.base)); case CT_PTR: return (ctbase_makePointer (c->contents.base)); case CT_ARRAY: return (ctbase_makeArray (c->contents.base)); case CT_FCN: return (ctbase_makeLiveFunction (c->contents.fcn->rval, uentryList_copy (c->contents.fcn->params))); case CT_STRUCT: return (ctbase_createStruct (cstring_copy (c->contents.su->name), uentryList_copy (c->contents.su->fields))); case CT_UNION: return (ctbase_createUnion (cstring_copy (c->contents.su->name), uentryList_copy (c->contents.su->fields))); case CT_CONJ: /*@i@*/ return (c); /* not a real copy for conj's */ default: llbug (message ("ctbase_copy: %q", ctbase_unparse (c))); } BADEXIT; } static enumNameList ctbase_elist (ctbase c) { llassert (ctbase_isDefined (c)); llassert (c->type == CT_ENUM); return (c->contents.cenum->members); } static void ctbase_free (/*@only@*/ ctbase c) { if (c == ctbase_bool || c == ctbase_unknown) { /*@-mustfree@*/ return; /*@=mustfree@*/ } --nctbases; if (ctbase_isDefined (c)) { switch (c->type) { case CT_UNKNOWN: sfree (c); break; case CT_PRIM: sfree (c); break; case CT_ENUM: sfree (c); break; case CT_ENUMLIST: /* sfree list? */ sfree (c); break; case CT_USER: case CT_ABST: case CT_NUMABST: sfree (c); break; case CT_PTR: case CT_ARRAY: sfree (c); break; case CT_FCN: /* Cannot free params: uentryList_free (c->contents.fcn->params); */ uentryList_freeShallow (c->contents.fcn->params); sfree (c); break; case CT_STRUCT: case CT_UNION: cstring_free (c->contents.su->name); uentryList_free (c->contents.su->fields); sfree (c); break; case CT_CONJ: /* Don't bree conj's, */ break; default: sfree (c); break; } } } /* ** c should be * */ static /*@only@*/ ctbase ctbase_expectFunction (ctype c) { ctbase f = ctbase_new (); f->type = CT_EXPFCN; f->contents.base = c; return (f); } static bool ctbase_isExpectFunction (/*@notnull@*/ ctbase ct) /*@*/ { return (ct->type == CT_EXPFCN); } static ctype ctbase_getExpectFunction (/*@notnull@*/ ctbase ct) { llassert (ctbase_isExpectFunction (ct)); return ct->contents.base; } static bool ctbase_genMatch (ctbase c1, ctbase c2, bool force, bool arg, bool def, bool deep) { ctuid c1tid, c2tid; /* undefined types never match */ if (ctbase_isUndefined (c1) || ctbase_isUndefined (c2)) return FALSE; /* abstract types match user types of same name */ c1 = ctbase_realType (c1); c2 = ctbase_realType (c2); DPRINTF (("Matching: %s / %s", ctbase_unparse (c1), ctbase_unparse (c2))); c1tid = c1->type; c2tid = c2->type; if (c1tid == CT_CONJ) { return (ctbase_genMatch (ctype_getCtbase (c1->contents.conj->a), c2, force, arg, def, deep) || ctbase_genMatch (ctype_getCtbase (c1->contents.conj->b), c2, force, arg, def, deep)); } if (c2tid == CT_CONJ) { return (ctbase_genMatch (c1, ctype_getCtbase (c2->contents.conj->a), force, arg, def, deep) || ctbase_genMatch (c1, ctype_getCtbase (c2->contents.conj->b), force, arg, def, deep)); } /* ** if the types don't match, there are some special cases... */ if (c1tid != c2tid) { /* unknowns match anything */ if (c1tid == CT_UNKNOWN || c2tid == CT_UNKNOWN) { return TRUE; } if (c1tid == CT_FIXEDARRAY && (c2tid == CT_ARRAY || (!def && c2tid == CT_PTR))) { if (ctype_isVoid (c2->contents.base)) { return (context_getFlag (FLG_ABSTVOIDP) || (!(ctype_isRealAbstract (c1->contents.farray->base)) && !(ctype_isRealAbstract (c2->contents.base)))); } return (ctbase_genMatch (ctype_getCtbase (c1->contents.farray->base), ctype_getCtbase (c2->contents.base), force, arg, def, deep)); } if (c2tid == CT_FIXEDARRAY && (c1tid == CT_ARRAY || (!def && c1tid == CT_PTR))) { if (ctype_isVoid (c1->contents.base)) { return (context_getFlag (FLG_ABSTVOIDP) || (!(ctype_isRealAbstract (c2->contents.farray->base)) && !(ctype_isRealAbstract (c1->contents.base)))); } return (ctbase_genMatch (ctype_getCtbase (c1->contents.base), ctype_getCtbase (c2->contents.farray->base), force, arg, def, deep)); } /* evs 2000-07-25: Bool's may match user/abstract types */ if ((c1tid == CT_BOOL && (c2tid == CT_PRIM && cprim_isInt (c2->contents.prim))) || (c2tid == CT_BOOL && (c1tid == CT_PRIM && cprim_isInt (c1->contents.prim)))) { return (context_msgBoolInt ()); } if ((c1tid == CT_BOOL && (ctuid_isAnyUserType (c2tid)))) { ctype t2c = c2->contents.base; return (ctype_isBool (t2c)); } if ((c2tid == CT_BOOL && (ctuid_isAnyUserType (c1tid)))) { ctype t1c = c1->contents.base; return (ctype_isBool (t1c)); } if ((c1tid == CT_ENUM && (c2tid == CT_PRIM && cprim_isInt (c2->contents.prim))) || (c2tid == CT_ENUM && (c1tid == CT_PRIM && cprim_isInt (c1->contents.prim)))) { return (context_msgEnumInt ()); } /* ** arrays and pointers...yuk! ** ** Considered equivalent except in definitions. ** (e.g., function parameters are equivalent) ** */ if (!def) { if (ctuid_isAP (c1tid) && ctuid_isAP (c2tid)) { c2tid = c1tid; } } /* ** Function pointers can be removed. ** ** [function ..] is equivalent to [function ..] * */ if (c1tid == CT_PTR && c2tid == CT_FCN) { if (ctype_isFunction (ctype_realType (c1->contents.base))) { c1 = ctbase_realType (ctype_getCtbaseSafe (c1->contents.base)); c1tid = c1->type; } } if (c2tid == CT_PTR && c1tid == CT_FCN) { if (ctype_isFunction (ctype_realType (c2->contents.base))) { c2 = ctbase_realType (ctype_getCtbaseSafe (c2->contents.base)); c2tid = c2->type; } } /* ** we allow forward declarations to structures like, ** ** typedef struct _t *t; ** ** to allow, ** struct _t * to match t */ if (context_getFlag (FLG_FORWARDDECL)) { if (ctuid_isAnyUserType (c1tid)) { if (ctuid_isAP (c2tid)) { ctype ts = c2->contents.base; if (ctype_isUA (ts)) { typeId ttid = ctype_typeId (ts); typeId ctid = c1->contents.tid ; if (usymtab_matchForwardStruct (ctid, ttid)) { return TRUE; } } } } if (ctuid_isAnyUserType (c2tid)) { if (ctuid_isAP (c1tid)) { ctype ts = c1->contents.base; if (ctype_isUA (ts)) { typeId ttid = ctype_typeId (ts); typeId ctid = c2->contents.tid ; if (usymtab_matchForwardStruct (ctid, ttid)) { return TRUE; } } } } } } if (c1tid != c2tid) return FALSE; switch (c1tid) { case CT_UNKNOWN: return (TRUE); case CT_PRIM: if (deep) { return (cprim_closeEnoughDeep (c1->contents.prim, c2->contents.prim)); } else { return (cprim_closeEnough (c1->contents.prim, c2->contents.prim)); } case CT_BOOL: return (TRUE); case CT_ABST: case CT_NUMABST: case CT_USER: return (typeId_equal (c1->contents.tid, c2->contents.tid)); case CT_ENUM: return (cstring_equal (c1->contents.cenum->tag, c2->contents.cenum->tag)); case CT_PTR: if (ctype_isVoid (c1->contents.base) || (ctype_isVoid (c2->contents.base))) { if (ctype_isFunction (ctype_realType (c1->contents.base)) || ctype_isFunction (ctype_realType (c2->contents.base))) { return (!context_getFlag (FLG_CASTFCNPTR)); } else { return (context_getFlag (FLG_ABSTVOIDP) || (!(ctype_isRealAbstract (c1->contents.base)) && !(ctype_isRealAbstract (c2->contents.base)))); } } else { /* Only allow one implicit function pointer. */ if (!bool_equal (ctype_isRealPointer (c1->contents.base), ctype_isRealPointer (c2->contents.base)) && (ctype_isRealFunction (c1->contents.base) || ctype_isRealFunction (c2->contents.base))) { return FALSE; } return (ctype_genMatch (c1->contents.base, c2->contents.base, force, arg, def, TRUE)); } case CT_FIXEDARRAY: if (ctype_isVoid (c1->contents.farray->base) || ctype_isVoid (c2->contents.farray->base)) return TRUE; return (ctype_genMatch (c1->contents.farray->base, c2->contents.farray->base, force, arg, def, deep)); case CT_ARRAY: if (ctype_isVoid (c1->contents.base) || ctype_isVoid (c2->contents.base)) return TRUE; return (ctype_genMatch (c1->contents.base, c2->contents.base, force, arg, def, TRUE)); case CT_FCN: return (ctype_genMatch (c1->contents.fcn->rval, c2->contents.fcn->rval, force, arg, def, TRUE) && uentryList_matchParams (c1->contents.fcn->params, c2->contents.fcn->params, force, TRUE)); case CT_STRUCT: case CT_UNION: DPRINTF (("Struct: %s / %s", c1->contents.su->name, c2->contents.su->name)); if (isFakeTag (c1->contents.su->name) && isFakeTag (c2->contents.su->name)) { /* Both fake tags, check structure */ if (cstring_equal (c1->contents.su->name, c2->contents.su->name)) { return TRUE; } else { return uentryList_matchFields (c1->contents.su->fields, c2->contents.su->fields); } } else { if (!cstring_isEmpty (c1->contents.su->name)) { return (cstring_equal (c1->contents.su->name, c2->contents.su->name)); } else { if (!cstring_isEmpty (c2->contents.su->name)) { return FALSE; } llcontbuglit ("ctbase_genMatch: match fields"); return (FALSE); } } default: llcontbug (message ("ctbase_genMatch: unknown type: %d\n", (int)c1tid)); return (FALSE); } } /* ** like ctbase_match, except for conjuncts: ** modifies conjuncts to match only */ static bool ctbase_forceMatch (ctbase c1, ctbase c2) /*@modifies c1, c2@*/ { return (ctbase_genMatch (c1, c2, TRUE, FALSE, FALSE, FALSE)); } static bool ctbase_match (ctbase c1, ctbase c2) /*@modifies nothing@*/ { return (ctbase_genMatch (c1, c2, FALSE, FALSE, FALSE, FALSE)); } static bool ctbase_matchDef (ctbase c1, ctbase c2) /*@modifies nothing@*/ { return (ctbase_genMatch (c1, c2, FALSE, FALSE, TRUE, FALSE)); } static bool ctbase_matchArg (ctbase c1, ctbase c2) { return (ctbase_genMatch (c1, c2, FALSE, TRUE, FALSE, FALSE)); } static /*@out@*/ /*@only@*/ /*@notnull@*/ ctbase ctbase_new () { ctbase c = (ctbase) dmalloc (sizeof (*c)); nctbases++; /* if (nctbases % 100 == 0 && nctbases > lastnc) { llmsg (message ("ctbases: %d", nctbases)); lastnc = nctbases; } */ return (c); } static /*@only@*/ ctbase ctbase_createPrim (cprim p) { ctbase c = ctbase_new (); c->type = CT_PRIM; c->contents.prim = p; return (c); } static /*@observer@*/ ctbase ctbase_getBool (void) { /*@i@*/ return ctbase_createBool (); } static ctbase ctbase_createBool () { if (!ctbase_isDefined (ctbase_bool)) { ctbase_bool = ctbase_new (); ctbase_bool->type = CT_BOOL; ctbase_bool->contents.prim = CTX_BOOL; } /*@-retalias@*/ /*@-globstate@*/ return ctbase_bool; /*@=retalias@*/ /*@=globstate@*/ } static /*@only@*/ ctbase ctbase_createUser (typeId u) { ctbase c = ctbase_new (); c->type = CT_USER; c->contents.tid = u; llassert (typeId_isValid (u)); return (c); } static /*@only@*/ ctbase ctbase_createEnum (/*@keep@*/ cstring etag, /*@keep@*/ enumNameList emembers) { ctbase c = ctbase_new (); c->type = CT_ENUM; if (cstring_isUndefined (etag)) { llcontbuglit ("Undefined enum tag!"); etag = fakeTag (); } c->contents.cenum = (tenum) dmalloc (sizeof (*c->contents.cenum)); c->contents.cenum->tag = etag; c->contents.cenum->members = emembers; return (c); } static /*@observer@*/ cstring ctbase_enumTag (/*@notnull@*/ ctbase ct) { return (ct->contents.cenum->tag); } static /*@only@*/ ctbase ctbase_createAbstract (typeId u) { ctbase c = ctbase_new (); c->type = CT_ABST; c->contents.tid = u; /* also check its abstract? */ llassert (typeId_isValid (c->contents.tid)); return (c); } static /*@only@*/ ctbase ctbase_createNumAbstract (typeId u) { ctbase c = ctbase_new (); c->type = CT_NUMABST; c->contents.tid = u; /* also check its abstract? */ llassert (typeId_isValid (c->contents.tid)); return (c); } static /*@only@*/ ctbase ctbase_createUnknown (void) { if (!ctbase_isDefined (ctbase_unknown)) { ctbase_unknown = ctbase_new (); ctbase_unknown->type = CT_UNKNOWN; ctbase_unknown->contents.prim = CTX_UNKNOWN; } /*@-retalias@*/ /*@-globstate@*/ return ctbase_unknown; /*@=retalias@*/ /*@=globstate@*/ } /* ** requires: result is not assigned to b ** (should copy, but no way to reclaim storage) */ static /*@only@*/ ctbase ctbase_makePointer (ctype b) { ctbase c = ctbase_new (); c->type = CT_PTR; c->contents.base = b; return (c); } static /*@only@*/ ctbase ctbase_makeArray (ctype b) { ctbase c = ctbase_new (); c->type = CT_ARRAY; c->contents.base = b; return (c); } static /*@notnull@*/ /*@only@*/ ctbase ctbase_makeFixedArray (ctype b, size_t size) { ctbase c = ctbase_new (); c->type = CT_FIXEDARRAY; c->contents.farray = (tfixed) dmalloc (sizeof (*c->contents.farray)); c->contents.farray->base = b; c->contents.farray->size = size; return (c); } static ctype ctbase_makeFunction (ctype b, /*@only@*/ uentryList p) { ctbase c = ctbase_new (); ctype ct; c->type = CT_FCN; c->contents.fcn = (cfcn) dmalloc (sizeof (*c->contents.fcn)); if (ctype_isFunction (b)) /* was: && ctype_isPointer (b)) */ { ctbase ctb; ctype rval; if (ctype_isPointer (b)) { ctb = ctype_getCtbase (ctype_baseArrayPtr (b)); } else { ctb = ctype_getCtbase (b); } llassert (ctbase_isDefined (ctb)); llassert (ctb->type == CT_FCN); rval = ctype_makeFunction (ctb->contents.fcn->rval, p); c->contents.fcn->rval = rval; c->contents.fcn->params = uentryList_copy (ctb->contents.fcn->params); /* no copy before */ } else { c->contents.fcn->rval = b; c->contents.fcn->params = uentryList_copy (p); /* no copy before */ /*@-branchstate@*/ /* p is really released on this branch */ } /*@=branchstate@*/ ct = cttable_addComplex (c); return (ct); /* was: ctype_makePointer (ct)); */ } static ctype ctbase_makeNFFunction (ctype b, /*@only@*/ uentryList p) { ctbase c = ctbase_new (); ctype ct; c->type = CT_FCN; c->contents.fcn = (cfcn) dmalloc (sizeof (*c->contents.fcn)); if (ctype_isFunction (b)) /* was && ctype_isPointer (b)) */ { ctbase ctb; ctype rval; if (ctype_isPointer (b)) { ctb = ctype_getCtbase (ctype_baseArrayPtr (b)); } else { ctb = ctype_getCtbase (b); } llassert (ctbase_isDefined (ctb)); llassert (ctb->type == CT_FCN); rval = ctype_makeNFParamsFunction (ctb->contents.fcn->rval, p); c->contents.fcn->rval = rval; c->contents.fcn->params = uentryList_copy (ctb->contents.fcn->params); } else { c->contents.fcn->rval = b; c->contents.fcn->params = uentryList_copy (p); /*@-branchstate@*/ } /*@=branchstate@*/ ct = cttable_addComplex (c); return (ct); /* was: ctype_makePointer (ct)); */ } static /*@only@*/ ctbase ctbase_makeLiveFunction (ctype b, /*@only@*/ uentryList p) { ctbase c = ctbase_new (); c->type = CT_FCN; c->contents.fcn = (cfcn) dmalloc (sizeof (*c->contents.fcn)); c->contents.fcn->rval = b; c->contents.fcn->params = p; /*@-mustfree@*/ return (c); /*@=mustfree@*/ } static /*@observer@*/ /*@notnull@*/ ctbase ctbase_realFunction (/*@dependent@*/ /*@notnull@*/ ctbase c) { ctbase res; if (c->type == CT_FCN) { return c; } llassert (ctbase_isFunction (c)); res = ctype_getCtbase (c->contents.base); llassert (ctbase_isDefined (res)); return (res); } static bool ctbase_isFunction (ctbase c) { llassert (c != ctbase_undefined); if (c->type == CT_FCN) { return TRUE; } else { if (c->type == CT_PTR) { ctbase fcn = ctype_getCtbase (ctbase_baseArrayPtr (c)); return (ctbase_isDefined (fcn) && fcn->type == CT_FCN); } return FALSE; } } /* doesn't copy c1 and c2 */ static /*@only@*/ ctbase ctbase_makeConj (ctype c1, ctype c2, bool isExplicit) { ctbase c = ctbase_new (); c->type = CT_CONJ; c->contents.conj = (tconj) dmalloc (sizeof (*c->contents.conj)); c->contents.conj->a = c1; c->contents.conj->b = c2; c->contents.conj->isExplicit = isExplicit; return (c); } static bool ctbase_isAnytype (/*@notnull@*/ ctbase b) { /* ** A unknown|dne conj is a special representation for an anytype. */ if (b->type == CT_CONJ) { /*@access ctype@*/ return (b->contents.conj->a == ctype_unknown && b->contents.conj->b == ctype_dne); /*@noaccess ctype@*/ } return FALSE; } static ctype ctbase_getConjA (/*@notnull@*/ ctbase c) { llassert (c->type == CT_CONJ); return (c->contents.conj->a); } static ctype ctbase_getConjB (/*@notnull@*/ ctbase c) { llassert (c->type == CT_CONJ); return (c->contents.conj->b); } static bool ctbase_isExplicitConj (/*@notnull@*/ ctbase c) { llassert (c->type == CT_CONJ); return (c->contents.conj->isExplicit); } static /*@only@*/ ctbase ctbase_createStruct (/*@only@*/ cstring n, /*@only@*/ uentryList f) { ctbase c = ctbase_new (); c->type = CT_STRUCT; c->contents.su = (tsu) dmalloc (sizeof (*c->contents.su)); c->contents.su->name = n; c->contents.su->fields = f; return (c); } static /*@observer@*/ uentryList ctbase_getuentryList (/*@notnull@*/ ctbase c) { c = ctbase_realType (c); if (!(c->type == CT_STRUCT || c->type == CT_UNION)) llfatalbug (message ("ctbase_getuentryList: bad invocation: %q", ctbase_unparse (c))); return (c->contents.su->fields); } static ctbase ctbase_createUnion (/*@keep@*/ cstring n, /*@only@*/ uentryList f) { ctbase c = ctbase_new (); c->type = CT_UNION; c->contents.su = (tsu) dmalloc (sizeof (*c->contents.su)); c->contents.su->name = n; c->contents.su->fields = f; return (c); } static ctype ctbase_baseArrayPtr (/*@notnull@*/ ctbase c) { ctuid ct; c = ctbase_realType (c); ct = c->type; if (ct == CT_FIXEDARRAY) { return c->contents.farray->base; } else { llassert (ctuid_isAP (ct)); return c->contents.base; } } static ctype ctbase_baseFunction (/*@notnull@*/ ctbase c) { ctbase_fixUser (c); c = ctbase_realFunction (c); if (c->type != CT_FCN) { llfatalbug (message ("ctbase_baseFunction: bad call: %q", ctbase_unparse (c))); } return (c->contents.fcn->rval); } static uentryList ctbase_argsFunction (/*@notnull@*/ ctbase c) { ctbase_fixUser (c); c = ctbase_realFunction (c); if (c->type != CT_FCN) { llfatalbug (message ("ctbase_argsFunction: bad call: %q", ctbase_unparse (c))); } return (c->contents.fcn->params); } static bool ctbase_baseisExpFcn (ctype c) { ctbase cb; c = ctype_removePointers (c); cb = ctype_getCtbase (c); llassert (ctbase_isDefined (cb)); if (cb->type == CT_FCN) { c = ctype_removePointers (ctype_getReturnType (c)); cb = ctype_getCtbase (c); llassert (ctbase_isDefined (cb)); return (cb->type == CT_EXPFCN); } return FALSE; } /* ** ctbase_newBase behaves specially when p is a CONJ: ** ** c -> conj (newBase (c, p.a), p.b) */ static ctype ctbase_newBase (ctype c, ctype p) { ctbase cb; DPRINTF (("New base: %s / %s", ctype_unparse (c), ctype_unparse (p))); if (ctype_isUndefined (c) || ctype_isUnknown (c)) { return p; } cb = ctype_getCtbase (c); if (ctype_isConj (p)) { ctbase pb = ctype_getCtbase (p); llassert (ctbase_isDefined (pb)); if (pb->contents.conj->isExplicit) { return (ctype_makeExplicitConj (ctype_newBase (c, pb->contents.conj->a), pb->contents.conj->b)); } else { return (ctype_makeConj (ctype_newBase (c, pb->contents.conj->a), pb->contents.conj->b)); } } if (ctbase_baseisExpFcn (c)) { return (ctbase_newBaseExpFcn (c, p)); } llassert (ctbase_isDefined (cb)); switch (cb->type) { case CT_UNKNOWN: case CT_PRIM: case CT_USER: case CT_ENUM: case CT_ABST: case CT_NUMABST: case CT_STRUCT: case CT_UNION: case CT_EXPFCN: return (p); case CT_PTR: { ctype ret; ctype cbn; cbn = ctbase_newBase (cb->contents.base, p); ret = ctype_makePointer (cbn); return ret; } case CT_FIXEDARRAY: return (ctype_makeFixedArray (ctbase_newBase (cb->contents.farray->base, p), cb->contents.farray->size)); case CT_ARRAY: return (ctype_makeArray (ctbase_newBase (cb->contents.base, p))); case CT_FCN: return (ctype_makeRawFunction (ctbase_newBase (cb->contents.fcn->rval, p), cb->contents.fcn->params)); case CT_CONJ: return (ctype_makeConjAux (ctbase_newBase (cb->contents.conj->a, p), ctbase_newBase (cb->contents.conj->b, p), cb->contents.conj->isExplicit)); default: llcontbug (message ("ctbase_newBase: bad ctbase: %q", ctbase_unparse (cb))); return (p); } BADEXIT; } static ctype ctbase_newBaseExpFcn (ctype c, ctype p) { ctbase cb = ctype_getCtbase (c); ctbase tcb; ctype ret, tmpct; ctype fp = ctype_unknown; uentryList ctargs = ctype_argsFunction (c); /* ** okay, this is really ugly... ** ** pointers inside mean pointers to the function; ** pointers outside are pointers to the return value; ** because its a function there is one superfluous pointer. */ /* ** bf is a ctype, used to derived structure of cb */ if (!ctbase_isFunction (cb)) llbuglit ("ctbase_newBaseExpFcn: expFcn -> not a function"); tmpct = ctype_getBaseType (ctype_getReturnType (c)); /* ** pointers before expfcn -> p are pointers to function, not result ** */ tcb = ctype_getCtbase (tmpct); llassert (ctbase_isDefined (tcb)); tmpct = tcb->contents.base; /* ** record pointers to base in fp */ while (!ctype_isUnknown (tmpct)) { if (ctype_isExpFcn (tmpct)) { ctbase ttcb = ctype_getCtbase (tmpct); /* ** evs 2000-05-16: This is necessary to deal with function pointers in parens. ** The whole function pointer parsing is a major kludge, but it seems to work, ** and I'm only embarrassed by it when I haven't look at the C spec recently... */ llassert (ctbase_isDefined (ttcb)); tmpct = ttcb->contents.base; llassert (!ctype_isUnknown (tmpct)); } switch (ctype_getCtKind (tmpct)) { case CTK_PTR: fp = ctype_makePointer (fp); /*@switchbreak@*/ break; case CTK_ARRAY: fp = ctype_makeArray (fp); /*@switchbreak@*/ break; case CTK_COMPLEX: { ctbase fbase = ctype_getCtbase (tmpct); if (ctbase_isFunction (fbase)) { fp = ctype_makeFunction (fp, uentryList_copy (ctargs)); ctargs = ctbase_argsFunction (fbase); } else { llbug (message ("ctbase_newBaseExpFcn: fixing expfunction: bad complex type: %s [base: %q]", ctype_unparse (tmpct), ctbase_unparse (fbase))); } goto exitLoop; } default: { llcontbug (message ("ctbase_newBaseExpFcn: fixing expfunction: bad type: %s", ctype_unparse (tmpct))); goto exitLoop; } } tmpct = ctype_baseArrayPtr (tmpct); } exitLoop: tmpct = ctype_getReturnType (c); /* ** pointers to expf are pointers to return value */ while (!ctype_isExpFcn (tmpct)) { switch (ctype_getCtKind (tmpct)) { case CTK_PTR: p = ctype_makePointer (p); /*@switchbreak@*/ break; case CTK_ARRAY: p = ctype_makeArray (p); /*@switchbreak@*/ break; case CTK_COMPLEX: { ctbase fbase = ctype_getCtbase (tmpct); if (ctbase_isFunction (fbase)) { p = ctype_makeFunction (p, uentryList_copy (ctbase_argsFunction (fbase))); } else { llbug (message ("ctbase_newBaseExpFcn: fixing expfunction: bad complex type: %s", ctype_unparse (tmpct))); } goto exitLoop2; } default: { llcontbug (message ("ctbase_newBaseExpFcn: fixing expfunction2: bad type: %t", tmpct)); goto exitLoop2; } } tmpct = ctype_baseArrayPtr (tmpct); } exitLoop2: /* ** pointers to fp are pointers to function type */ ret = ctype_makeRawFunction (p, uentryList_copy (ctargs)); while (ctype_getCtKind (fp) > CTK_PLAIN) { switch (ctype_getCtKind (fp)) { case CTK_PTR: ret = ctype_makePointer (ret); /*@switchbreak@*/ break; case CTK_ARRAY: ret = ctype_makeArray (ret); /*@switchbreak@*/ break; case CTK_COMPLEX: { ctbase fbase = ctype_getCtbase (fp); if (ctbase_isFunction (fbase)) { ret = ctype_makeFunction (ret, uentryList_copy (ctbase_argsFunction (fbase))); } else { BADBRANCH; } goto exitLoop3; } default: { llcontbug (message ("post-fixing expfunction: bad type: %t", fp)); goto exitLoop3; } } fp = ctype_baseArrayPtr (fp); } exitLoop3: return (ret); } /* ** returns lowest level base of c: plain type */ static /*@notnull@*/ /*@only@*/ ctbase ctbase_getBaseType (/*@notnull@*/ ctbase c) { switch (c->type) { case CT_UNKNOWN: case CT_PRIM: case CT_USER: case CT_ENUM: case CT_ENUMLIST: case CT_BOOL: case CT_ABST: case CT_NUMABST: case CT_FCN: case CT_STRUCT: case CT_UNION: return (ctbase_copy (c)); case CT_PTR: case CT_ARRAY: return (ctbase_getBaseType (ctype_getCtbaseSafe (c->contents.base))); case CT_FIXEDARRAY: return (ctbase_getBaseType (ctype_getCtbaseSafe (c->contents.farray->base))); case CT_CONJ: /* base type of A conj branch? */ return (ctbase_getBaseType (ctype_getCtbaseSafe (c->contents.conj->a))); case CT_EXPFCN: return (ctbase_copy (c)); default: llfatalbug (message ("ctbase_getBaseType: bad ctbase: %q", ctbase_unparse (c))); } BADEXIT; } static int ctbase_compare (ctbase c1, ctbase c2, bool strict) { ctuid c1tid, c2tid; if (ctbase_isUndefined (c1) || ctbase_isUndefined (c2)) { llcontbuglit ("ctbase_compare: undefined ctbase"); return -1; } c1tid = c1->type; c2tid = c2->type; if (c1tid < c2tid) return -1; if (c1tid > c2tid) return 1; switch (c1tid) { case CT_UNKNOWN: return 0; case CT_PRIM: return (int_compare (c1->contents.prim, c2->contents.prim)); case CT_BOOL: return 0; case CT_USER: return (typeId_compare (c1->contents.tid, c2->contents.tid)); case CT_ENUMLIST: return 1; case CT_ENUM: /* for now, keep like abstract */ case CT_ABST: case CT_NUMABST: return (typeId_compare (c1->contents.tid, c2->contents.tid)); case CT_PTR: return (ctype_compare (c1->contents.base, c2->contents.base)); case CT_FIXEDARRAY: INTCOMPARERETURN (c1->contents.farray->size, c2->contents.farray->size); return (ctype_compare (c1->contents.farray->base, c2->contents.farray->base)); case CT_ARRAY: return (ctype_compare (c1->contents.base, c2->contents.base)); case CT_FCN: { COMPARERETURN (ctype_compare (c1->contents.fcn->rval, c2->contents.fcn->rval)); if (strict) { return (uentryList_compareStrict (c1->contents.fcn->params, c2->contents.fcn->params)); } else { return (uentryList_compareParams (c1->contents.fcn->params, c2->contents.fcn->params)); } } case CT_EXPFCN: return (ctype_compare (c1->contents.base, c2->contents.base)); case CT_STRUCT: case CT_UNION: /* evs 2000-07-28: this block was missing! */ if (strict) { int ncmp = cstring_compare (c1->contents.su->name, c2->contents.su->name); if (ncmp != 0) { if (isFakeTag (c1->contents.su->name) && isFakeTag (c2->contents.su->name)) { ; /* If they are both fake struct tags, don't require match. */ } else { return ncmp; } } } DPRINTF (("Comparing fields: %s / %s", ctbase_unparse (c1), ctbase_unparse (c2))); return (uentryList_compareFields (c1->contents.su->fields, c2->contents.su->fields)); case CT_CONJ: { COMPARERETURN (ctype_compare (c1->contents.conj->a, c2->contents.conj->a)); COMPARERETURN (ctype_compare (c1->contents.conj->b, c2->contents.conj->b)); return (bool_compare (c1->contents.conj->isExplicit, c2->contents.conj->isExplicit)); } } BADEXIT; } static int ctbase_compareStrict (/*@notnull@*/ ctbase c1, /*@notnull@*/ ctbase c2) { return (ctbase_compare (c1, c2, TRUE)); } static bool ctbase_equivStrict (/*@notnull@*/ ctbase c1, /*@notnull@*/ ctbase c2) { return (ctbase_compareStrict (c1,c2) == 0); } static bool ctbase_equiv (/*@notnull@*/ ctbase c1, /*@notnull@*/ ctbase c2) { return (ctbase_compare (c1, c2, FALSE) == 0); } static bool ctbase_isKind (/*@notnull@*/ ctbase c, ctuid kind) { ctuid ck = c->type; if (ck == kind) return TRUE; if (ck == CT_CONJ) return (ctbase_isKind (ctype_getCtbaseSafe (c->contents.conj->a), kind) || ctbase_isKind (ctype_getCtbaseSafe (c->contents.conj->b), kind)); return FALSE; } static bool ctbase_isKind2 (/*@notnull@*/ ctbase c, ctuid kind1, ctuid kind2) { ctuid ck = c->type; if (ck == kind1 || ck == kind2) return TRUE; if (ck == CT_CONJ) return (ctbase_isKind2 (ctype_getCtbaseSafe (c->contents.conj->a), kind1, kind2) || ctbase_isKind2 (ctype_getCtbaseSafe (c->contents.conj->b), kind1, kind2)); return FALSE; } static bool ctbase_isAbstract (/*@notnull@*/ ctbase c) { return (c->type == CT_ABST || c->type == CT_NUMABST); } static bool ctbase_isNumAbstract (/*@notnull@*/ ctbase c) { return (c->type == CT_NUMABST); } static bool ctbase_isUA (ctbase c) { return (ctbase_isDefined (c) && (ctuid_isAnyUserType (c->type))); } static bool ctbase_almostEqual (ctbase c1, ctbase c2) { ctuid c1tid, c2tid; /* undefined types never match */ if (ctbase_isUndefined (c1) || ctbase_isUndefined (c2)) return FALSE; c1tid = c1->type; c2tid = c2->type; if (c1tid == CT_FIXEDARRAY && c2tid == CT_ARRAY) { return (ctbase_almostEqual (ctype_getCtbase (c1->contents.farray->base), ctype_getCtbase (c2->contents.base))); } if (c2tid == CT_FIXEDARRAY && c1tid == CT_ARRAY) { return (ctbase_almostEqual (ctype_getCtbase (c1->contents.base), ctype_getCtbase (c2->contents.farray->base))); } if (c1tid != c2tid) return FALSE; switch (c1tid) { case CT_UNKNOWN: return TRUE; case CT_PRIM: return (cprim_equal (c1->contents.prim, c2->contents.prim)); case CT_BOOL: return TRUE; case CT_ABST: case CT_NUMABST: case CT_USER: return (typeId_equal (c1->contents.tid, c2->contents.tid)); case CT_ENUM: return (cstring_equal (c1->contents.cenum->tag, c2->contents.cenum->tag)); case CT_PTR: return (ctype_almostEqual (c1->contents.base, c2->contents.base)); case CT_FIXEDARRAY: return (ctype_almostEqual (c1->contents.farray->base, c2->contents.farray->base)); case CT_ARRAY: return (ctype_almostEqual (c1->contents.base, c2->contents.base)); case CT_FCN: return (ctype_almostEqual (c1->contents.fcn->rval, c2->contents.fcn->rval) && uentryList_matchParams (c1->contents.fcn->params, c2->contents.fcn->params, FALSE, TRUE)); case CT_STRUCT: case CT_UNION: if (!cstring_isEmpty (c1->contents.su->name)) { return (cstring_equal (c1->contents.su->name, c2->contents.su->name)); } else { if (!cstring_isEmpty (c2->contents.su->name)) { return FALSE; } llcontbuglit ("ctbase_almostEqual: match fields"); return (FALSE); } default: llcontbug (message ("ctbase_almostEqual: unknown type: %d\n", (int)c1tid)); return (FALSE); } } /*drl added July 02, 001 called by ctype_getArraySize */ size_t ctbase_getArraySize (ctbase ctb) { /*drl 1/25/2002 fixed discovered by Jim Francis */ ctbase r; llassert (ctbase_isDefined (ctb) ); r = ctbase_realType (ctb); llassert (ctbase_isFixedArray(r) ); return (r->contents.farray->size); } bool ctbase_isBigger (ctbase ct1, ctbase ct2) { if (ct1 != NULL && ct2 != NULL && (ct1->type == CT_PRIM && ct2->type == CT_PRIM)) { /* Only compare sizes for primitives */ cprim cp1 = ct1->contents.prim; cprim cp2 = ct2->contents.prim; int nbits1 = cprim_getExpectedBits (cp1); int nbits2 = cprim_getExpectedBits (cp2); if (nbits1 > nbits2) { return TRUE; } else { return FALSE; } } else { return FALSE; } } int ctbase_getSize (ctbase ct) { if (ct == NULL) { return 0; } switch (ct->type) { case CT_UNKNOWN: case CT_BOOL: case CT_PRIM: { cprim cp = ct->contents.prim; int nbits = cprim_getExpectedBits (cp); return nbits; } case CT_USER: case CT_ABST: case CT_NUMABST: case CT_EXPFCN: { return 0; } case CT_PTR: { /* Malloc returns void *, but they are bytes. Normal void * is pointer size. */ if (ctype_isVoid (ct->contents.base)) { return 8; } else { return ctype_getSize (ct->contents.base); } } case CT_FIXEDARRAY: case CT_ARRAY: case CT_FCN: case CT_STRUCT: case CT_UNION: case CT_ENUM: case CT_CONJ: break; BADDEFAULT; } return 0; }