static void type_add_str_pre( type *r, int *need_paren, int *need_spc, char **bufp, int *sz) { type *prev_skipped; enum type_qualifier q = qual_none; /* int (**fn())[2] * btype -> array -> ptr -> ptr -> func * ^ parens * * .tmp looks right, down the chain, .ref looks left, up the chain */ *need_paren = r->ref && IS_PTR(r->type) && (prev_skipped = type_skip_all(r->ref))->type != type_btype && !IS_PTR(prev_skipped->type); if(*need_paren){ ADD_SPC(); BUF_ADD("("); } switch(r->type){ case type_ptr: #ifdef SHOW_DECAYED_ARRAYS if(r->bits.ptr.size) break; /* decayed array */ #endif ADD_SPC(); BUF_ADD("*"); break; case type_cast: q = r->bits.cast.qual; break; case type_block: ADD_SPC(); BUF_ADD("^"); break; default:break; } if(q){ ADD_SPC(); BUF_ADD("%s", type_qual_to_str(q, 0)); *need_spc = 1; /* space out after qualifier, e.g. * int *const p; * ^ * int const a; * ^ */ } }
type *type_called(type *functy, struct funcargs **pfuncargs) { functy = type_skip_all(functy); assert(functy->type == type_func); if(pfuncargs) *pfuncargs = functy->bits.func.args; return functy->ref; }
const char *type_to_str_r_show_decayed(char buf[TYPE_STATIC_BUFSIZ], struct type *r) { r = type_skip_all(r); if(r->type == type_ptr && r->bits.ptr.decayed_from) r = r->bits.ptr.decayed_from; return type_to_str_r(buf, r); }
static const out_val *vla_cached_size(type *const qual_t, out_ctx *octx) { type *t = type_skip_all(qual_t); struct cc1_out_ctx **cc1_octx = cc1_out_ctx(octx); dynmap *vlamap; if(*cc1_octx && (vlamap = (*cc1_octx)->vlamap)){ const out_val *stack_off = dynmap_get(type *, const out_val *, vlamap, t); if(stack_off){ out_comment(octx, "vla saved size for %s", type_to_str(qual_t)); out_val_retain(octx, stack_off); return out_deref(octx, stack_off); } } return NULL; }
static enum type_cmp type_cmp_r( type *const orig_a, type *const orig_b, enum type_cmp_opts opts) { enum type_cmp ret; type *a, *b; int subchk = 1; if(!orig_a || !orig_b) return orig_a == orig_b ? TYPE_EQUAL : TYPE_NOT_EQUAL; a = type_skip_all(orig_a); b = type_skip_all(orig_b); /* array/func decay takes care of any array->ptr checks */ if(a->type != b->type){ /* allow _Bool <- pointer */ if(type_is_primitive(a, type__Bool) && type_is_ptr(b)) return TYPE_CONVERTIBLE_IMPLICIT; /* allow int <-> ptr (or block) */ if((type_is_ptr_or_block(a) && type_is_integral(b)) || (type_is_ptr_or_block(b) && type_is_integral(a))) { return TYPE_CONVERTIBLE_EXPLICIT; } /* allow void <- anything */ if(type_is_void(a)) return TYPE_CONVERTIBLE_IMPLICIT; /* allow block <-> fnptr */ if((type_is_fptr(a) && type_is(b, type_block)) || (type_is_fptr(b) && type_is(a, type_block))) { return TYPE_CONVERTIBLE_EXPLICIT; } return TYPE_NOT_EQUAL; } switch(a->type){ case type_auto: ICE("__auto_type"); case type_btype: subchk = 0; ret = btype_cmp(a->bits.type, b->bits.type); break; case type_array: if(a->bits.array.is_vla || b->bits.array.is_vla){ /* fine, pretend they're equal even if different expressions */ ret = TYPE_EQUAL_TYPEDEF; }else{ const int a_has_sz = !!a->bits.array.size; const int b_has_sz = !!b->bits.array.size; if(a_has_sz && b_has_sz){ integral_t av = const_fold_val_i(a->bits.array.size); integral_t bv = const_fold_val_i(b->bits.array.size); if(av != bv) return TYPE_NOT_EQUAL; }else if(a_has_sz != b_has_sz){ if((opts & TYPE_CMP_ALLOW_TENATIVE_ARRAY) == 0) return TYPE_NOT_EQUAL; } } /* next */ break; case type_block: case type_ptr: break; case type_cast: case type_tdef: case type_attr: case type_where: ICE("should've been skipped"); case type_func: switch(funcargs_cmp(a->bits.func.args, b->bits.func.args)){ case FUNCARGS_EXACT_EQUAL: case FUNCARGS_IMPLICIT_CONV: break; default: /* "void (int)" and "void (int, int)" aren't equal, * but a cast can soon fix it */ return TYPE_CONVERTIBLE_EXPLICIT; } break; } if(subchk) ret = type_cmp_r(a->ref, b->ref, opts); if(ret == TYPE_NOT_EQUAL && a->type == type_func) { /* "int (int)" and "void (int)" aren't equal - but castable */ ret = TYPE_CONVERTIBLE_EXPLICIT; } if(ret == TYPE_NOT_EQUAL && a->type == type_ptr && fopt_mode & FOPT_PLAN9_EXTENSIONS) { /* allow b to be an anonymous member of a, if pointers */ struct_union_enum_st *a_sue = type_is_s_or_u(a), *b_sue = type_is_s_or_u(b); if(a_sue && b_sue /* already know they aren't equal */){ /* b_sue has an a_sue, * the implicit cast adjusts to return said a_sue */ if(struct_union_member_find_sue(b_sue, a_sue)) return TYPE_CONVERTIBLE_IMPLICIT; } } /* allow ptr <-> ptr */ if(ret == TYPE_NOT_EQUAL && type_is_ptr(a) && type_is_ptr(b)) ret = TYPE_CONVERTIBLE_EXPLICIT; /* char * and int * are explicitly conv., * even though char and int are implicit */ if(ret == TYPE_CONVERTIBLE_IMPLICIT && a->type == type_ptr) ret = TYPE_CONVERTIBLE_EXPLICIT; if(a->type == type_ptr || a->type == type_block){ switch(ret){ #define MAP(a, b) case a: ret = b; break MAP(TYPE_QUAL_ADD, TYPE_QUAL_POINTED_ADD); MAP(TYPE_QUAL_SUB, TYPE_QUAL_POINTED_SUB); MAP(TYPE_QUAL_POINTED_ADD, TYPE_QUAL_NESTED_CHANGE); MAP(TYPE_QUAL_POINTED_SUB, TYPE_QUAL_NESTED_CHANGE); #undef MAP default: break; } } if(ret & TYPE_EQUAL_ANY){ enum type_qualifier a_qual = type_qual(orig_a); enum type_qualifier b_qual = type_qual(orig_b); if(a_qual && b_qual){ switch(type_qual_cmp(a_qual, b_qual)){ case -1: /* a has more */ ret = TYPE_QUAL_ADD; break; case 1: /* b has more */ ret = TYPE_QUAL_SUB; break; } }else if(a_qual){ ret = TYPE_QUAL_ADD; }else if(b_qual){ ret = TYPE_QUAL_SUB; } /* else neither are casts */ } if(ret == TYPE_EQUAL){ int at = orig_a->type == type_tdef; int bt = orig_b->type == type_tdef; if(at != bt){ /* one is a typedef */ ret = TYPE_EQUAL_TYPEDEF; }else if(at){ /* both typedefs */ if(orig_a->bits.tdef.decl != orig_b->bits.tdef.decl){ ret = TYPE_EQUAL_TYPEDEF; } } /* else no typedefs */ } return ret; }