/* * T_WHILE T_LPARN expr T_RPARN */ void while1(tnode_t *tn) { if (!reached) { /* loop not entered at top */ warning(207); reached = 1; } if (tn != NULL) tn = cconv(tn); if (tn != NULL) tn = promote(NOOP, 0, tn); if (tn != NULL && !issclt(tn->tn_type->t_tspec)) { /* controlling expressions must have scalar type */ error(204); tn = NULL; } pushctrl(T_WHILE); cstk->c_loop = 1; if (tn != NULL && tn->tn_op == CON) { if (isityp(tn->tn_type->t_tspec)) { cstk->c_infinite = tn->tn_val->v_quad != 0; } else { cstk->c_infinite = tn->tn_val->v_ldbl != 0.0; } } expr(tn, 0, 1); }
/* * T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN */ void for1(tnode_t *tn1, tnode_t *tn2, tnode_t *tn3) { /* * If there is no initialisation expression it is possible that * it is intended not to enter the loop at top. */ if (tn1 != NULL && !reached) { /* loop not entered at top */ warning(207); reached = 1; } pushctrl(T_FOR); cstk->c_loop = 1; /* * Store the tree memory for the reinitialisation expression. * Also remember this expression itself. We must check it at * the end of the loop to get "used but not set" warnings correct. */ cstk->c_fexprm = tsave(); cstk->c_f3expr = tn3; STRUCT_ASSIGN(cstk->c_fpos, curr_pos); STRUCT_ASSIGN(cstk->c_cfpos, csrc_pos); if (tn1 != NULL) expr(tn1, 0, 0); if (tn2 != NULL) tn2 = cconv(tn2); if (tn2 != NULL) tn2 = promote(NOOP, 0, tn2); if (tn2 != NULL && !issclt(tn2->tn_type->t_tspec)) { /* controlling expressions must have scalar type */ error(204); tn2 = NULL; } if (tn2 != NULL) expr(tn2, 0, 1); if (tn2 == NULL) { cstk->c_infinite = 1; } else if (tn2->tn_op == CON) { if (isityp(tn2->tn_type->t_tspec)) { cstk->c_infinite = tn2->tn_val->v_quad != 0; } else { cstk->c_infinite = tn2->tn_val->v_ldbl != 0.0; } } /* Checking the reinitialisation expression is done in for2() */ reached = 1; }
/* * T_SWITCH T_LPARN expr T_RPARN */ void switch1(tnode_t *tn) { tspec_t t; type_t *tp; if (tn != NULL) tn = cconv(tn); if (tn != NULL) tn = promote(NOOP, 0, tn); if (tn != NULL && !isityp(tn->tn_type->t_tspec)) { /* switch expression must have integral type */ error(205); tn = NULL; } if (tn != NULL && tflag) { t = tn->tn_type->t_tspec; if (t == LONG || t == ULONG || t == QUAD || t == UQUAD) { /* switch expr. must be of type `int' in trad. C */ warning(271); } } /* * Remember the type of the expression. Because its possible * that (*tp) is allocated on tree memory the type must be * duplicated. This is not too complicated because it is * only an integer type. */ if ((tp = calloc(1, sizeof (type_t))) == NULL) nomem(); if (tn != NULL) { tp->t_tspec = tn->tn_type->t_tspec; if ((tp->t_isenum = tn->tn_type->t_isenum) != 0) tp->t_enum = tn->tn_type->t_enum; } else { tp->t_tspec = INT; } expr(tn, 1, 0); pushctrl(T_SWITCH); cstk->c_switch = 1; cstk->c_swtype = tp; reached = rchflg = 0; ftflg = 1; }
/* * do stmnt do_while_expr * do error */ void do2(tnode_t *tn) { /* * If there was a continue statement the expression controlling the * loop is reached. */ if (cstk->c_cont) reached = 1; if (tn != NULL) tn = cconv(tn); if (tn != NULL) tn = promote(NOOP, 0, tn); if (tn != NULL && !issclt(tn->tn_type->t_tspec)) { /* controlling expressions must have scalar type */ error(204); tn = NULL; } if (tn != NULL && tn->tn_op == CON) { if (isityp(tn->tn_type->t_tspec)) { cstk->c_infinite = tn->tn_val->v_quad != 0; } else { cstk->c_infinite = tn->tn_val->v_ldbl != 0.0; } if (!cstk->c_infinite && cstk->c_cont) error(323); } expr(tn, 0, 1, 1); /* * The end of the loop is only reached if it is no endless loop * or there was a break statement which could be reached. */ reached = !cstk->c_infinite || cstk->c_break; rchflg = 0; popctrl(T_DO); }
/* * Check a single argument in a function call. * * hte a pointer to the hash table entry of the function * n the number of the argument (1..) * def the function definition or NULL * decl prototype declaration, old style declaration or NULL * pos1p position of definition, declaration of first call * call1 first call, if both def and decl are old style def/decl * call checked call * arg1 currently checked argument of def/decl/call1 * arg2 currently checked argument of call * */ static void chkau(hte_t *hte, int n, sym_t *def, sym_t *decl, pos_t *pos1p, fcall_t *call1, fcall_t *call, type_t *arg1, type_t *arg2) { /* LINTED (automatic hides external declaration: warn) */ int promote, asgn, warn; tspec_t t1, t2; arginf_t *ai, *ai1; char *pos1; /* * If a function definition is available (def != NULL), we compare the * function call (call) with the definition. Otherwise, if a function * definition is available and it is not an old style definition * (decl != NULL && TP(decl->s_type)->t_proto), we compare the call * with this declaration. Otherwise we compare it with the first * call we have found (call1). */ /* arg1 must be promoted if it stems from an old style definition */ promote = def != NULL && def->s_osdef; /* * If we compair with a definition or declaration, we must perform * the same checks for qualifiers in indirected types as in * assignments. */ asgn = def != NULL || (decl != NULL && TP(decl->s_type)->t_proto); warn = 0; if (eqtype(arg1, arg2, 1, promote, asgn, &warn) && (!sflag || !warn)) return; /* * Other lint implementations print warnings as soon as the type * of an argument does not match exactly the expected type. The * result are lots of warnings which are really not necessary. * We print a warning only if * (0) at least one type is not an integer type and types differ * (1) hflag is set and types differ * (2) types differ, except in signedness * If the argument is an integer constant whose msb is not set, * signedness is ignored (e.g. 0 matches both signed and unsigned * int). This is with and without hflag. * If the argument is an integer constant with value 0 and the * expected argument is of type pointer and the width of the * integer constant is the same as the width of the pointer, * no warning is printed. */ t1 = arg1->t_tspec; t2 = arg2->t_tspec; if (isityp(t1) && isityp(t2) && !arg1->t_isenum && !arg2->t_isenum) { if (promote) { /* * XXX Here is a problem: Although it is possible to * pass an int where a char/short it expected, there * may be loss in significant digits. We should first * check for const arguments if they can be converted * into the original parameter type. */ if (t1 == FLOAT) { t1 = DOUBLE; } else if (t1 == CHAR || t1 == SCHAR) { t1 = INT; } else if (t1 == UCHAR) { t1 = tflag ? UINT : INT; } else if (t1 == SHORT) { t1 = INT; } else if (t1 == USHORT) { /* CONSTCOND */ t1 = INT_MAX < USHRT_MAX || tflag ? UINT : INT; } } if (styp(t1) == styp(t2)) { /* * types differ only in signedness; get information * about arguments */ /* * treat a definition like a call with variable * arguments */ ai1 = call1 != NULL ? call1->f_args : NULL; /* * if two calls are compared, ai1 is set to the * information for the n-th argument, if this was * a constant, otherwise to NULL */ for ( ; ai1 != NULL; ai1 = ai1->a_nxt) { if (ai1->a_num == n) break; } /* * ai is set to the information of the n-th arg * of the (second) call, if this was a constant, * otherwise to NULL */ for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) { if (ai->a_num == n) break; } if (ai1 == NULL && ai == NULL) { /* no constant at all */ if (!hflag) return; } else if (ai1 == NULL || ai == NULL) { /* one constant */ if (ai == NULL) ai = ai1; if (ai->a_zero || ai->a_pcon) /* same value in signed and unsigned */ return; /* value (not representation) differently */ } else { /* * two constants, one signed, one unsigned; * if the msb of one of the constants is set, * the argument is used inconsistently. */ if (!ai1->a_ncon && !ai->a_ncon) return; } } } else if (t1 == PTR && isityp(t2)) { for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) { if (ai->a_num == n) break; } /* * Vendor implementations of lint (e.g. HP-UX, Digital UNIX) * don't care about the size of the integer argument, * only whether or not it is zero. We do the same. */ if (ai != NULL && ai->a_zero) return; } pos1 = xstrdup(mkpos(pos1p)); /* %s, arg %d used inconsistently\t%s :: %s */ msg(6, hte->h_name, n, pos1, mkpos(&call->f_pos)); free(pos1); }
/* * write out all information necessary for lint2 to check function * calls * * rvused is set if the return value is used (asigned to a variable) * rvdisc is set if the return value is not used and not ignored * (casted to void) */ void outcall(tnode_t *tn, int rvused, int rvdisc) { tnode_t *args, *arg; int narg, n, i; int64_t q; tspec_t t; /* reset buffer */ outclr(); /* * line number of .c source, 'c' for function call, Id of current * source (.c or .h), and line in current source */ outint(csrc_pos.p_line); outchar('c'); outint(getfnid(curr_pos.p_file)); outchar('.'); outint(curr_pos.p_line); /* * flags; 'u' and 'i' must be last to make sure a letter * is between the numeric argument of a flag and the name of * the function */ narg = 0; args = tn->tn_right; for (arg = args; arg != NULL; arg = arg->tn_right) narg++; /* informations about arguments */ for (n = 1; n <= narg; n++) { /* the last argument is the top one in the tree */ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) continue; arg = arg->tn_left; if (arg->tn_op == CON) { if (isityp(t = arg->tn_type->t_tspec)) { /* * XXX it would probably be better to * explicitly test the sign */ if ((q = arg->tn_val->v_quad) == 0) { /* zero constant */ outchar('z'); } else if (msb(q, t, 0) == 0) { /* positive if casted to signed */ outchar('p'); } else { /* negative if casted to signed */ outchar('n'); } outint(n); } } else if (arg->tn_op == AMPER && arg->tn_left->tn_op == STRING && arg->tn_left->tn_strg->st_tspec == CHAR) { /* constant string, write all format specifiers */ outchar('s'); outint(n); outfstrg(arg->tn_left->tn_strg); } } /* return value discarded/used/ignored */ outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i')); /* name of the called function */ outname(tn->tn_left->tn_left->tn_sym->s_name); /* types of arguments */ outchar('f'); outint(narg); for (n = 1; n <= narg; n++) { /* the last argument is the top one in the tree */ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) continue; outtype(arg->tn_left->tn_type); } /* expected type of return value */ outtype(tn->tn_type); }
/* * Process a label. * * typ type of the label (T_NAME, T_DEFAULT or T_CASE). * sym symbol table entry of label if typ == T_NAME * tn expression if typ == T_CASE */ void label(int typ, sym_t *sym, tnode_t *tn) { cstk_t *ci; clst_t *cl; val_t *v; val_t nv; tspec_t t; switch (typ) { case T_NAME: if (sym->s_set) { /* label %s redefined */ error(194, sym->s_name); } else { setsflg(sym); } break; case T_CASE: /* find the stack entry for the innermost switch statement */ for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) continue; if (ci == NULL) { /* case not in switch */ error(195); tn = NULL; } else if (tn != NULL && tn->tn_op != CON) { /* non-constant case expression */ error(197); tn = NULL; } else if (tn != NULL && !isityp(tn->tn_type->t_tspec)) { /* non-integral case expression */ error(198); tn = NULL; } if (tn != NULL) { if (ci->c_swtype == NULL) lerror("label() 1"); if (reached && !ftflg) { if (hflag) /* fallthrough on case statement */ warning(220); } t = tn->tn_type->t_tspec; if (t == LONG || t == ULONG || t == QUAD || t == UQUAD) { if (tflag) /* case label must be of type ... */ warning(203); } /* * get the value of the expression and convert it * to the type of the switch expression */ v = constant(tn); (void) memset(&nv, 0, sizeof nv); cvtcon(CASE, 0, ci->c_swtype, &nv, v); free(v); /* look if we had this value already */ for (cl = ci->c_clst; cl != NULL; cl = cl->cl_nxt) { if (cl->cl_val.v_quad == nv.v_quad) break; } if (cl != NULL && isutyp(nv.v_tspec)) { /* duplicate case in switch, %lu */ error(200, (u_long)nv.v_quad); } else if (cl != NULL) { /* duplicate case in switch, %ld */ error(199, (long)nv.v_quad); } else { /* * append the value to the list of * case values */ cl = xcalloc(1, sizeof (clst_t)); STRUCT_ASSIGN(cl->cl_val, nv); cl->cl_nxt = ci->c_clst; ci->c_clst = cl; } } tfreeblk(); break; case T_DEFAULT: /* find the stack entry for the innermost switch statement */ for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) continue; if (ci == NULL) { /* default outside switch */ error(201); } else if (ci->c_default) { /* duplicate default in switch */ error(202); } else { if (reached && !ftflg) { if (hflag) /* fallthrough on default statement */ warning(284); } ci->c_default = 1; } break; }; reached = 1; }
void mkinit(tnode_t *tn) { ptrdiff_t offs; sym_t *sym; tspec_t lt, rt; tnode_t *ln; struct mbl *tmem; scl_t sc; if (initerr || tn == NULL) goto end; sc = initsym->s_scl; /* * Do not test for automatic aggregat initialisation. If the * initializer starts with a brace we have the warning already. * If not, an error will be printed that the initializer must * be enclosed by braces. */ /* * Local initialisation of non-array-types with only one expression * without braces is done by ASSIGN */ if ((sc == AUTO || sc == REG) && initsym->s_type->t_tspec != ARRAY && initstk->i_nxt == NULL) { ln = getnnode(initsym, 0); ln->tn_type = tduptyp(ln->tn_type); ln->tn_type->t_const = 0; tn = build(ASSIGN, ln, tn); expr(tn, 0, 0); goto end; } /* * Remove all entries which cannot be used for further initializers * and do not require a closing brace. */ popinit(0); /* Initialisations by strings are done in strginit(). */ if (strginit(tn)) goto end; nextinit(0); if (initerr || tn == NULL) goto end; initstk->i_cnt--; /* Create a temporary node for the left side. */ ln = tgetblk(sizeof (tnode_t)); ln->tn_op = NAME; ln->tn_type = tduptyp(initstk->i_type); ln->tn_type->t_const = 0; ln->tn_lvalue = 1; ln->tn_sym = initsym; /* better than nothing */ tn = cconv(tn); lt = ln->tn_type->t_tspec; rt = tn->tn_type->t_tspec; if (!issclt(lt)) lerror("mkinit() 1"); if (!typeok(INIT, 0, ln, tn)) goto end; /* * Store the tree memory. This is nessesary because otherwise * expr() would free it. */ tmem = tsave(); expr(tn, 1, 0); trestor(tmem); if (isityp(lt) && ln->tn_type->t_isfield && !isityp(rt)) { /* * Bit-fields can be initialized in trad. C only by integer * constants. */ if (tflag) /* bit-field initialisation is illegal in trad. C */ warning(186); } if (lt != rt || (initstk->i_type->t_isfield && tn->tn_op == CON)) tn = convert(INIT, 0, initstk->i_type, tn); if (tn != NULL && tn->tn_op != CON) { sym = NULL; offs = 0; if (conaddr(tn, &sym, &offs) == -1) { if (sc == AUTO || sc == REG) { /* non-constant initializer */ (void)gnuism(177); } else { /* non-constant initializer */ error(177); } } } end: tfreeblk(); }