static int check_arg_counts( funcargs *args_from_decl, unsigned count_decl, expr **exprargs, expr *fnexpr, char *sp) { where *const loc = &fnexpr->where; /* this block is purely count checking */ if(!FUNCARGS_EMPTY_NOVOID(args_from_decl)){ const unsigned count_arg = dynarray_count(exprargs); if(count_decl != count_arg && (args_from_decl->variadic ? count_arg < count_decl : 1)) { decl *call_decl; /* may be args_old_proto but also args_void if copied from * another prototype elsewhere */ int warn = args_from_decl->args_old_proto && !args_from_decl->args_void; int warning_emitted = 1; #define common_warning \ "too %s arguments to function %s%s(got %d, need %d)",\ count_arg > count_decl ? "many" : "few", \ sp ? sp : "", \ sp ? " " : "", \ count_arg, count_decl if(warn){ warning_emitted = cc1_warn_at(loc, funcall_argcount, common_warning); }else{ warn_at_print_error(loc, common_warning); } #undef common_warning if(warning_emitted && (call_decl = expr_to_declref(fnexpr->expr, NULL))) { note_at(&call_decl->where, "'%s' declared here", call_decl->spel); } if(!warn){ fold_had_error = 1; return 1; } } }else if(args_from_decl->args_void_implicit && exprargs){ cc1_warn_at(loc, funcall_argcount, "too many arguments to implicitly (void)-function"); } return 0; }
static void static_array_check( decl *arg_decl, expr *arg_expr) { /* if ty_func is x[static %d], check counts */ type *ty_expr = arg_expr->tree_type; type *ty_decl = decl_is_decayed_array(arg_decl); consty k_decl; if(!ty_decl) return; assert(ty_decl->type == type_array); if(!ty_decl->bits.array.is_static) return; /* want to check any pointer type */ if(expr_is_null_ptr(arg_expr, NULL_STRICT_ANY_PTR)){ cc1_warn_at(&arg_expr->where, attr_nonnull, "passing null-pointer where array expected"); return; } if(!ty_decl->bits.array.size) return; const_fold(ty_decl->bits.array.size, &k_decl); if((ty_expr = type_is_decayed_array(ty_expr))){ assert(ty_expr->type == type_array); if(ty_expr->bits.array.size){ consty k_arg; const_fold(ty_expr->bits.array.size, &k_arg); if(k_decl.type == CONST_NUM && K_INTEGRAL(k_arg.bits.num) && k_arg.bits.num.val.i < k_decl.bits.num.val.i) { cc1_warn_at(&arg_expr->where, static_array_bad, "array of size %" NUMERIC_FMT_D " passed where size %" NUMERIC_FMT_D " needed", k_arg.bits.num.val.i, k_decl.bits.num.val.i); } } } /* else it's a random pointer, just be quiet */ }
int symtab_fold(symtable *tab, int current) { const int this_start = current; if(tab->decls){ const int word_size = platform_word_size(); decl **diter; int arg_offset; arg_offset = 0; /* need to walk backwards for args */ for(diter = tab->decls; *diter; diter++); for(diter--; diter >= tab->decls; diter--){ sym *s = (*diter)->sym; /*enum type_primitive last = type_int; TODO: packing */ if(s->type == sym_local && (s->decl->type->spec & (spec_extern | spec_static)) == 0){ int siz = decl_size(s->decl); if(siz <= word_size) s->offset = current; else s->offset = current + siz - word_size; /* an array and structs start at the bottom */ /* need to increase by a multiple of word_size */ if(siz % word_size) siz += word_size - siz % word_size; current += siz; /* static analysis on sym (only auto-vars) */ if(s->nwrites == 0 && !decl_has_array(s->decl)){ cc1_warn_at(&s->decl->where, 0, WARN_SYM_NEVER_WRITTEN, "\"%s\" never written to", s->decl->spel); s->nwrites++; /* only warn once */ } }else if(s->type == sym_arg){ s->offset = arg_offset; arg_offset += word_size; } } } { symtable **tabi; int subtab_max = 0; for(tabi = tab->children; tabi && *tabi; tabi++){ int this = symtab_fold(*tabi, current); if(this > subtab_max) subtab_max = this; } tab->auto_total_size = current - this_start + subtab_max; } return tab->auto_total_size; }
static attribute *parse_attr_single(const char *ident, symtable *scope) { symtable_global *glob; int i; where attrloc; for(i = 0; attrs[i].ident; i++) { char buf[MAX_FMT_LEN]; if(!strcmp(attrs[i].ident, ident) || (snprintf(buf, sizeof buf, "__%s__", attrs[i].ident), !strcmp(buf, ident))) { return attrs[i].parser(scope, attrs[i].ident); } } where_cc1_current(&attrloc); attrloc.chr -= strlen(ident); /* unrecognised - only do the warning (and map checking) if non system-header */ if(cc1_warning.system_headers || !where_in_sysheader(&attrloc)) { glob = symtab_global(scope); if(!dynmap_exists(char *, glob->unrecog_attrs, (char *)ident)) { char *dup = ustrdup(ident); if(!glob->unrecog_attrs) glob->unrecog_attrs = dynmap_new(char *, strcmp, dynmap_strhash); dynmap_set(char *, void *, glob->unrecog_attrs, dup, NULL); cc1_warn_at(&attrloc, attr_unknown, "ignoring unrecognised attribute \"%s\"", ident); } }
static attribute *parse_attr_section(symtable *symtab, const char *ident) { /* __attribute__((section ("sectionname"))) */ attribute *da; char *func; size_t len, i; (void)symtab; (void)ident; EAT(token_open_paren); if(curtok != token_string) die_at(NULL, "string expected for section"); token_get_current_str(&func, &len, NULL, NULL); EAT(token_string); for(i = 0; i < len; i++) if(!isprint(func[i])) { if(i < len - 1 || func[i] != '\0') cc1_warn_at(NULL, attr_section_badchar, "character 0x%x detected in section", func[i]); break; } da = attribute_new(attr_section); da->bits.section = func; EAT(token_close_paren); return da; }
static void check_arg_voidness_and_nonnulls( expr *callexpr, symtable *stab, funcargs *args_from_decl, unsigned count_decl, expr **exprargs, char *sp) { /* this block folds the args and type-checks */ unsigned long nonnulls = 0; unsigned i; attribute *da; if((da = func_or_builtin_attr_present(callexpr, attr_nonnull))) nonnulls = da->bits.nonnull_args; for(i = 0; exprargs[i]; i++){ expr *arg = FOLD_EXPR(exprargs[i], stab); char buf[64]; ARG_BUF(buf, i, sp); if(fold_check_expr(arg, FOLD_CHK_NO_ST_UN, buf)) continue; if(i < count_decl && (nonnulls & (1 << i)) && type_is_ptr(args_from_decl->arglist[i]->ref) && expr_is_null_ptr(arg, NULL_STRICT_INT)) { cc1_warn_at(&arg->where, attr_nonnull, "null passed where non-null required (arg %d)", i + 1); } } }
void token_get_current_str( char **ps, size_t *pl, int *pwide, where *w) { extern char *currentstring; extern size_t currentstringlen; extern int currentstringwide; *ps = currentstring; if(pwide) *pwide = currentstringwide; else if(currentstringwide) die_at(NULL, "wide string not wanted"); if(w){ extern where currentstringwhere; memcpy_safe(w, ¤tstringwhere); } if(pl){ *pl = currentstringlen; }else{ char *p = memchr(currentstring, '\0', currentstringlen); if(p && p < currentstring + currentstringlen - 1) cc1_warn_at(NULL, str_contain_nul, "nul-character terminates string early (%s)", p + 1); } currentstring = NULL; currentstringlen = 0; }
static void handle_pragma_stdc(const char *pragma, where *loc) { /* * #pragma STDC FP_CONTRACT <arg> * #pragma STDC FENV_ACCESS <arg> * #pragma STDC CX_LIMITED_RANGE <arg> */ cc1_warn_at(loc, unknown_pragma, "unhandled STDC pragma '%s'", pragma); }
static void check_implicit_funcall(expr *e, symtable *stab, char **const psp) { struct symtab_entry ent; funcargs *args; decl *df, *owning_func; type *func_ty; if(e->expr->in_parens || !expr_kind(e->expr, identifier) /* not folded yet, hence no 'e->expr->bits.ident.type != IDENT_NORM' */ /* get the spel that parse stashes in the identifier expr: */ || !((*psp) = e->expr->bits.ident.bits.ident.spel)) { return; } /* check for implicit function */ if(symtab_search(stab, *psp, NULL, &ent) && ent.type == SYMTAB_ENT_DECL) { e->expr->bits.ident.bits.ident.sym = ent.bits.decl->sym; return; } args = funcargs_new(); /* set up the funcargs as if it's "x()" - i.e. any args */ funcargs_empty(args); func_ty = type_func_of( type_nav_btype(cc1_type_nav, type_int), args, symtab_new(stab, &e->where) /*new symtable for args*/); cc1_warn_at(&e->expr->where, implicit_func, "implicit declaration of function \"%s\"", *psp); df = decl_new(); memcpy_safe(&df->where, &e->where); df->ref = func_ty; df->spel = e->expr->bits.ident.bits.ident.spel; df->flags |= DECL_FLAGS_IMPLICIT; fold_decl(df, stab); /* update calling conv, for e.g. */ df->sym->type = sym_global; e->expr->bits.ident.bits.ident.sym = df->sym; e->expr->tree_type = func_ty; owning_func = symtab_func(stab); if(owning_func) symtab_insert_before(symtab_root(stab), owning_func, df); else symtab_add_to_scope(symtab_root(stab), df); /* function call at global scope */ }
void fold_expr_compound_lit(expr *e, symtable *stab) { decl *d = e->bits.complit.decl; int static_ctx = e->bits.complit.static_ctx; /* global or static */ if(cc1_std < STD_C99) cc1_warn_at(&e->where, c89_compound_literal, "compound literals are a C99 feature"); /* if(!stab->parent) assert(static_ctx); * * except things like sizeof() just pass 0 for static_ctx, * as it doesn't matter, we're not code-gen'd */ if(!stab->parent) static_ctx = 1; if(COMP_LIT_INITIALISED(e)) return; /* being called from fold_gen_init_assignment_base */ /* must be set before the recursive fold_gen_init_assignment_base */ e->tree_type = d->ref; if(static_ctx){ assert(!d->spel_asm); d->spel_asm = out_label_data_store(STORE_COMP_LIT); d->store = store_static; } e->bits.complit.sym = sym_new_and_prepend_decl( stab, d, static_ctx ? sym_global : sym_local); /* fold the initialiser */ UCC_ASSERT(d->bits.var.init.dinit, "no init for comp.literal"); decl_init_brace_up_fold(d, stab); /* * update the type, for example if an array type has been completed * this is done before folds, for array bounds checks */ e->tree_type = d->ref; if(!static_ctx){ /* create the code for assignemnts * * - we must create a nested scope, * otherwise any other decls in stab's scope will * be generated twice - once for the scope we're nested in (stab), * and again on our call to gen_stmt() in our gen function */ decl_init_create_assignments_base_and_fold(d, e, stab); }else{ fold_decl_global_init(d, stab); } }
static void handle_pragma_ucc(const char *pragma, where *loc) { if(!strncmp(pragma, "namespace ", 10)){ free(ucc_namespace); ucc_namespace = ustrdup(pragma + 10); fprintf(stderr, "namespace \"%s\"\n", ucc_namespace); }else{ cc1_warn_at(loc, unknown_pragma, "unknown ucc pragma '%s'", pragma); } }
static attribute *parse_attr_format(symtable *symtab, const char *ident) { /* __attribute__((format (printf, fmtarg, firstvararg))) */ attribute *da; char *func; enum fmt_type fmt; (void)symtab; (void)ident; EAT(token_open_paren); func = token_current_spel(); EAT(token_identifier); /* TODO: token_current_spel() * and token_get_current_str(..,..) * checks everywhere */ if(!func) return NULL; #define CHECK(s) !strcmp(func, s) || !strcmp(func, "__" s "__") if(CHECK("printf")) { fmt = attr_fmt_printf; } else if(CHECK("scanf")) { fmt = attr_fmt_scanf; } else { cc1_warn_at(NULL, attr_format_unknown, "unknown format func \"%s\"", func); parse_attr_bracket_chomp(1); return NULL; } da = attribute_new(attr_format); da->bits.format.fmt_func = fmt; EAT(token_comma); da->bits.format.fmt_idx = currentval.val.i - 1; EAT(token_integer); EAT(token_comma); da->bits.format.var_idx = currentval.val.i - 1; EAT(token_integer); EAT(token_close_paren); return da; }
static attribute *parse_attr_nonnull(symtable *symtab, const char *ident) { /* __attribute__((nonnull(1, 2, 3, 4...))) * or * __attribute__((nonnull)) - all args */ attribute *da = attribute_new(attr_nonnull); unsigned long l = 0; int had_error = 0; (void)symtab; (void)ident; if(accept(token_open_paren)) { while(curtok != token_close_paren) { if(curtok == token_integer) { int n = currentval.val.i; if(n <= 0) { /* shouldn't ever be negative */ cc1_warn_at(NULL, attr_nonnull_bad, "%s nonnull argument ignored", n < 0 ? "negative" : "zero"); had_error = 1; } else { /* implicitly disallow functions with >32 args */ /* n-1, since we convert from 1-base to 0-base */ l |= 1 << (n - 1); } } else { EAT(token_integer); /* raise error */ } EAT(curtok); if(accept(token_comma)) continue; break; } EAT(token_close_paren); } /* if we had an error, go with what we've got, (even if it's nothing), to avoid spurious warnings */ da->bits.nonnull_args = (l || had_error) ? l : ~0UL; /* all if 0 */ return da; }
static void warn_value_changed_at( where *w, const char *infmt, int signed_in, int signed_out, integral_t a, integral_t b) { char *fmt = ustrdup(infmt); char *p = fmt; for(;;){ p = strchr(p, '%'); if(!p) break; p += 3; if(*p == 'A' || *p == 'B'){ *p = (*p == 'A' ? signed_in : signed_out) ? 'd' : 'u'; } } cc1_warn_at(w, overflow, fmt, a, b); free(fmt); }
void pragma_handle(const char *pragma, where *loc) { if(!strncmp(pragma, "STDC", 4)){ handle_pragma_stdc(str_spc_skip(pragma + 4), loc); }else if(!strncmp(pragma, "ucc", 3)){ handle_pragma_ucc(str_spc_skip(pragma + 3), loc); }else{ /* * #pragma GCC visibility <arg> * #pragma align <arg> * #pragma pack <arg> * #pragma section <arg> * #pragma unused <arg> * #pragma weak <arg> * #pragma attribute <arg> */ cc1_warn_at(loc, unknown_pragma, "unknown pragma '%s'", pragma); } }
void bitfield_trunc_check(decl *mem, expr *from) { consty k; if(expr_kind(from, cast)){ /* we'll warn about bitfield truncation, prevent warnings * about cast truncation */ from->expr_cast_implicit = 0; } const_fold(from, &k); if(k.type == CONST_NUM){ const sintegral_t kexp = k.bits.num.val.i; /* highest may be -1 - kexp is zero */ const int highest = integral_high_bit(k.bits.num.val.i, from->tree_type); const int is_signed = type_is_signed(mem->bits.var.field_width->tree_type); const_fold(mem->bits.var.field_width, &k); UCC_ASSERT(k.type == CONST_NUM, "bitfield size not val?"); UCC_ASSERT(K_INTEGRAL(k.bits.num), "fp bitfield size?"); if(highest > (sintegral_t)k.bits.num.val.i || (is_signed && highest == (sintegral_t)k.bits.num.val.i)) { sintegral_t kexp_to = kexp & ~(-1UL << k.bits.num.val.i); cc1_warn_at(&from->where, bitfield_trunc, "truncation in store to bitfield alters value: " "%" NUMERIC_FMT_D " -> %" NUMERIC_FMT_D, kexp, kexp_to); } } }
static void try_pointer_propagate( expr *e, enum type_cmp cmp, type *const tt_l, type *const tt_r) { /* 6.5.15 p6 */ int l_ptr = !!type_is_ptr_or_block(tt_l); int r_ptr = !!type_is_ptr_or_block(tt_r); /* if both the second and third operands are pointers */ if(l_ptr && r_ptr){ int allowed = TYPE_EQUAL_ANY | TYPE_QUAL_ADD | TYPE_QUAL_SUB | TYPE_QUAL_POINTED_ADD | TYPE_QUAL_POINTED_SUB; if(cmp & allowed){ e->tree_type = pointer_to_qualified(type_next(tt_l), tt_l, tt_r); } } if(!e->tree_type && (l_ptr || r_ptr)){ /* or one is a null pointer constant and the other is a pointer */ int l_ptr_null = expr_is_null_ptr( e->lhs ? e->lhs : e->expr, NULL_STRICT_INT); int r_ptr_null = expr_is_null_ptr(e->rhs, NULL_STRICT_INT); /* both may still be pointers here */ if((l_ptr && r_ptr_null) || (r_ptr && l_ptr_null)){ type *pointed_to; if(l_ptr_null != r_ptr_null){ /* only one is an int - pick the other side */ pointed_to = type_next(l_ptr_null ? tt_r : tt_l); }else{ /* both are pointers, pick either side */ pointed_to = type_next(l_ptr ? tt_l : tt_r); } e->tree_type = pointer_to_qualified( pointed_to, l_ptr ? tt_l : NULL, r_ptr ? tt_r : NULL); } } if(!e->tree_type && l_ptr && r_ptr){ e->tree_type = pointer_to_qualified( type_nav_btype(cc1_type_nav, type_void), tt_l, tt_r); /* gcc/clang relax the rule here. * 0 ? (A *)0 : (B *)0 * becomes a void pointer too */ if(!type_is_void_ptr(tt_l) && !type_is_void_ptr(tt_r)){ char buf[TYPE_STATIC_BUFSIZ]; cc1_warn_at(&e->where, mismatch_conditional, "conditional type mismatch (%s vs %s)", type_to_str(tt_l), type_to_str_r(buf, tt_r)); } } if(!e->tree_type){ char buf[TYPE_STATIC_BUFSIZ]; warn_at_print_error(&e->where, "conditional type mismatch (%s vs %s)", type_to_str(tt_l), type_to_str_r(buf, tt_r)); fold_had_error = 1; e->tree_type = type_nav_btype(cc1_type_nav, type_void); } }
void fold_expr_funcall(expr *e, symtable *stab) { type *func_ty; funcargs *args_from_decl; char *sp = NULL; unsigned count_decl; check_implicit_funcall(e, stab, &sp); FOLD_EXPR(e->expr, stab); func_ty = e->expr->tree_type; if(!type_is_callable(func_ty)){ warn_at_print_error(&e->expr->where, "%s-expression (type '%s') not callable", expr_str_friendly(e->expr, 0), type_to_str(func_ty)); fold_had_error = 1; e->tree_type = type_nav_btype(cc1_type_nav, type_int); return; } e->tree_type = type_func_call(func_ty, &args_from_decl); /* func count comparison, only if the func has arg-decls, or the func is f(void) */ UCC_ASSERT(args_from_decl, "no funcargs for decl %s", sp); count_decl = dynarray_count(args_from_decl->arglist); if(check_arg_counts(args_from_decl, count_decl, e->funcargs, e, sp)) return; if(e->funcargs){ check_arg_voidness_and_nonnulls( e, stab, args_from_decl, count_decl, e->funcargs, sp); } if(!FUNCARGS_EMPTY_NOVOID(args_from_decl)) check_arg_types(args_from_decl, e->funcargs, stab, sp, &e->where); if(e->funcargs) default_promote_args(e->funcargs, count_decl, stab); if(type_is_s_or_u(e->tree_type)){ /* handled transparently by the backend */ e->f_islval = expr_is_lval_struct; cc1_warn_at(&e->expr->where, aggregate_return, "called function returns aggregate (%s)", type_to_str(e->tree_type)); } /* attr */ { type *fnty = e->expr->tree_type; /* look through decays */ if(expr_kind(e->expr, cast) && expr_cast_is_lval2rval(e->expr)) fnty = expr_cast_child(e->expr)->tree_type; format_check_call(fnty, e->funcargs, args_from_decl->variadic); sentinel_check( &e->where, e, e->funcargs, args_from_decl->variadic, count_decl, stab); } /* check the subexp tree type to get the funcall attributes */ if(func_or_builtin_attr_present(e, attr_warn_unused)) e->freestanding = 0; /* needs use */ if(sp && !cc1_fopt.freestanding) check_standard_funcs(sp, e->funcargs); }
void fold_expr_funcall(expr *e, symtable *stab) { decl *df; funcargs *args_exp; if(expr_kind(e->expr, identifier) && e->expr->spel){ char *const sp = e->expr->spel; e->sym = symtab_search(stab, sp); if(!e->sym){ df = decl_new_where(&e->where); df->type->primitive = type_int; df->type->spec |= spec_extern; cc1_warn_at(&e->where, 0, WARN_IMPLICIT_FUNC, "implicit declaration of function \"%s\"", sp); df->spel = sp; df->funcargs = funcargs_new(); if(e->funcargs) /* set up the funcargs as if it's "x()" - i.e. any args */ function_empty_args(df->funcargs); e->sym = symtab_add(symtab_root(stab), df, sym_global, SYMTAB_WITH_SYM, SYMTAB_PREPEND); }else{ df = e->sym->decl; } fold_expr(e->expr, stab); }else{ fold_expr(e->expr, stab); /* * convert int (*)() to remove the deref */ if(decl_is_func_ptr(e->expr->tree_type)){ /* XXX: memleak */ e->expr = e->expr->lhs; fprintf(stderr, "FUNCPTR\n"); }else{ fprintf(stderr, "decl %s\n", decl_to_str(e->expr->tree_type)); } df = e->expr->tree_type; if(!decl_is_callable(df)){ die_at(&e->expr->where, "expression %s (%s) not callable", e->expr->f_str(), decl_to_str(df)); } } e->tree_type = decl_copy(df); /* * int (*x)(); * (*x)(); * evaluates to tree_type = int; */ decl_func_deref(e->tree_type); if(e->funcargs){ expr **iter; for(iter = e->funcargs; *iter; iter++) fold_expr(*iter, stab); } /* func count comparison, only if the func has arg-decls, or the func is f(void) */ args_exp = decl_funcargs(e->tree_type); UCC_ASSERT(args_exp, "no funcargs for decl %s", df->spel); if(args_exp->arglist || args_exp->args_void){ expr **iter_arg; decl **iter_decl; int count_decl, count_arg; count_decl = count_arg = 0; for(iter_arg = e->funcargs; iter_arg && *iter_arg; iter_arg++, count_arg++); for(iter_decl = args_exp->arglist; iter_decl && *iter_decl; iter_decl++, count_decl++); if(count_decl != count_arg && (args_exp->variadic ? count_arg < count_decl : 1)){ die_at(&e->where, "too %s arguments to function %s (got %d, need %d)", count_arg > count_decl ? "many" : "few", df->spel, count_arg, count_decl); } if(e->funcargs){ funcargs *argument_decls = funcargs_new(); for(iter_arg = e->funcargs; *iter_arg; iter_arg++) dynarray_add((void ***)&argument_decls->arglist, (*iter_arg)->tree_type); fold_funcargs_equal(args_exp, argument_decls, 1, &e->where, "argument", df->spel); funcargs_free(argument_decls, 0); } } }