static value intern_fast_val(struct channel * chan, unsigned long magic) { value res; mlsize_t whsize, wosize; unsigned long bhsize; color_t color; header_t hd; whsize = getword(chan); if (whsize == 0) { res = (value) getword(chan); if (IS_LONG(res)) return res; else return Atom(res >> 2); }
/* Turn an externalized ML value (a string) into an ML value, a la intern.c */ value mlval_string(value s) { value res; mlsize_t whsize, wosize; unsigned long bhsize; color_t color; header_t hd; whsize = ((mlsize_t *)s)[0]; if (whsize == 0) { res = (value) ((mlsize_t *)s)[1]; if (IS_LONG(res)) return res; else return Atom(res >> 2); }
/* * XXX warn about ``unsigned char *'' vs ``char *'', * unlike gcc */ static int compare_tlist(struct type_node *dest, struct type_node *src, int flag) { struct type_node *dest_start = dest; for (; dest != NULL && src != NULL; dest = dest->next, src = src->next) { if (src->type == TN_FUNCTION || dest->type == TN_FUNCTION) { if (dest->type != src->type) { /* XXX fix this later */ if (dest == dest_start) { /* * Ordinary function symbols are * compatible with pointers to * functions */ if (dest->type == TN_FUNCTION) { if (src->type == TN_POINTER_TO) { src = src->next; } else { return -1; } } else { if (dest->type == TN_POINTER_TO) { dest = dest->next; } else { return -1; } } } } } if (dest->type != src->type) { /* Pointer vs array vs function */ if (flag & CMPTY_ARRAYPTR) { if ((dest->type == TN_ARRAY_OF || src->type == TN_ARRAY_OF || dest->type == TN_VARARRAY_OF || src->type == TN_VARARRAY_OF) && (dest->type == TN_POINTER_TO || src->type == TN_POINTER_TO)) { continue; } } return -1; } switch (dest->type) { case TN_ARRAY_OF: case TN_VARARRAY_OF: if (flag & CMPTY_TENTDEC) { #if REMOVE_ARRARG if (!dest->have_array_size || !src->have_array_size) { #else if (dest->arrarg->const_value == NULL || src->arrarg->const_value == NULL) { #endif /* * probably * extern int foo[]; * int foo[123]; * -> OK! */ break; } } if (dest->arrarg_const != src->arrarg_const && ((flag & CMPTY_ARRAYPTR) == 0 || dest_start != dest)) { #if REMOVE_ARRARG if (!src->have_array_size || !dest->have_array_size) { #else if (src->arrarg->const_value == NULL || dest->arrarg->const_value == NULL) { #endif /* * One side has unspecified size, this * is OK! * extern char foo[]; * char (*p)[5] = &foo; * char bar[5]; * char (*p2)[] = &bar; */ break; } else { /* Array sizes differ */ return -1; } } break; case TN_POINTER_TO: break; case TN_FUNCTION: if (compare_tfunc(dest->tfunc, src->tfunc) == -1) { return -1; } break; } } if (dest != NULL || src != NULL) { /* One list is longer, so it differs by definition */ return -1; } return 0; } #endif /* #ifndef PREPROCESSOR */ int compare_types(struct type *dest, struct type *src, int flag) { int is_void_ptr = 0; /* 04/08/08: Changed this (for the better, hopefully!) */ if (dest->tlist != NULL && dest->tlist->type == TN_POINTER_TO && dest->tlist->next == NULL && dest->code == TY_VOID) { is_void_ptr = 1; } else if (src->tlist != NULL && src->tlist->type == TN_POINTER_TO && src->tlist->next == NULL && src->code == TY_VOID) { is_void_ptr = 1; } if (dest->code != src->code) { /* * Differing base type - This is ok if we have a void * pointer vs a non-void pointer, otherwise return error */ if (!is_void_ptr || src->tlist == NULL || dest->tlist == NULL) { return -1; } } if (flag & CMPTY_SIGN) { if (dest->sign != dest->sign) { /* Differing sign */ return -1; } } if (flag & CMPTY_CONST) { if (IS_CONST(dest->flags) != IS_CONST(src->flags)) { /* One is const-qualified */ /*return -1;*/ } } /* * 04/08/08: Skip the tlist comparison if this is void pointer * vs non-void pointer; Otherwise tlists of different length * will compare uneven, as in void * vs int **, which is wrong */ if (is_void_ptr) { return 0; } #ifndef PREPROCESSOR return compare_tlist(dest->tlist, src->tlist, flag); #else return -1; #endif } int check_init_type(struct type *ofwhat, struct expr *init) { if (ofwhat->tlist == NULL) { if (init->next != NULL) { } } else if (ofwhat->tlist->type == TN_ARRAY_OF) { if (init->type->code == TOK_STRING_LITERAL) { return 0; } else { struct expr *ex; for (ex = init; ex != NULL; ex = ex->next) { } } } return 0; } void copy_type(struct type *dest, const struct type *src, int fullcopy) { if (fullcopy) { memcpy(dest, src, sizeof *dest); } else { memcpy(dest, src, sizeof *dest); } } struct type_node * copy_tlist(struct type_node **dest, const struct type_node *src) { struct type_node *head; struct type_node *tail; struct type_node *tn; if (src == NULL) { *dest = NULL; return NULL; } head = tail = NULL; do { tn = n_xmalloc(sizeof *tn); memcpy(tn, src, sizeof *tn); if (head == NULL) { head = tail = tn; } else { tail->next = tn; tail = tail->next; } } while ((src = src->next) != NULL); *dest = head; return tail; } void set_type_sign(struct type *ty) { if (ty->code == TY_UCHAR || ty->code == TY_USHORT || ty->code == TY_UINT || ty->code == TY_ULONG || ty->code == TY_ULLONG) { ty->sign = TOK_KEY_UNSIGNED; } else if (!IS_FLOATING(ty->code) && ty->code != TY_STRUCT && ty->code != TY_UNION) { ty->sign = TOK_KEY_SIGNED; } } struct type * make_basic_type(int code) { #define N_TYPES (TY_MAX - TY_MIN) #if 0 static struct type basic_types[N_TYPES]; #endif static int inited; static struct type *basic_types; if (!inited) { int i; int nbytes = N_TYPES * sizeof(struct type); int need_mprotect = 1; basic_types = debug_malloc_pages(nbytes); if (basic_types == NULL) { /* * Probably debug_malloc_pages() doesn't work * on this system */ basic_types = n_xmalloc(nbytes); need_mprotect = 0; } memset(basic_types, 0, nbytes); for (i = 0; i < N_TYPES; ++i) { basic_types[i].code = i + TY_MIN; set_type_sign(&basic_types[i]); } inited = 1; if (need_mprotect) { /* * We make the array unwritable because it really * should not be written to; Modifying it is a bug * that has happend more than once. * * The void cast is necessary because of a broken * Solaris prototype that takes caddr_t :-/ */ mprotect((void *)basic_types, nbytes, PROT_READ); } } if (code < 0 || (code - TY_MIN) >= N_TYPES) { printf("BUG: bad code for make_basic_type: %d\n", code); abort(); } #if 0 if (code == TY_PSEUDEO_SIZE_T) { static struct type ty; static struct type *p; if (p == NULL) { ty = basic_types[TY_UINT]; } } #endif #if 0 /* As of Jan 6 2007, the basic types may not be modified anymore */ basic_types[code - TY_MIN].tlist = NULL; #endif return &basic_types[code - TY_MIN]; } struct type * make_void_ptr_type(void) { static struct type *ty; if (ty == NULL) { ty = make_basic_type(TY_VOID); ty = n_xmemdup(ty, sizeof *ty); append_typelist(ty, TN_POINTER_TO, NULL, NULL, NULL); } return ty; } struct type * make_array_type(int size, int is_wide_char) { struct type *ret = alloc_type(); if (is_wide_char) { ret->code = backend->get_wchar_t()->code; ret->sign = backend->get_wchar_t()->sign; } else { ret->code = TY_CHAR; if (CHAR_MAX == UCHAR_MAX) { /* XXX */ ret->sign = TOK_KEY_UNSIGNED; } else { ret->sign = TOK_KEY_SIGNED; } } ret->storage = TOK_KEY_STATIC; ret->tlist = alloc_type_node(); ret->tlist->type = TN_ARRAY_OF; ret->tlist->arrarg_const = size; #if REMOVE_ARRARG ret->tlist->have_array_size = 1; #endif return ret; } /* * Helper function for parse_declarator()- stores pointer/array-of/function * property (specified by ``type'' argument) with optional arguments type_arg * (for pointer/array-of) and tf (for function) in type specified by t * * 01/26/08: Extended to do some sanity checking (functions may not return * functions or arrays). This means some type constructions are now REQUIRED * to go through append_typelist()! May not be the best approach, needs * testing?! */ void append_typelist(struct type *t, int type, void *type_arg, struct ty_func *tf, struct token *tok) { struct type_node *te; struct expr *ex; (void) tok; /* XXX unneeded?!?! */ /* Allocate and insert new type node */ if (t->tlist == NULL) { te = t->tlist = t->tlist_tail = alloc_type_node(); te->prev = NULL; if (type == TN_FUNCTION) { /* * If the first node in the type list is a function * designator, this means we are dealing with a genuine * function declaration/definition (as opposed to a * pointer) */ t->is_func = 1; } } else { /* * 01/26/08: Some sanity checking! */ int tailtype = t->tlist_tail->type; if (tailtype == TN_ARRAY_OF || tailtype == TN_VARARRAY_OF) { if (type == TN_FUNCTION) { errorfl(tok, "Invalid declaration of `array of " "functions' - Maybe you meant `array " "of pointer to function'; `void (*ar[N])();'?"); return /* -1 XXX */ ; } } else if (tailtype == TN_FUNCTION) { if (type == TN_ARRAY_OF || type == TN_VARARRAY_OF) { errorfl(tok, "Invalid declaration of `function " "returning array' - If you really want " "to return an array by value, put it " "into a structure!"); return /* -1 XXX */ ; } else if (type == TN_FUNCTION) { errorfl(tok, "Invalid declaration of `function " "returning function' - You can at most " "return a pointer to a function; " "`void (*foo())();'"); return /* -1 XXX */ ; } } te = alloc_type_node(); te->prev = t->tlist_tail; t->tlist_tail->next = te; t->tlist_tail = t->tlist_tail->next; } te->next = NULL; te->type = type; switch (type) { case TN_VARARRAY_OF: case TN_ARRAY_OF: #if REMOVE_ARRARG ex = type_arg; if (ex->const_value == NULL) { /* Size not specified - extern char buf[]; */ te->have_array_size = 0; } else { te->have_array_size = 1; ex->const_value->type = n_xmemdup(ex->const_value->type, sizeof(struct type)); cross_convert_tyval(ex->const_value, NULL, NULL); te->arrarg_const = cross_to_host_size_t( ex->const_value); if (te->arrarg_const == 0) { /* * In GNU C, * int foo[0]; * may be a flexible array member */ te->have_array_size = 0; #if 0 errorfl(tok, "Cannot create zero-sized arrays"); #endif } } if (type == TN_VARARRAY_OF) { te->variable_arrarg = ex; } #else /* Using arrarg */ te->arrarg = type_arg; if (te->arrarg->const_value) { te->arrarg->const_value->type = n_xmemdup(te->arrarg->const_value->type, sizeof(struct type)); cross_convert_tyval(te->arrarg->const_value, NULL, NULL); te->arrarg_const = /* *(size_t *) */ cross_to_host_size_t( te->arrarg->const_value); /*->value; */ if (te->arrarg_const == 0) { /* * In GNU C, * int foo[0]; * may be a flexible array member */ te->arrarg->const_value = NULL; #if 0 errorfl(tok, "Cannot create zero-sized arrays"); #endif } } #endif /* REMOVE_ARRARG is disabled */ break; case TN_POINTER_TO: te->ptrarg = type_arg? *(int *)type_arg: 0; break; case TN_FUNCTION: te->tfunc = tf; break; } } static struct { char *name; int code; } basic_type_names[] = { { "char", TY_CHAR }, { "unsigned char", TY_UCHAR }, { "signed char", TY_SCHAR }, { "short", TY_SHORT }, { "unsigned short", TY_USHORT }, { "int", TY_INT }, { "unsigned int", TY_UINT }, { "long", TY_LONG }, { "unsigned long", TY_ULONG }, { "float", TY_FLOAT }, { "double", TY_DOUBLE }, { "long double", TY_LDOUBLE }, { "struct", TY_STRUCT }, { "union", TY_UNION }, { "enum", TY_ENUM }, { "void", TY_VOID }, { "long long", TY_LLONG }, { "unsigned long long", TY_ULLONG }, { "_Bool", TY_BOOL }, { NULL, 0 } }; char * ret_type_to_text(struct type *ty) { struct type_node *orig_tlist = NULL; char *ret; if (ty->tlist != NULL) { orig_tlist = ty->tlist; if (ty->tlist->type == TN_FUNCTION) { ty->tlist = ty->tlist->next; } else if (ty->tlist->type == TN_POINTER_TO && ty->tlist->next != NULL && ty->tlist->next->type == TN_FUNCTION) { ty->tlist = ty->tlist->next->next; } ret = type_to_text(ty); ty->tlist = orig_tlist; } else { ret = type_to_text(ty); } return ret; } char * type_to_text(struct type *dt) { struct type_node *t; char *buf = NULL; char *p = NULL; size_t size = 0; size_t used = 0; int i; for (t = dt->tlist; t != NULL; t = t->next) { switch (t->type) { case TN_ARRAY_OF: case TN_VARARRAY_OF: make_room(&buf, &size, used + 64); used += sprintf(buf+used, "an array of %d ", (int)t->arrarg_const); break; case TN_POINTER_TO: { char *quali = ""; if (t->ptrarg != 0) { switch (t->ptrarg) { case TOK_KEY_VOLATILE: quali = "volatile"; break; case TOK_KEY_CONST: quali = "constant"; break; case TOK_KEY_RESTRICT: quali = "restricted"; break; } } make_room(&buf, &size, used + 32); used += sprintf(buf+used, "a %s pointer to ", quali); break; } case TN_FUNCTION: make_room(&buf, &size, used + 32); used += sprintf(buf+used, "a function (with %d args) returning ", t->tfunc->nargs); break; } } #if 0 p = basic_type_names[dt->code - TY_MIN]; #endif for (i = 0; basic_type_names[i].name != NULL; ++i) { if (dt->code == basic_type_names[i].code) { p = basic_type_names[i].name; break; } } make_room(&buf, &size, strlen(p) + 5); used += sprintf(buf+used, "%s", p); if (dt->code == TY_STRUCT) { if (dt->tstruc && dt->tstruc->tag) { make_room(&buf, &size, used + strlen(dt->tstruc->tag) + 2); sprintf(buf+used, " %s", dt->tstruc->tag); } } return buf; } #ifndef PREPROCESSOR extern void put_ppc_llong(struct num *); /* * XXX same stupid size_t cross-compilaion bug as const_from_value().. * this stuff SUCKS!!! */ struct token * const_from_type(struct type *ty, int from_alignment, int extype, struct token *t) { struct token *ret = alloc_token(); size_t size; int size_t_size; #if 0 ret->type = TY_ULONG; /* XXX size_t */ #endif ret->type = backend->get_size_t()->code; if (from_alignment) { size = backend->get_align_type(ty); } else { size = backend->get_sizeof_type(ty, t); } /*ret->data = n_xmemdup(&size, sizeof size);*/ ret->data = n_xmalloc(16); /* XXX */ size_t_size = backend->get_sizeof_type(backend->get_size_t(), NULL); if (sizeof size == size_t_size) { memcpy(ret->data, &size, sizeof size); } else if (sizeof(int) == size_t_size) { unsigned int i = (unsigned int)size; memcpy(ret->data, &i, sizeof i); } else if (sizeof(long) == size_t_size) { unsigned long l = (unsigned long)size; memcpy(ret->data, &l, sizeof l); } else if (sizeof(long long) == size_t_size) { unsigned long long ll = (unsigned long long)size; memcpy(ret->data, &ll, sizeof ll); } else { unimpl(); } if (backend->abi == ABI_POWER64 && extype != EXPR_CONST && extype != EXPR_CONSTINIT /* What about EXPR_OPTCONSTINIT?! */ ) { struct num *n = n_xmalloc(sizeof *n); /* * XXX see definition of put_ppc_llong() for an * explanation of this mess */ n->type = ret->type; n->value = ret->data; put_ppc_llong(n); /*ret->data = llong_const;*/ ret->data2 = llong_const; } return ret; } /* * XXX this interface is ROTTEN!! * too easy to pass a ``size_t'' for value with ty=NULL by accident!! * * XXXX WOAH this was totally broken WRT cross-compilation! ``type'' * is interpreted as host type when dealing with ``value'', and as * target type too by making it the type of the token! Current ad-hoc * kludge sucks! */ struct token * const_from_value(void *value, struct type *ty) { struct token *ret = alloc_token(); size_t size; if (ty == NULL) { ret->type = TY_INT; size = backend->get_sizeof_type(make_basic_type( TY_INT), NULL);; } else { ret->type = ty->code; size = backend->get_sizeof_type(ty, NULL); } if (ty && (IS_LONG(ty->code) || IS_LLONG(ty->code))) { if (sizeof(long) == size) { /* Size matches - nothing to do */ ; } else { static long long llv; llv = *(int *)value; value = &llv; } } ret->data = n_xmemdup(value, size); if (backend->abi == ABI_POWER64 && ty != NULL && is_integral_type(ty) && size == 8) { struct num *n = n_xmalloc(sizeof *n); static struct num nullnum; *n = nullnum; n->type = ret->type; n->value = ret->data; put_ppc_llong(n); ret->data2 = llong_const; } return ret; } /* * Construct a floating point constant token of type ``type'' * containing ``value'' (which must be a string parsable by sscanf().) */ struct token * fp_const_from_ascii(const char *value, int type) { struct num *n; struct token *ret = n_xmalloc(sizeof *ret); n = cross_scan_value(value, type, 0, 0, 1); if (n == NULL) { return NULL; } /* * XXX token.data is ``struct ty_float'', not * ``struct num''. Because the interfaces are * still messed up, we have to get the current * ty_float corresponding to ``n'' from the * float list. This SUCKS! */ ret->data = float_const/*n->value*/; ret->type = type; ret->ascii = n_xstrdup(value); return ret; } struct token * const_from_string(const char *value) { struct token *ret = alloc_token(); struct type *ty; struct ty_string *tmpstr; tmpstr = alloc_ty_string(); tmpstr->size = strlen(value) + 1; tmpstr->str = n_xmemdup(value, tmpstr->size); tmpstr->is_wide_char = 0; ret->type = TOK_STRING_LITERAL; ty = make_array_type(tmpstr->size, tmpstr->is_wide_char); tmpstr->ty = ty; ret->data = tmpstr; return ret; } int is_integral_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (IS_CHAR(t->code) || IS_SHORT(t->code) || IS_INT(t->code) || IS_LONG(t->code) || IS_LLONG(t->code) || t->code == TY_ENUM) { return 1; } return 0; } int is_floating_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (t->code == TY_FLOAT || t->code == TY_DOUBLE || t->code == TY_LDOUBLE) { return 1; } return 0; } int is_arithmetic_type(struct type *t) { if (t->tlist != NULL) { return 0; } if (IS_FLOATING(t->code) || is_integral_type(t)) { return 1; } return 0; } int is_array_type(struct type *t) { struct type_node *tn; if (t->tlist == NULL) { return 0; } for (tn = t->tlist; tn != NULL; tn = tn->next) { if (tn->type != TN_ARRAY_OF) { return 0; } else { break; } } return 1; } int is_basic_agg_type(struct type *t) { if (t->tlist == NULL) { if (t->code == TY_STRUCT || t->code == TY_UNION) { return 1; } } else if (is_array_type(t)) { return 1; } return 0; } int is_scalar_type(struct type *t) { if (t->tlist == NULL && (t->code == TY_STRUCT || t->code == TY_UNION || t->code == TY_VOID)) { return 0; } return 1; } int is_arr_of_ptr(struct type *t) { struct type_node *tn; for (tn = t->tlist; tn != NULL; tn = tn->next) { if (tn->type == TN_POINTER_TO) { return 1; } else if (tn->type == TN_FUNCTION) { return 0; } } return 0; } int is_nullptr_const(struct token *constant, struct type *ty) { if (IS_INT(ty->code) && *(unsigned *)constant->data == 0) { return 1; } else if (IS_LONG(ty->code) && *(unsigned long *)constant->data == 0) { return 1; } return 0; } /* * The source type must be passed with a vreg because we need the null * pointer constant and object backing information it gives us */ int check_types_assign( struct token *t, struct type *left, struct vreg *right, int to_const_ok, int silent) { struct type *ltype = left; struct type *rtype = right->type; if (ltype == NULL || rtype == NULL) { printf("attempt to assign to/from value without type :(\n"); abort(); } /* * 01/26/08: Changed this to call is_modifyable(), which also * rules out assignment to const-qualified pointers */ /*if (ltype->tlist == NULL && ltype->is_const && !to_const_ok) { */ if (!is_modifyable(ltype) && !to_const_ok) { if (!silent) { errorfl(t, "Assignment to const-qualified object"); } return -1; } if (is_arithmetic_type(ltype)) { if (!is_arithmetic_type(rtype)) { if (ltype->code == TY_BOOL && rtype->tlist != NULL) { /* ok - pointer to bool */ return 0; } else { int allow = 0; if (rtype->tlist != NULL && is_integral_type(ltype)) { /* * 03/09/09: Give in and allow pointer * to integer assignment with a warning */ allow = 1; } if (!silent) { if (allow) { warningfl(t, "Assignment from non-arithmetic to " "arithmetic type"); } else { errorfl(t, "Assignment from non-arithmetic to " "arithmetic type"); } } if (allow) { return 0; } else { return -1; } } } else if (ltype->sign != rtype->sign && !right->from_const) { /* * Do not warn about signedness differences if the * right side is a constant! */ #if 0 /* XXX Too verbose */ warningfl(t, "Assignment from type of differing signedness"); #endif return 0; } return 0; } else if (ltype->tlist == NULL) { /* Must be struct/union */ if (rtype->tlist != NULL) { if (ltype->code == TY_BOOL) { return 0; } else { if (!silent) { /* 06/01/08: Warn, not error */ warningfl(t, "Assignment from pointer to non-pointer type"); } /* * 07/20/08: The return below was commented out! * That's wrong because pointer to struct will * compare assignable to struct * Why was this removed? */ return -1; } } else if (ltype->code == TY_BOOL) { return 0; /* _Bool b = ptr; is OK */ } else if (rtype->code != ltype->code || rtype->tstruc != ltype->tstruc) { if (!silent) { errorfl(t, "Assignment from incompatible type"); } return -1; } else { return 0; } } else { /* Left is pointer of some sort */ if (right->is_nullptr_const) { ; /* ok */ } else if (rtype->tlist == NULL) { if (!silent) { warningfl(t, "Assignment from non-pointer " "to pointer type"); } /* return -1;*/ } else if (rtype->code == TY_VOID && rtype->tlist->type == TN_POINTER_TO && rtype->tlist->next == NULL) { ; /* void pointer - compatible */ } else if (ltype->code == TY_VOID && ltype->tlist->type == TN_POINTER_TO && ltype->tlist->next == NULL) { ; /* void pointer - compatible */ } else if (compare_tlist(ltype->tlist, rtype->tlist, CMPTY_ARRAYPTR)) { if (!silent) { warningfl(t, "Assignment from incompatible pointer type" " (illegal in ISO C, and very " "probably not what you want)"); } else { /* * This is only used for transparent_union * right now... in that case we do not want * to allow this assignment because type- * checking is the whole point of that * language extension */ return -1; } return 0; } else if (!IS_CONST(ltype->flags) && IS_CONST(rtype->flags)) { if (!silent) { warningfl(t, "Assignment from const-qualified type " "to unqualified one"); } return 0; } else if (rtype->code != ltype->code && rtype->code != TY_VOID && ltype->code != TY_VOID /* XXX */ && (!IS_CHAR(ltype->code) || !IS_CHAR(rtype->code))) { if (type_without_sign(ltype->code) == type_without_sign(rtype->code)) { if (!silent) { warningfl(t, "Assignment from pointer of " "differing signedness"); } else { return -1; } return 0; } else { if (!silent) { warningfl(t, "Assignment from incompatible " "pointer type (illegal in ISO C, and " "very probably not what you want)"); } else { return -1; } #if 0 return -1; #endif return 0; } } else if (IS_CONST(ltype->flags) && !IS_CONST(rtype->flags) && ltype->tlist != NULL && ltype->tlist->next != NULL) { if (!silent) { warningfl(t, "ISO C does not allow assignment " "from `T **' to `const T **' without a " "cast (otherwise invalid code like " "`const char dont_modify; char *p; const " "char **cp = &p; *cp = &dont_modify; *p = 0;' " "would pass without warning)"); } return 0; } } return 0; } struct type * addrofify_type(struct type *ty) { struct type *ret = n_xmemdup(ty, sizeof *ty); struct type_node *tn; copy_tlist(&ret->tlist, ret->tlist); tn = alloc_type_node(); tn->type = TN_POINTER_TO; tn->next = ret->tlist; ret->tlist = tn; return ret; } int type_without_sign(int code) { int rc = code; if (code == TY_UCHAR) rc = TY_CHAR; else if (code == TY_USHORT) rc = TY_SHORT; else if (code == TY_UINT) rc = TY_INT; else if (code == TY_ULONG) rc = TY_LONG; else if (code == TY_ULLONG) rc = TY_LLONG; return rc; }
/* * Parse the type and its initializer and emit it (recursively). */ static void emitInitVal(struct dbuf_s *oBuf, symbol *topsym, sym_link *my_type, initList *list) { symbol *sym; int size, i; long lit; unsigned char *str; size = getSize(my_type); if (IS_PTR(my_type)) { DEBUGprintf ("(pointer, %d byte) %p\n", size, list ? (void *)(long)list2int(list) : NULL); emitIvals(oBuf, topsym, list, 0, size); return; } if (IS_ARRAY(my_type) && topsym && topsym->isstrlit) { str = (unsigned char *)SPEC_CVAL(topsym->etype).v_char; emitIvalLabel(oBuf, topsym); do { dbuf_printf (oBuf, "\tretlw 0x%02x ; '%c'\n", str[0], (str[0] >= 0x20 && str[0] < 128) ? str[0] : '.'); } while (*(str++)); return; } if (IS_ARRAY(my_type) && list && list->type == INIT_NODE) { fprintf (stderr, "Unhandled initialized symbol: %s\n", topsym->name); assert ( !"Initialized char-arrays are not yet supported, assign at runtime instead." ); return; } if (IS_ARRAY(my_type)) { DEBUGprintf ("(array, %d items, %d byte) below\n", DCL_ELEM(my_type), size); assert (!list || list->type == INIT_DEEP); if (list) list = list->init.deep; for (i = 0; i < DCL_ELEM(my_type); i++) { emitInitVal(oBuf, topsym, my_type->next, list); topsym = NULL; if (list) list = list->next; } // for i return; } if (IS_FLOAT(my_type)) { // float, 32 bit DEBUGprintf ("(float, %d byte) %lf\n", size, list ? list2int(list) : 0.0); emitIvals(oBuf, topsym, list, 0, size); return; } if (IS_CHAR(my_type) || IS_INT(my_type) || IS_LONG(my_type)) { // integral type, 8, 16, or 32 bit DEBUGprintf ("(integral, %d byte) 0x%lx/%ld\n", size, list ? (long)list2int(list) : 0, list ? (long)list2int(list) : 0); emitIvals(oBuf, topsym, list, 0, size); return; } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == STRUCT) { // struct DEBUGprintf ("(struct, %d byte) handled below\n", size); assert (!list || (list->type == INIT_DEEP)); // iterate over struct members and initList if (list) list = list->init.deep; sym = SPEC_STRUCT(my_type)->fields; while (sym) { long bitfield = 0; int len = 0; if (IS_BITFIELD(sym->type)) { while (sym && IS_BITFIELD(sym->type)) { int bitoff = SPEC_BSTR(getSpec(sym->type)) + 8 * sym->offset; assert (!list || ((list->type == INIT_NODE) && IS_AST_LIT_VALUE(list->init.node))); lit = (long) (list ? list2int(list) : 0); DEBUGprintf ( "(bitfield member) %02lx (%d bit, starting at %d, bitfield %02lx)\n", lit, SPEC_BLEN(getSpec(sym->type)), bitoff, bitfield); bitfield |= (lit & ((1ul << SPEC_BLEN(getSpec(sym->type))) - 1)) << bitoff; len += SPEC_BLEN(getSpec(sym->type)); sym = sym->next; if (list) list = list->next; } // while assert (len < sizeof (long) * 8); // did we overflow our initializer?!? len = (len + 7) & ~0x07; // round up to full bytes emitIvals(oBuf, topsym, NULL, bitfield, len / 8); topsym = NULL; } // if if (sym) { emitInitVal(oBuf, topsym, sym->type, list); topsym = NULL; sym = sym->next; if (list) list = list->next; } // if } // while if (list) { assert ( !"Excess initializers." ); } // if return; } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == UNION) { // union DEBUGprintf ("(union, %d byte) handled below\n", size); assert (list && list->type == INIT_DEEP); // iterate over union members and initList, try to map number and type of fields and initializers my_type = matchIvalToUnion(list, my_type, size); if (my_type) { emitInitVal(oBuf, topsym, my_type, list->init.deep); topsym = NULL; size -= getSize(my_type); if (size > 0) { // pad with (leading) zeros emitIvals(oBuf, NULL, NULL, 0, size); } return; } // if assert ( !"No UNION member matches the initializer structure."); } else if (IS_BITFIELD(my_type)) { assert ( !"bitfields should only occur in structs..." ); } else { printf ("SPEC_NOUN: %d\n", SPEC_NOUN(my_type)); assert( !"Unhandled initialized type."); } }
/* * For UNIONs, we first have to find the correct alternative to map the * initializer to. This function maps the structure of the initializer to * the UNION members recursively. * Returns the type of the first `fitting' member. */ static sym_link * matchIvalToUnion (initList *list, sym_link *type, int size) { symbol *sym; assert (type); if (IS_PTR(type) || IS_CHAR(type) || IS_INT(type) || IS_LONG(type) || IS_FLOAT(type)) { if (!list || (list->type == INIT_NODE)) { DEBUGprintf ("OK, simple type\n"); return (type); } else { DEBUGprintf ("ERROR, simple type\n"); return (NULL); } } else if (IS_BITFIELD(type)) { if (!list || (list->type == INIT_NODE)) { DEBUGprintf ("OK, bitfield\n"); return (type); } else { DEBUGprintf ("ERROR, bitfield\n"); return (NULL); } } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == STRUCT) { if (!list || (list->type == INIT_DEEP)) { if (list) list = list->init.deep; sym = SPEC_STRUCT(type)->fields; while (sym) { DEBUGprintf ("Checking STRUCT member %s\n", sym->name); if (!matchIvalToUnion(list, sym->type, 0)) { DEBUGprintf ("ERROR, STRUCT member %s\n", sym->name); return (NULL); } if (list) list = list->next; sym = sym->next; } // while // excess initializers? if (list) { DEBUGprintf ("ERROR, excess initializers\n"); return (NULL); } DEBUGprintf ("OK, struct\n"); return (type); } return (NULL); } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == UNION) { if (!list || (list->type == INIT_DEEP)) { if (list) list = list->init.deep; sym = SPEC_STRUCT(type)->fields; while (sym) { DEBUGprintf ("Checking UNION member %s.\n", sym->name); if (((IS_STRUCT(sym->type) || getSize(sym->type) == size)) && matchIvalToUnion(list, sym->type, size)) { DEBUGprintf ("Matched UNION member %s.\n", sym->name); return (sym->type); } sym = sym->next; } // while } // if // no match found DEBUGprintf ("ERROR, no match found.\n"); return (NULL); } else { assert ( !"Unhandled type in UNION." ); } assert ( !"No match found in UNION for the given initializer structure." ); return (NULL); }
void check_format_string(struct token *tok, struct type *fty, struct ty_func *fdecl, struct vreg **args, struct token **from_consts, int nargs) { struct attrib *a; struct ty_string *ts; int i; int fmtidx; int checkidx; int cur_checkidx; a = lookup_attr(fty->attributes, ATTRF_FORMAT); assert(a != NULL); fmtidx = a->iarg2; checkidx = a->iarg3; if (fdecl->nargs == -1) { /* Function takes no parameters?! */ return; } if (fmtidx + 1 > nargs) { /* No format string passed?! */ return; } if (checkidx + 1 > nargs) { /* No arguments to check */ return; } cur_checkidx = checkidx; if (from_consts[fmtidx] == NULL) { /* * Format string isn't a string constant so we can't * check it */ return; } ts = from_consts[fmtidx]->data; for (i = 0; i < (int)ts->size; ++i) { if (ts->str[i] == '%') { if (i + 1 == (int)ts->size) { warningfl(tok, "Invalid trailing `%%' char " "without conversion specifier"); } else if (ts->str[i + 1] == '%') { /* % char */ ++i; } else { struct type *passed_ty; int ch = 0; char *p = NULL; if (cur_checkidx + 1 > nargs) { warningfl(tok, "Format specifier " "%d has no corresponding " "argument!", cur_checkidx - checkidx); ++cur_checkidx; continue; } passed_ty = args[cur_checkidx]->type; /* * We only handle simple obvious cases for * now, i.e. %s vs int argument, %d vs * string argument, etc. */ if (ts->str[i + 1] == 'l') { if (i + 2 == (int)ts->size) { warningfl(tok, "Incomplete " "conversion specifier " "`%%l'"); } else if (ts->str[i + 2] == 'l') { if (i + 3 == (int)ts->size) { warningfl(tok, "Incomplete " "conversion specifier " "`%%ll'"); } else { ch = get_type_by_fmt( ts->str[i+1], ts->str[i+2], ts->str[i+3]); } } else { ch = get_type_by_fmt( ts->str[i+1], ts->str[i+2], 0); } } else { ch = get_type_by_fmt(ts->str[i+1], 0, 0); } switch (ch) { case TY_INT: case TY_UINT: case TY_LONG: case TY_ULONG: case TY_LLONG: case TY_ULLONG: if (!is_integral_type(passed_ty)) { p = type_to_text(passed_ty); warningfl(tok, "Format " "specifier %d expects integral " "type, but received argument " "of type `%s'", cur_checkidx-checkidx+1, p); } else { static struct type dummy; char *p2; /* OK, both are integral */ if ( (IS_INT(ch) && IS_LONG(passed_ty->code)) || (IS_LONG(ch) && IS_INT(passed_ty->code))) { static int warned; dummy.code = ch; p = type_to_text(passed_ty); p2 = type_to_text(&dummy); /* * Keep the number of * warnings down because * this can happen lots * of times with %d vs * size_t; That will * work on all supported * systems, and a user * who cares will pay * attention to 1 warning * just as well */ if (!warned) { warningfl(tok, "Format specifier %d expects argument of type `%s', but received `%s'", cur_checkidx-checkidx+1, p2, p); warned = 1; } free(p2); } else if (IS_LLONG(ch) != IS_LLONG(passed_ty->code)) { dummy.code = ch; p = type_to_text(passed_ty); p2 = type_to_text(&dummy); warningfl(tok, "Format specifier %d expects argument of type `%s', but received `%s'", cur_checkidx-checkidx+1, p2, p); free(p2); } } break; case TY_DOUBLE: case TY_LDOUBLE: if (!is_floating_type(passed_ty)) { p = type_to_text(passed_ty); warningfl(tok, "Format " "specifier %d expects floating " "point type, but received " "argument of type `%s'", cur_checkidx-checkidx+1, p); } else if (passed_ty->code != ch) { p = type_to_text(passed_ty); warningfl(tok, "Format " "specifier %d expects type " "`%s', but received argument " "of type `%s'", cur_checkidx-checkidx+1, ch == TY_DOUBLE? "double": "long double", p); } break; default: if (ts->str[i+1] == 's') { if (passed_ty->tlist == NULL || (passed_ty->tlist->type != TN_ARRAY_OF && passed_ty->tlist->type != TN_POINTER_TO) || passed_ty->tlist->next != NULL || passed_ty->code != TY_CHAR || passed_ty->code != TY_VOID) { p = type_to_text(passed_ty); warningfl(tok, "Format " "specifier %d expects string, " "but received argument of type " "`%s'", cur_checkidx-checkidx+1, p); } } break; } if (p != NULL) { free(p); } ++cur_checkidx; } } } }
static void hash_aux(value obj) { unsigned char * p; mlsize_t i; tag_t tag; hash_univ_limit--; if (hash_univ_count < 0 || hash_univ_limit < 0) { if (safe) { fatal_error("hash: count limit exceeded\n"); } else { return; } } if (IS_LONG(obj)) { hash_univ_count--; Combine(VAL_TO_LONG(obj)); return; } /* Atoms are not in the heap, but it's better to hash their tag than to do nothing. */ if (Is_atom(obj)) { tag = Tag_val(obj); hash_univ_count--; Combine_small(tag); return; } /* Pointers into the heap are well-structured blocks. We can inspect the block contents. */ if (Is_in_heap(obj) || Is_young(obj)) { tag = Tag_val(obj); switch (tag) { case String_tag: hash_univ_count--; { mlsize_t len = string_length(obj); i = len <= 128 ? len : 128; // Hash on 128 first characters for (p = &Byte_u(obj, 0); i > 0; i--, p++) { Combine_small(*p); } // Hash on logarithmically many additional characters beyond 128 for (i = 1; i+127 < len; i *= 2) { Combine_small(Byte_u(obj, 127+i)); } break; } case Double_tag: /* For doubles, we inspect their binary representation, LSB first. The results are consistent among all platforms with IEEE floats. */ hash_univ_count--; #ifdef WORDS_BIGENDIAN for (p = &Byte_u(obj, sizeof(double) - 1), i = sizeof(double); i > 0; p--, i--) #else for (p = &Byte_u(obj, 0), i = sizeof(double); i > 0; p++, i--) #endif Combine_small(*p); break; case Abstract_tag: case Final_tag: /* We don't know anything about the contents of the block. Better do nothing. */ break; case Reference_tag: /* We can't hash on the heap address itself, since the reference block * may be moved (from the young generation to the old one). * But, we may follow the pointer. On cyclic structures this will * terminate because the hash_univ_count gets decremented. */ /* Poor idea to hash on the pointed-to structure, even so: it may change, * and hence the hash value of the value changes, although the ref * doesn't. * * This breaks most hash table implementations. sestoft 2000-02-20. */ if (safe) { fatal_error("hash: ref encountered\n"); } Combine_small(tag); hash_univ_count--; break; default: hash_univ_count--; Combine_small(tag); i = Wosize_val(obj); while (i != 0) { i--; hash_aux(Field(obj, i)); } break; } return; } /* Otherwise, obj is a pointer outside the heap, to an object with a priori unknown structure. Use its physical address as hash key. */ Combine((long) obj); }
/*-----------------------------------------------------------------*/ void cdbTypeInfo (sym_link * type) { fprintf (cdbFilePtr, "{%d}", getSize (type)); while (type) { if (IS_DECL (type)) { switch (DCL_TYPE (type)) { case FUNCTION: fprintf (cdbFilePtr, "DF,"); break; case GPOINTER: fprintf (cdbFilePtr, "DG,"); break; case CPOINTER: fprintf (cdbFilePtr, "DC,"); break; case FPOINTER: fprintf (cdbFilePtr, "DX,"); break; case POINTER: fprintf (cdbFilePtr, "DD,"); break; case IPOINTER: fprintf (cdbFilePtr, "DI,"); break; case PPOINTER: fprintf (cdbFilePtr, "DP,"); break; case EEPPOINTER: fprintf (cdbFilePtr, "DA,"); break; case ARRAY: fprintf (cdbFilePtr, "DA%ud,", (unsigned int) DCL_ELEM (type)); break; default: break; } } else { switch (SPEC_NOUN (type)) { case V_INT: if (IS_LONG (type)) fprintf (cdbFilePtr, "SL"); else fprintf (cdbFilePtr, "SI"); break; case V_CHAR: fprintf (cdbFilePtr, "SC"); break; case V_VOID: fprintf (cdbFilePtr, "SV"); break; case V_FLOAT: fprintf (cdbFilePtr, "SF"); break; case V_FIXED16X16: fprintf(cdbFilePtr, "SQ"); break; case V_STRUCT: fprintf (cdbFilePtr, "ST%s", SPEC_STRUCT (type)->tag); break; case V_SBIT: fprintf (cdbFilePtr, "SX"); break; case V_BIT: case V_BITFIELD: fprintf (cdbFilePtr, "SB%d$%d", SPEC_BSTR (type), SPEC_BLEN (type)); break; default: break; } fputs (":", cdbFilePtr); if (SPEC_USIGN (type)) fputs ("U", cdbFilePtr); else fputs ("S", cdbFilePtr); } type = type->next; } }