diff options
Diffstat (limited to 'usr.bin/xlint/lint1/tree.c')
-rw-r--r-- | usr.bin/xlint/lint1/tree.c | 3966 |
1 files changed, 0 insertions, 3966 deletions
diff --git a/usr.bin/xlint/lint1/tree.c b/usr.bin/xlint/lint1/tree.c deleted file mode 100644 index ce6a1e20941..00000000000 --- a/usr.bin/xlint/lint1/tree.c +++ /dev/null @@ -1,3966 +0,0 @@ -/* $OpenBSD: tree.c,v 1.48 2011/09/21 18:08:07 jsg Exp $ */ -/* $NetBSD: tree.c,v 1.12 1995/10/02 17:37:57 jpo Exp $ */ - -/* - * Copyright (c) 1994, 1995 Jochen Pohl - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Jochen Pohl for - * The NetBSD Project. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <string.h> -#include <float.h> -#include <limits.h> -#include <math.h> - -#include "lint1.h" -#include "y.tab.h" - -/* Various flags for each operator. */ -static mod_t modtab[NOPS]; - -static tnode_t *getinode(tspec_t, quad_t); -static void ptrcmpok(op_t, tnode_t *, tnode_t *); -static int asgntypok(op_t, farg_t *, tnode_t *, tnode_t *); -static void chkbeop(op_t, tnode_t *, tnode_t *); -static void chkeop2(op_t, farg_t *, tnode_t *, tnode_t *); -static void chkeop1(op_t, farg_t *, tnode_t *, tnode_t *); -static tnode_t *mktnode(op_t, type_t *, tnode_t *, tnode_t *); -static void balance(op_t, tnode_t **, tnode_t **); -static void incompat(op_t, tspec_t, tspec_t); -static void illptrc(mod_t *, type_t *, type_t *); -static void mrgqual(type_t **, type_t *, type_t *); -static int conmemb(type_t *); -static tspec_t fcnconv(farg_t *, tspec_t, tspec_t, type_t *, tnode_t *); -static void iiconv(op_t, farg_t *, tspec_t, tspec_t, type_t *, tnode_t *); -static void piconv(op_t, tspec_t, type_t *, tnode_t *); -static void ppconv(op_t, tnode_t *, type_t *); -static tnode_t *bldstr(op_t, tnode_t *, tnode_t *); -static tnode_t *bldincdec(op_t, tnode_t *); -static tnode_t *bldamper(tnode_t *, int); -static tnode_t *bldplmi(op_t, tnode_t *, tnode_t *); -static tnode_t *bldshft(op_t, tnode_t *, tnode_t *); -static tnode_t *bldcol(tnode_t *, tnode_t *); -static tnode_t *bldasgn(op_t, tnode_t *, tnode_t *); -static tnode_t *plength(type_t *); -static tnode_t *fold(tnode_t *); -static tnode_t *foldtst(tnode_t *); -static tnode_t *foldflt(tnode_t *); -static tnode_t *chkfarg(tnode_t *, tnode_t *); -static tnode_t *parg(farg_t *, tnode_t *); -static int chkdbz(op_t, tnode_t *); -static void nulleff(tnode_t *); -static int nulleffexpr(tnode_t *); -static void chkaidx(tnode_t *, int); -static void chkcomp(op_t, tnode_t *, tnode_t *); -static void precconf(tnode_t *); -static const char *funcname(tnode_t *); - -/* - * Initialize mods of operators. - */ -void -initmtab(void) -{ - static struct { - op_t op; - mod_t m; - } imods[] = { - { ARROW, { 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, - "->" } }, - { POINT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - "." } }, - { NOT, { 0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0, - "!" } }, - { COMPL, { 0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1, - "~" } }, - { INCBEF, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0, - "prefix++" } }, - { DECBEF, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0, - "prefix--" } }, - { INCAFT, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0, - "postfix++" } }, - { DECAFT, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0, - "postfix--" } }, - { UPLUS, { 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1, - "unary +" } }, - { UMINUS, { 0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,1,1, - "unary -" } }, - { STAR, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, - "unary *" } }, - { AMPER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - "unary &" } }, - { MULT, { 1,0,0,0,1,1,1,0,1,0,0,1,0,0,0,1,1, - "*" } }, - { DIV, { 1,0,0,0,1,1,1,0,1,0,1,1,0,0,0,1,1, - "/" } }, - { MOD, { 1,0,1,0,0,1,1,0,1,0,1,1,0,0,0,1,1, - "%" } }, - { PLUS, { 1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,0, - "+" } }, - { MINUS, { 1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,0, - "-" } }, - { SHL, { 1,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,1, - "<<" } }, - { SHR, { 1,0,1,0,0,1,1,0,0,0,1,0,1,0,0,1,1, - ">>" } }, - { LT, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1, - "<" } }, - { LE, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1, - "<=" } }, - { GT, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1, - ">" } }, - { GE, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1, - ">=" } }, - { EQ, { 1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,0,0, - "==" } }, - { NE, { 1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,0,1, - "!=" } }, - { AND, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0, - "&" } }, - { XOR, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0, - "^" } }, - { OR, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0, - "|" } }, - { LOGAND, { 1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0, - "&&" } }, - { LOGOR, { 1,1,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0, - "||" } }, - { QUEST, { 1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, - "?" } }, - { COLON, { 1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0, - ":" } }, - { ASSIGN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, - "=" } }, - { MULASS, { 1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0, - "*=" } }, - { DIVASS, { 1,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0, - "/=" } }, - { MODASS, { 1,0,1,0,0,0,0,0,0,1,0,1,0,0,0,1,0, - "%=" } }, - { ADDASS, { 1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0, - "+=" } }, - { SUBASS, { 1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0, - "-=" } }, - { SHLASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0, - "<<=" } }, - { SHRASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0, - ">>=" } }, - { ANDASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0, - "&=" } }, - { XORASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0, - "^=" } }, - { ORASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0, - "|=" } }, - { NAME, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - "NAME" } }, - { CON, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - "CON" } }, - { STRING, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - "STRING" } }, - { FSEL, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - "FSEL" } }, - { CALL, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, - "CALL" } }, - { COMMA, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, - "," } }, - { CVT, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, - "CVT" } }, - { ICALL, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, - "ICALL" } }, - { LOAD, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - "LOAD" } }, - { PUSH, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, - "PUSH" } }, - { RETURN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, - "RETURN" } }, - { REAL, { 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1, - "__real__" } }, - { IMAG, { 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1, - "__imag__" } }, - { INIT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, - "INIT" } }, - { FARG, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, - "FARG" } }, - { NOOP } - }; - int i; - - for (i = 0; imods[i].op != NOOP; i++) - STRUCT_ASSIGN(modtab[imods[i].op], imods[i].m); -} - -/* - * Increase degree of reference. - * This is most often used to change type "T" in type "pointer to T". - */ -type_t * -incref(type_t *tp, tspec_t t) -{ - type_t *tp2; - - tp2 = getblk(sizeof (type_t)); - tp2->t_tspec = t; - tp2->t_subt = tp; - return (tp2); -} - -/* - * same for use in expressions - */ -type_t * -tincref(type_t *tp, tspec_t t) -{ - type_t *tp2; - - tp2 = tgetblk(sizeof (type_t)); - tp2->t_tspec = t; - tp2->t_subt = tp; - return (tp2); -} - -/* - * Create a node for a constant. - */ -tnode_t * -getcnode(type_t *tp, val_t *v) -{ - tnode_t *n; - - n = getnode(); - n->tn_op = CON; - n->tn_type = tp; - n->tn_val = tgetblk(sizeof (val_t)); - n->tn_val->v_tspec = tp->t_tspec; - n->tn_val->v_lspec = v->v_lspec; - n->tn_val->v_ansiu = v->v_ansiu; - n->tn_val->v_u = v->v_u; - free(v); - return (n); -} - -/* - * Create a node for a integer constant. - */ -static tnode_t * -getinode(tspec_t t, quad_t q) -{ - tnode_t *n; - - n = getnode(); - n->tn_op = CON; - n->tn_type = gettyp(t); - n->tn_val = tgetblk(sizeof (val_t)); - n->tn_val->v_tspec = t; - n->tn_val->v_quad = q; - return (n); -} - -/* - * Create a node for a name (symbol table entry). - * ntok is the token which follows the name. - */ -tnode_t * -getnnode(sym_t *sym, int ntok) -{ - tnode_t *n; - - if (sym->s_scl == NOSCL) { - sym->s_scl = EXTERN; - sym->s_def = DECL; - if (ntok == T_LPARN) { - if (sflag) { - /* function implicitly declared to ... */ - warning(215); - } - sym->s_type = incref(sym->s_type, FUNC); - } else { - /* %s undefined */ - error(99, sym->s_name); - } - } - - if (sym->s_kind != FVFT && sym->s_kind != FMOS) - lerror("getnnode() 1"); - - n = getnode(); - n->tn_type = sym->s_type; - if (sym->s_scl != ENUMCON) { - n->tn_op = NAME; - n->tn_sym = sym; - if (sym->s_kind == FVFT && sym->s_type->t_tspec != FUNC) - n->tn_lvalue = 1; - } else { - n->tn_op = CON; - n->tn_val = tgetblk(sizeof (val_t)); - *n->tn_val = sym->s_value; - } - - return (n); -} - -/* - * Create a node for a string. - */ -tnode_t * -getsnode(strg_t *strg) -{ - size_t len; - tnode_t *n; - - len = strg->st_len; - - n = getnode(); - - n->tn_op = STRING; - n->tn_type = tincref(gettyp(strg->st_tspec), ARRAY); - n->tn_type->t_dim = len + 1; - n->tn_lvalue = 1; - - n->tn_strg = tgetblk(sizeof (strg_t)); - n->tn_strg->st_tspec = strg->st_tspec; - n->tn_strg->st_len = len; - - if (strg->st_tspec == CHAR) { - n->tn_strg->st_cp = tgetblk(len + 1); - (void)memcpy(n->tn_strg->st_cp, strg->st_cp, len + 1); - free(strg->st_cp); - } else { - n->tn_strg->st_wcp = tgetblk((len + 1) * sizeof (wchar_t)); - (void)memcpy(n->tn_strg->st_wcp, strg->st_wcp, - (len + 1) * sizeof (wchar_t)); - free(strg->st_wcp); - } - free(strg); - - return (n); -} - -/* - * Returns a symbol which has the same name as the msym argument and is a - * member of the struct or union specified by the tn argument. - */ -sym_t * -strmemb(tnode_t *tn, op_t op, sym_t *msym) -{ - str_t *str; - type_t *tp; - sym_t *sym, *csym; - int eq; - tspec_t t; - - /* - * Remove the member if it was unknown until now (Which means - * that no defined struct or union has a member with the same name). - */ - if (msym->s_scl == NOSCL) { - /* undefined struct/union member: %s */ - error(101, msym->s_name); - rmsym(msym); - msym->s_kind = FMOS; - msym->s_scl = MOS; - msym->s_styp = tgetblk(sizeof (str_t)); - msym->s_styp->stag = tgetblk(sizeof (sym_t)); - msym->s_styp->stag->s_name = unnamed; - msym->s_value.v_tspec = INT; - return (msym); - } - - /* Set str to the tag of which msym is expected to be a member. */ - str = NULL; - t = (tp = tn->tn_type)->t_tspec; - if (op == POINT) { - if (t == STRUCT || t == UNION) - str = tp->t_str; - } else if (op == ARROW && t == PTR) { - t = (tp = tp->t_subt)->t_tspec; - if (t == STRUCT || t == UNION) - str = tp->t_str; - } - - /* - * If this struct/union has a member with the name of msym, return - * return this it. - */ - if (str != NULL) { - for (sym = msym; sym != NULL; sym = sym->s_link) { - if (sym->s_scl != MOS && sym->s_scl != MOU) - continue; - if (sym->s_styp != str) - continue; - if (strcmp(sym->s_name, msym->s_name) != 0) - continue; - return (sym); - } - } - - /* - * Set eq to 0 if there are struct/union members with the same name - * and different types and/or offsets. - */ - eq = 1; - for (csym = msym; csym != NULL; csym = csym->s_link) { - if (csym->s_scl != MOS && csym->s_scl != MOU) - continue; - if (strcmp(msym->s_name, csym->s_name) != 0) - continue; - for (sym = csym->s_link ; sym != NULL; sym = sym->s_link) { - int w; - - if (sym->s_scl != MOS && sym->s_scl != MOU) - continue; - if (strcmp(csym->s_name, sym->s_name) != 0) - continue; - if (csym->s_value.v_quad != sym->s_value.v_quad) { - eq = 0; - break; - } - w = 0; - eq = eqtype(csym->s_type, sym->s_type, 0, 0, &w) && !w; - if (!eq) - break; - if (csym->s_field != sym->s_field) { - eq = 0; - break; - } - if (csym->s_field) { - type_t *tp1, *tp2; - - tp1 = csym->s_type; - tp2 = sym->s_type; - if (tp1->t_flen != tp2->t_flen) { - eq = 0; - break; - } - if (tp1->t_foffs != tp2->t_foffs) { - eq = 0; - break; - } - } - } - if (!eq) - break; - } - - /* - * Now handle the case in which the left operand refers really - * to a struct/union, but the right operand is not member of it. - */ - if (str != NULL) { - /* illegal member use: %s */ - error(102, msym->s_name); - return (msym); - } - - /* - * Now the left operand of ARROW does not point to a struct/union - * or the left operand of POINT is no struct/union. - */ - if (eq) { - if (op == POINT) { - /* left operand of "." must be struct/union object */ - error(103); - } else { - /* left operand of "->" must be pointer to ... */ - error(104); - } - } else { - /* unacceptable operand of %s */ - error(111, modtab[op].m_name); - } - - return (msym); -} - -/* - * Create a tree node. Called for most operands except function calls, - * sizeof and casts. - * - * op operator - * ln left operand - * rn if not NULL, right operand - */ -tnode_t * -build(op_t op, tnode_t *ln, tnode_t *rn) -{ - mod_t *mp; - tnode_t *ntn; - type_t *rtp; - - mp = &modtab[op]; - - /* If there was an error in one of the operands, return. */ - if (ln == NULL || (mp->m_binary && rn == NULL)) - return (NULL); - - /* - * Apply class conversions to the left operand, but only if its - * value is needed or it is compared with null. - */ - if (mp->m_vctx || mp->m_tctx) - ln = cconv(ln); - /* - * The right operand is almost always in a test or value context, - * except if it is a struct or union member. - */ - if (mp->m_binary && op != ARROW && op != POINT) - rn = cconv(rn); - - /* - * Print some warnings for comparisons of unsigned values with - * constants lower than or equal to null. This must be done - * before promote() because otherwise unsigned char and unsigned - * short would be promoted to int. Also types are tested to be - * CHAR, which would also become int. - */ - if (mp->m_comp) - chkcomp(op, ln, rn); - - /* - * Promote the left operand if it is in a test or value context - */ - if (mp->m_vctx || mp->m_tctx) - ln = promote(op, 0, ln); - /* - * Promote the right operand, but only if it is no struct or - * union member, or if it is not to be assigned to the left operand - */ - if (mp->m_binary && op != ARROW && op != POINT && - op != ASSIGN && op != RETURN) { - rn = promote(op, 0, rn); - } - - /* - * If the result of the operation is different for signed or - * unsigned operands and one of the operands is signed only in - * ANSI C, print a warning. - */ - if (mp->m_tlansiu && ln->tn_op == CON && ln->tn_val->v_ansiu) { - /* ANSI C treats constant as unsigned, op %s */ - warning(218, mp->m_name); - ln->tn_val->v_ansiu = 0; - } - if (mp->m_transiu && rn->tn_op == CON && rn->tn_val->v_ansiu) { - /* ANSI C treats constant as unsigned, op %s */ - warning(218, mp->m_name); - rn->tn_val->v_ansiu = 0; - } - - /* Make sure both operands are of the same type */ - if (mp->m_balance) - balance(op, &ln, &rn); - - /* - * Check types for compatibility with the operation and mutual - * compatibility. Return if there are serious problems. - */ - if (!typeok(op, NULL, ln, rn)) - return (NULL); - - /* And now create the node. */ - switch (op) { - case POINT: - case ARROW: - ntn = bldstr(op, ln, rn); - break; - case INCAFT: - case DECAFT: - case INCBEF: - case DECBEF: - ntn = bldincdec(op, ln); - break; - case AMPER: - ntn = bldamper(ln, 0); - break; - case STAR: - ntn = mktnode(STAR, ln->tn_type->t_subt, ln, NULL); - break; - case PLUS: - case MINUS: - ntn = bldplmi(op, ln, rn); - break; - case SHL: - case SHR: - ntn = bldshft(op, ln, rn); - break; - case COLON: - ntn = bldcol(ln, rn); - break; - case ASSIGN: - case MULASS: - case DIVASS: - case MODASS: - case ADDASS: - case SUBASS: - case SHLASS: - case SHRASS: - case ANDASS: - case XORASS: - case ORASS: - case RETURN: - ntn = bldasgn(op, ln, rn); - break; - case COMMA: - case QUEST: - ntn = mktnode(op, rn->tn_type, ln, rn); - break; - case REAL: - case IMAG: - rtp = ln->tn_type; - if (rtp->t_tspec == COMPLEX) - rtp = gettyp(FLOAT); - else if (rtp->t_tspec == DCOMPLEX) - rtp = gettyp(DOUBLE); - else if (rtp->t_tspec == LDCOMPLEX) - rtp = gettyp(LDOUBLE); - ntn = mktnode(op, rtp, ln, rn); - break; - default: - rtp = mp->m_logop ? gettyp(INT) : ln->tn_type; - if (!mp->m_binary && rn != NULL) - lerror("build() 1"); - ntn = mktnode(op, rtp, ln, rn); - break; - } - - /* Return if an error occurred. */ - if (ntn == NULL) - return (NULL); - - /* Print a warning if precedence confusion is possible */ - if (mp->m_tpconf) - precconf(ntn); - - /* - * Print a warning if one of the operands is in a context where - * it is compared with null and if this operand is a constant. - */ - if (mp->m_tctx) { - if (ln->tn_op == CON || - ((mp->m_binary && op != QUEST) && rn->tn_op == CON)) { - if (hflag && !ccflg) { - /* constant in conditional context */ - warning(161); - } - } - } - - /* Fold if the operator requires it */ - if (mp->m_fold) { - if (ln->tn_op == CON && (!mp->m_binary || rn->tn_op == CON)) { - if (mp->m_tctx) { - ntn = foldtst(ntn); - } else if (isftyp(ntn->tn_type->t_tspec)) { - ntn = foldflt(ntn); - } else { - ntn = fold(ntn); - } - } else if (op == QUEST && ln->tn_op == CON) { - ntn = ln->tn_val->v_quad ? rn->tn_left : rn->tn_right; - } - } - - return (ntn); -} - -/* - * Perform class conversions. - * - * Arrays of type T are converted into pointers to type T. - * Functions are converted to pointers to functions. - * Lvalues are converted to rvalues. - */ -tnode_t * -cconv(tnode_t *tn) -{ - type_t *tp; - - /* - * Array-lvalue (array of type T) is converted into rvalue - * (pointer to type T) - */ - if (tn->tn_type->t_tspec == ARRAY) { - if (!tn->tn_lvalue) { - /* operand of '%s' must be lvalue */ - /* XXX print correct operator */ - (void)gnuism(114, "", modtab[AMPER].m_name); - } - tn = mktnode(AMPER, tincref(tn->tn_type->t_subt, PTR), - tn, NULL); - } - - /* - * Expression of type function (function with return value of type T) - * in rvalue-expression (pointer to function with return value - * of type T) - */ - if (tn->tn_type->t_tspec == FUNC) - tn = bldamper(tn, 1); - - /* lvalue to rvalue */ - if (tn->tn_lvalue) { - tp = tduptyp(tn->tn_type); - tp->t_const = tp->t_volatile = 0; - tn = mktnode(LOAD, tp, tn, NULL); - } - - return (tn); -} - -/* - * Perform most type checks. First the types are checked using - * information from modtab[]. After that it is done by hand for - * more complicated operators and type combinations. - * - * If the types are ok, typeok() returns 1, otherwise 0. - */ -int -typeok(op_t op, farg_t *farg, tnode_t *ln, tnode_t *rn) -{ - mod_t *mp; - tspec_t lt, rt = NOTSPEC, lst = NOTSPEC, rst = NOTSPEC, - olt = NOTSPEC, ort = NOTSPEC; - type_t *ltp, *rtp, *lstp, *rstp; - tnode_t *tn; - - mp = &modtab[op]; - - if ((lt = (ltp = ln->tn_type)->t_tspec) == PTR) - lst = (lstp = ltp->t_subt)->t_tspec; - if (mp->m_binary) { - if ((rt = (rtp = rn->tn_type)->t_tspec) == PTR) - rst = (rstp = rtp->t_subt)->t_tspec; - } - - if (mp->m_rqint) { - if (op == COMPL && iscomplex(lt)) { - /* use of '~' for complex conjugation is a GNUism */ - } else - /* integer types required */ - if (!isityp(lt) || (mp->m_binary && !isityp(rt))) { - incompat(op, lt, rt); - return (0); - } - } else if (mp->m_rqsclt) { - /* scalar types required */ - if (!issclt(lt) || (mp->m_binary && !issclt(rt))) { - incompat(op, lt, rt); - return (0); - } - } else if (mp->m_rqatyp) { - /* arithmetic types required */ - if (!isatyp(lt) || (mp->m_binary && !isatyp(rt))) { - incompat(op, lt, rt); - return (0); - } - } - - if (op == SHL || op == SHR || op == SHLASS || op == SHRASS) { - /* - * For these operations we need the types before promotion - * and balancing. - */ - for (tn=ln; tn->tn_op==CVT && !tn->tn_cast; tn=tn->tn_left) ; - olt = tn->tn_type->t_tspec; - for (tn=rn; tn->tn_op==CVT && !tn->tn_cast; tn=tn->tn_left) ; - ort = tn->tn_type->t_tspec; - } - - switch (op) { - case POINT: - /* - * Most errors required by ANSI C are reported in strmemb(). - * Here we only must check for totally wrong things. - */ - if (lt == FUNC || lt == VOID || ltp->t_isfield || - ((lt != STRUCT && lt != UNION) && !ln->tn_lvalue)) { - /* we already have an error from strmemb() */ - return (0); - } - /* Now we have an object we can create a pointer to */ - break; - case ARROW: - if (lt != PTR) { - /* we already have an error from strmemb() */ - return (0); - } - break; - case INCAFT: - case DECAFT: - case INCBEF: - case DECBEF: - /* operands have scalar types (checked above) */ - if (!ln->tn_lvalue) { - if (ln->tn_op == CVT && ln->tn_cast && - ln->tn_left->tn_op == LOAD) { - /* a cast does not yield an lvalue */ - error(163); - } - /* %soperand of %s must be lvalue */ - error(114, "", mp->m_name); - return (0); - } else if (ltp->t_const) { - /* %soperand of %s must be modifiable lvalue */ - warning(115, "", mp->m_name); - } - break; - case AMPER: - if (lt == ARRAY || lt == FUNC) { - /* ok, a warning comes later (in bldamper()) */ - } else if (!ln->tn_lvalue) { - if (ln->tn_op == CVT && ln->tn_cast && - ln->tn_left->tn_op == LOAD) { - /* a cast does not yield an lvalue */ - error(163); - } - /* %soperand of %s must be lvalue */ - error(114, "", mp->m_name); - return (0); - } else if (issclt(lt)) { - if (ltp->t_isfield) { - /* cannot take address of bit-field */ - error(112); - return (0); - } - } else if (lt != STRUCT && lt != UNION) { - /* unacceptable operand of %s */ - error(111, mp->m_name); - return (0); - } - if (ln->tn_op == NAME && ln->tn_sym->s_reg) { - /* cannot take address of register %s */ - error(113, ln->tn_sym->s_name); - return (0); - } - break; - case STAR: - /* until now there were no type checks for this operator */ - if (lt != PTR) { - /* cannot dereference non-pointer type */ - error(96); - return (0); - } - break; - case PLUS: - /* operands have scalar types (checked above) */ - if ((lt == PTR && !isityp(rt)) || (rt == PTR && !isityp(lt))) { - incompat(op, lt, rt); - return (0); - } - break; - case MINUS: - /* operands have scalar types (checked above) */ - if (lt == PTR && (!isityp(rt) && rt != PTR)) { - incompat(op, lt, rt); - return (0); - } else if (rt == PTR && lt != PTR) { - incompat(op, lt, rt); - return (0); - } - if (lt == PTR && rt == PTR) { - if (!eqtype(lstp, rstp, 1, 0, NULL)) { - /* illegal pointer subtraction */ - error(116); - } - } - break; - case SHR: - /* operands have integer types (checked above) */ - if (pflag && !isutyp(lt)) { - /* - * The left operand is signed. This means that - * the operation is (possibly) nonportable. - */ - /* bitwise operation on signed value nonportable */ - if (ln->tn_op != CON) { - /* possibly nonportable */ - warning(117); - } else if (ln->tn_val->v_quad < 0) { - warning(120); - } - } else if (!sflag && !isutyp(olt) && isutyp(ort)) { - /* - * The left operand would become unsigned in - * traditional C. - */ - if (hflag && - (ln->tn_op != CON || ln->tn_val->v_quad < 0)) { - /* semantics of %s change in ANSI C; use ... */ - warning(118, mp->m_name); - } - } else if (!sflag && !isutyp(olt) && !isutyp(ort) && - psize(lt) < psize(rt)) { - /* - * In traditional C the left operand would be extended, - * possibly with 1, and then shifted. - */ - if (hflag && - (ln->tn_op != CON || ln->tn_val->v_quad < 0)) { - /* semantics of %s change in ANSI C; use ... */ - warning(118, mp->m_name); - } - } - - /* right shift of %d-bit quantity by %lld bits */ - if (rn->tn_op == CON && size(olt) <= rn->tn_val->v_quad) - warning(310, size(olt), rn->tn_val->v_quad); - - goto shift; - case SHL: - /* - * ANSI C does not perform balancing for shift operations, - * but traditional C does. If the width of the right operand - * is greather than the width of the left operand, than in - * traditional C the left operand would be extended to the - * width of the right operand. For SHL this may result in - * different results. - */ - if (psize(lt) < psize(rt)) { - /* - * XXX If both operands are constant make sure - * that there is really a difference between - * ANSI C and traditional C. - */ - if (hflag) - /* semantics of %s change in ANSI C; use ... */ - warning(118, mp->m_name); - } - shift: - if (rn->tn_op == CON) { - if (!isutyp(rt) && rn->tn_val->v_quad < 0) { - /* negative shift */ - warning(121); - } else if ((u_quad_t)rn->tn_val->v_quad == size(lt)) { - /* shift equal to size of object */ - warning(267); - } else if ((u_quad_t)rn->tn_val->v_quad > size(lt)) { - /* shift greater than size of object */ - warning(122); - } - } - break; - case EQ: - case NE: - /* - * Accept some things which are allowed with EQ and NE, - * but not with ordered comparisons. - */ - if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) { - if (rn->tn_op == CON && rn->tn_val->v_quad == 0) - break; - } - if (rt == PTR && ((lt == PTR && lst == VOID) || isityp(lt))) { - if (ln->tn_op == CON && ln->tn_val->v_quad == 0) - break; - } - /* FALLTHROUGH */ - case LT: - case GT: - case LE: - case GE: - if ((lt == PTR || rt == PTR) && lt != rt) { - if (isityp(lt) || isityp(rt)) { - /* illegal comb. of pointer and int., op %s */ - warning(123, mp->m_name); - } else { - incompat(op, lt, rt); - return (0); - } - } else if (lt == PTR && rt == PTR) { - ptrcmpok(op, ln, rn); - } - break; - case QUEST: - if (!issclt(lt)) { - /* first operand must have scalar type, op ? : */ - error(170); - return (0); - } - if (rn->tn_op != COLON) - lerror("typeok() 2"); - break; - case COLON: - - if (isatyp(lt) && isatyp(rt)) - break; - - if (lt == STRUCT && rt == STRUCT && ltp->t_str == rtp->t_str) - break; - if (lt == UNION && rt == UNION && ltp->t_str == rtp->t_str) - break; - - /* combination of any pointer and 0, 0L or (void *)0 is ok */ - if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) { - if (rn->tn_op == CON && rn->tn_val->v_quad == 0) - break; - } - if (rt == PTR && ((lt == PTR && lst == VOID) || isityp(lt))) { - if (ln->tn_op == CON && ln->tn_val->v_quad == 0) - break; - } - - if ((lt == PTR && isityp(rt)) || (isityp(lt) && rt == PTR)) { - /* illegal comb. of ptr. and int., op %s */ - warning(123, mp->m_name); - break; - } - - if (lt == VOID || rt == VOID) { - if (lt != VOID || rt != VOID) - /* incompatible types in conditional */ - warning(126); - break; - } - - if (lt == PTR && rt == PTR && ((lst == VOID && rst == FUNC) || - (lst == FUNC && rst == VOID))) { - /* (void *)0 handled above */ - if (sflag) - /* ANSI C forbids conv. of %s to %s, op %s */ - warning(305, "function pointer", "'void *'", - mp->m_name); - break; - } - - if (rt == PTR && lt == PTR) { - if (!eqtype(lstp, rstp, 1, 0, NULL)) - illptrc(mp, ltp, rtp); - break; - } - - /* incompatible types in conditional */ - error(126); - return (0); - - case ASSIGN: - case INIT: - case FARG: - case RETURN: - if (!asgntypok(op, farg, ln, rn)) - return (0); - goto assign; - case MULASS: - case DIVASS: - case MODASS: - goto assign; - case ADDASS: - case SUBASS: - /* operands have scalar types (checked above) */ - if ((lt == PTR && !isityp(rt)) || rt == PTR) { - incompat(op, lt, rt); - return (0); - } - goto assign; - case SHLASS: - goto assign; - case SHRASS: - if (pflag && !isutyp(lt)) { - /* bitwise operation on s.v. possibly nonportable */ - warning(117); - } - - /* right shift of %d-bit quantity by %d bits */ - if (rn->tn_op == CON && size(olt) <= rn->tn_val->v_quad) - warning(310, size(olt), rn->tn_val->v_quad); - - goto assign; - case ANDASS: - case XORASS: - case ORASS: - goto assign; - assign: - if (!ln->tn_lvalue) { - if (ln->tn_op == CVT && ln->tn_cast && - ln->tn_left->tn_op == LOAD) { - /* a cast does not yield an lvalue */ - error(163); - } - /* %soperand of %s must be lvalue */ - error(114, "left ", mp->m_name); - return (0); - } else if (ltp->t_const || ((lt == STRUCT || lt == UNION) && - conmemb(ltp))) { - /* %soperand of %s must be modifiable lvalue */ - warning(115, "left ", mp->m_name); - } - break; - case COMMA: - if (!modtab[ln->tn_op].m_sideeff) - nulleff(ln); - break; - /* LINTED (enumeration values not handled in switch) */ - } - - if (mp->m_badeop && - (ltp->t_isenum || (mp->m_binary && rtp->t_isenum))) { - chkbeop(op, ln, rn); - } else if (mp->m_enumop && (ltp->t_isenum && rtp->t_isenum)) { - chkeop2(op, farg, ln, rn); - } else if (mp->m_enumop && (ltp->t_isenum || rtp->t_isenum)) { - chkeop1(op, farg, ln, rn); - } - - return (1); -} - -static void -ptrcmpok(op_t op, tnode_t *ln, tnode_t *rn) -{ - type_t *ltp, *rtp; - tspec_t lt, rt; - const char *lts, *rts; - - lt = (ltp = ln->tn_type)->t_subt->t_tspec; - rt = (rtp = rn->tn_type)->t_subt->t_tspec; - - if (lt == VOID || rt == VOID) { - if (sflag && (lt == FUNC || rt == FUNC)) { - /* (void *)0 already handled in typeok() */ - *(lt == FUNC ? <s : &rts) = "function pointer"; - *(lt == VOID ? <s : &rts) = "'void *'"; - /* ANSI C forbids comparison of %s with %s */ - warning(274, lts, rts); - } - return; - } - - if (!eqtype(ltp->t_subt, rtp->t_subt, 1, 0, NULL)) { - illptrc(&modtab[op], ltp, rtp); - return; - } - - if (lt == FUNC && rt == FUNC) { - if (sflag && op != EQ && op != NE) - /* ANSI C forbids ordered comp. of func ptr */ - warning(125); - } -} - -/* - * Checks type compatibility for ASSIGN, INIT, FARG and RETURN - * and prints warnings/errors if necessary. - * If the types are (almost) compatible, 1 is returned, otherwise 0. - */ -static int -asgntypok(op_t op, farg_t *farg, tnode_t *ln, tnode_t *rn) -{ - tspec_t lt, rt, lst = NOTSPEC, rst = NOTSPEC; - type_t *ltp, *rtp, *lstp, *rstp; - mod_t *mp; - const char *lts, *rts; - int arg = (farg) ? farg->fa_num : 0; - - if ((lt = (ltp = ln->tn_type)->t_tspec) == PTR) - lst = (lstp = ltp->t_subt)->t_tspec; - if ((rt = (rtp = rn->tn_type)->t_tspec) == PTR) - rst = (rstp = rtp->t_subt)->t_tspec; - mp = &modtab[op]; - - /* be picky about conversion of function return types */ - if (rn->tn_op == CALL) { - if (size(lt) < size(rt) || - (size(lt) == size(rt) && isutyp(lt) && !isutyp(rt))) { - warning(313, funcname(rn), - tyname(rn->tn_type), tyname(ln->tn_type)); - } - } - - if (isatyp(lt) && isatyp(rt)) - return (1); - - if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION)) - /* both are struct or union */ - return (ltp->t_str == rtp->t_str); - - /* 0, 0L and (void *)0 may be assigned to any pointer */ - if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) { - if (rn->tn_op == CON && rn->tn_val->v_quad == 0) - return (1); - } - - if (lt == PTR && rt == PTR && (lst == VOID || rst == VOID)) { - /* two pointers, at least one pointer to void */ - if (sflag && (lst == FUNC || rst == FUNC)) { - /* comb. of ptr to func and ptr to void */ - *(lst == FUNC ? <s : &rts) = "function pointer"; - *(lst == VOID ? <s : &rts) = "'void *'"; - switch (op) { - case INIT: - case RETURN: - /* ANSI C forbids conversion of %s to %s */ - warning(303, rts, lts); - break; - case FARG: - /* ANSI C forbids conv. of %s to %s, arg #%d */ - warning(304, rts, lts, arg); - break; - default: - /* ANSI C forbids conv. of %s to %s, op %s */ - warning(305, rts, lts, mp->m_name); - break; - } - } - } - - if (lt == PTR && rt == PTR && (lst == VOID || rst == VOID || - eqtype(lstp, rstp, 1, 0, NULL))) { - /* compatible pointer types (qualifiers ignored) */ - if (((!lstp->t_const && rstp->t_const) || - (!lstp->t_volatile && rstp->t_volatile))) { - /* left side has not all qualifiers of right */ - switch (op) { - case INIT: - case RETURN: - /* incompatible pointer types */ - warning(182); - break; - case FARG: - /* %s arg #%d: incompatible ptr. type */ - warning(153, funcname(farg->fa_func), arg); - break; - default: - /* operands have incompat. ptr. types, op %s */ - warning(128, mp->m_name); - break; - } - } - return (1); - } - - if ((lt == PTR && isityp(rt)) || (isityp(lt) && rt == PTR)) { - switch (op) { - case INIT: - case RETURN: - /* illegal combination of pointer and integer */ - warning(183); - break; - case FARG: - /* %s arg #%d: illegal comb. of ptr. and int. */ - warning(154, funcname(farg->fa_func), arg); - break; - default: - /* illegal comb. of ptr. and int., op %s */ - warning(123, mp->m_name); - break; - } - return (1); - } - - if (lt == PTR && rt == PTR) { - switch (op) { - case INIT: - case RETURN: - illptrc(NULL, ltp, rtp); - break; - case FARG: - /* %s arg #%d: incompatible pointer type */ - warning(153, funcname(farg->fa_func), arg); - break; - default: - illptrc(mp, ltp, rtp); - break; - } - return (1); - } - - switch (op) { - case INIT: - /* initialisation type mismatch */ - error(185); - break; - case RETURN: - /* return value type mismatch */ - error(211); - break; - case FARG: - /* %s arg #%d: argument is incompatible with prototype */ - warning(155, funcname(farg->fa_func), arg); - break; - default: - incompat(op, lt, rt); - break; - } - - return (0); -} - -/* - * Prints a warning if an operator, which should be senseless for an - * enum type, is applied to an enum type. - */ -static void -chkbeop(op_t op, tnode_t *ln, tnode_t *rn) -{ - mod_t *mp; - - if (!eflag) - return; - - mp = &modtab[op]; - - if (!(ln->tn_type->t_isenum || - (mp->m_binary && rn->tn_type->t_isenum))) { - return; - } - - /* - * Enum as offset to a pointer is an exception (otherwise enums - * could not be used as array indizes). - */ - if (op == PLUS && - ((ln->tn_type->t_isenum && rn->tn_type->t_tspec == PTR) || - (rn->tn_type->t_isenum && ln->tn_type->t_tspec == PTR))) { - return; - } - - /* dubious operation on enum, op %s */ - warning(241, mp->m_name); - -} - -/* - * Prints a warning if an operator is applied to two different enum types. - */ -static void -chkeop2(op_t op, farg_t *farg, tnode_t *ln, tnode_t *rn) -{ - mod_t *mp; - int arg = (farg) ? farg->fa_num : 0; - - mp = &modtab[op]; - - if (ln->tn_type->t_enum != rn->tn_type->t_enum) { - switch (op) { - case INIT: - /* enum type mismatch in initialisation */ - warning(210); - break; - case FARG: - /* %s arg #%d: enum type mismatch */ - warning(156, funcname(farg->fa_func), arg); - break; - case RETURN: - /* return value type mismatch */ - warning(211); - break; - default: - /* enum type mismatch, op %s */ - warning(130, mp->m_name); - break; - } -#if 0 - } else if (mp->m_comp && op != EQ && op != NE) { - if (eflag) - /* dubious comparisons of enums */ - warning(243, mp->m_name); -#endif - } -} - -/* - * Prints a warning if an operator has both enum end other integer - * types. - */ -static void -chkeop1(op_t op, farg_t *farg, tnode_t *ln, tnode_t *rn) -{ - int arg = (farg) ? farg->fa_num : 0; - - if (!eflag) - return; - - switch (op) { - case INIT: - /* - * Initializations with 0 should be allowed. Otherwise, - * we should complain about all uninitialized enums, - * consequently. - */ - if (!rn->tn_type->t_isenum && rn->tn_op == CON && - isityp(rn->tn_type->t_tspec) && rn->tn_val->v_quad == 0) { - return; - } - /* initialisation of '%s' with '%s' */ - warning(277, tyname(ln->tn_type), tyname(rn->tn_type)); - break; - case FARG: - /* %s arg #%d: combination of '%s' and '%s' */ - warning(278, funcname(farg->fa_func), arg, tyname(ln->tn_type), tyname(rn->tn_type)); - break; - case RETURN: - /* combination of '%s' and '%s' in return */ - warning(279, tyname(ln->tn_type), tyname(rn->tn_type)); - break; - default: - /* combination of '%s' and %s, op %s */ - warning(242, tyname(ln->tn_type), tyname(rn->tn_type), - modtab[op].m_name); - break; - } -} - -/* - * Build and initialize a new node. - */ -static tnode_t * -mktnode(op_t op, type_t *type, tnode_t *ln, tnode_t *rn) -{ - tnode_t *ntn; - tspec_t t; - - ntn = getnode(); - - ntn->tn_op = op; - ntn->tn_type = type; - ntn->tn_left = ln; - ntn->tn_right = rn; - - if (op == STAR || op == FSEL) { - if (ln->tn_type->t_tspec == PTR) { - t = ln->tn_type->t_subt->t_tspec; - if (t != FUNC && t != VOID) - ntn->tn_lvalue = 1; - } else { - lerror("mktnode() 2"); - } - } else if (op == REAL || op == IMAG) { - ntn->tn_lvalue = ln->tn_lvalue; - } - - return (ntn); -} - -/* - * Performs usual conversion of operands to (unsigned) int. - * - * If the operand is a function argument with no type information - * (no prototype or variable # of args), convert float to double. - */ -tnode_t * -promote(op_t op, int farg, tnode_t *tn) -{ - tspec_t t; - type_t *ntp; - int len; - - t = tn->tn_type->t_tspec; - - if (!isatyp(t)) - return (tn); - - /* - * ANSI C requires that the result is always of type INT - * if INT can represent all possible values of the previous - * type (it is "value preserving" rather than "sign - * preserving"). - * - * XXX: Adjust value-preserving rules for longs and long - * longs, too. - */ - if (tn->tn_type->t_isfield) { - len = tn->tn_type->t_flen; - if (size(INT) > len) { - t = INT; - } else { - if (size(INT) != len) - lerror("promote() 1"); - if (isutyp(t)) { - t = UINT; - } else { - t = INT; - } - } - } else if (t == CHAR || t == UCHAR || t == SCHAR) { - t = (size(CHAR) < size(INT) || t != UCHAR) ? - INT : UINT; - } else if (t == SHORT || t == USHORT) { - t = (size(SHORT) < size(INT) || t == SHORT) ? - INT : UINT; - } else if (t == ENUM) { - t = INT; - } else if (farg && t == FLOAT) { - t = DOUBLE; - } - - if (t != tn->tn_type->t_tspec) { - ntp = tduptyp(tn->tn_type); - ntp->t_tspec = t; - /* - * Keep t_isenum so we are later able to check compatibility - * of enum types. - */ - tn = convert(op, NULL, ntp, tn); - } - - return (tn); -} - -/* - * Insert conversions which are necessary to give both operands the same - * type. This is done in different ways for traditional C and ANSI C. - */ -static void -balance(op_t op, tnode_t **lnp, tnode_t **rnp) -{ - tspec_t lt, rt, t; - int i; - type_t *ntp; - static tspec_t tl[] = { - LDOUBLE, DOUBLE, FLOAT, UQUAD, QUAD, ULONG, LONG, UINT, INT, - }; - - lt = (*lnp)->tn_type->t_tspec; - rt = (*rnp)->tn_type->t_tspec; - - if (!isatyp(lt) || !isatyp(rt)) - return; - - if (lt == rt) { - t = lt; - } else if (lt == LDOUBLE || rt == LDOUBLE) { - t = LDOUBLE; - } else if (lt == DOUBLE || rt == DOUBLE) { - t = DOUBLE; - } else if (lt == FLOAT || rt == FLOAT) { - t = FLOAT; - } else { - /* - * If type A has more bits than type B it should - * be able to hold all possible values of type B. - */ - if (size(lt) > size(rt)) { - t = lt; - } else if (size(lt) < size(rt)) { - t = rt; - } else { - for (i = 3; tl[i] != INT; i++) { - if (tl[i] == lt || tl[i] == rt) - break; - } - if ((isutyp(lt) || isutyp(rt)) && - !isutyp(tl[i])) { - i--; - } - t = tl[i]; - } - } - - if (t != lt) { - ntp = tduptyp((*lnp)->tn_type); - ntp->t_tspec = t; - *lnp = convert(op, NULL, ntp, *lnp); - } - if (t != rt) { - ntp = tduptyp((*rnp)->tn_type); - ntp->t_tspec = t; - *rnp = convert(op, NULL, ntp, *rnp); - } -} - -/* - * Insert a conversion operator, which converts the type of the node - * to another given type. - * If op is FARG, farg contains the passed argument information. - */ -tnode_t * -convert(op_t op, farg_t *farg, type_t *tp, tnode_t *tn) -{ - tnode_t *ntn; - tspec_t nt, ot, ost = NOTSPEC; - int arg = (farg) ? farg->fa_num : 0; - - if (tn->tn_lvalue) - lerror("convert() 1"); - - nt = tp->t_tspec; - if ((ot = tn->tn_type->t_tspec) == PTR) - ost = tn->tn_type->t_subt->t_tspec; - - if (op == FARG) - nt = fcnconv(farg, nt, ot, tp, tn); - - if (isityp(nt) && isityp(ot)) { - iiconv(op, farg, nt, ot, tp, tn); - } else if (nt == PTR && ((ot == PTR && ost == VOID) || isityp(ot)) && - tn->tn_op == CON && tn->tn_val->v_quad == 0) { - /* 0, 0L and (void *)0 may be assigned to any pointer. */ - } else if (isityp(nt) && ot == PTR) { - piconv(op, nt, tp, tn); - } else if (nt == PTR && ot == PTR) { - ppconv(op, tn, tp); - } else if (isftyp(ot) && !isftyp(nt)) { - /* conversion from floating point to fixed point */ - if (tn->tn_op == CON) { - /* ok. cvtcon() warns if constant out of range */ - } else { - if (op == FARG) - /* %s arg #%d: converted from '%s' to '%s' */ - warning(259, funcname(farg->fa_func), arg, - tyname(tn->tn_type), tyname(tp)); - else - warning(132, tyname(tn->tn_type), - tyname(tp)); - } - } - - ntn = getnode(); - ntn->tn_op = CVT; - ntn->tn_type = tp; - ntn->tn_cast = op == CVT; - if (tn->tn_op != CON || nt == VOID) { - ntn->tn_left = tn; - } else { - ntn->tn_op = CON; - ntn->tn_val = tgetblk(sizeof (val_t)); - cvtcon(op, farg, ntn->tn_type, ntn->tn_val, tn->tn_val); - } - - return (ntn); -} - -/* - * Print warnings for conversions of function call arguments. Conversions - * happen differently between standard C and traditional C, and also happen - * differently in standard C depending on whether a prototype is present. - * - * Errors/Warnings about illegal type combinations are already printed - * in asgntypok(). - */ -static tspec_t -fcnconv(farg_t *farg, tspec_t nt, tspec_t ot, type_t *tp, tnode_t *tn) -{ - tnode_t *ptn; - type_t *fcn = farg->fa_func->tn_type->t_subt; - tspec_t pt; - int arg = farg->fa_num; - - /* In standard C, if the function call is governed by a prototype, - * the arguments don't necessarily undergo the usual argument conversions - * before the call. They can be converted directly to the type of the - * formal parameter, without necessarily widening/narrowing. - */ - if (fcn->t_proto || !isatyp(nt) || !isatyp(ot)) - return nt; - - /* get default promotion */ - ptn = promote(NOOP, 1, tn); - pt = ptn->tn_type->t_tspec; - - /* - * If the type of the formal parameter is char/short, a warning - * would be useless, because functions declared the old style - * can't expect char/short arguments. - */ - if (nt == CHAR || nt == UCHAR || nt == SHORT || nt == USHORT) - return pt; - - /* return if types are the same with and without promotion */ - if (nt == pt || (nt == ENUM && pt == INT)) - return pt; - - if (isftyp(nt) != isftyp(pt) || psize(nt) != psize(pt)) { - /* representation and/or width change */ - if (styp(nt) != SHORT || !isityp(pt) || psize(pt) > psize(INT)) { - if (ptn->tn_op == CON) { - /* ok. promote() warns if constant out of range */ - } else { - /* %s arg #%d: converted from '%s' to '%s' */ - warning(259, funcname(farg->fa_func), arg, - tyname(tn->tn_type), tyname(tp)); - } - } - } else if (hflag) { - /* - * they differ in sign or base type (char, short, int, - * long, long long, float, double, long double) - * - * if they differ only in sign and the argument is a constant - * and the msb of the argument is not set, print no warning - */ - if (ptn->tn_op == CON && isityp(nt) && styp(nt) == styp(pt) && - msb(ptn->tn_val->v_quad, ot, -1) == 0) { - /* ok */ - } else if (ptn->tn_op != CON) { - /* %s arg #%d: converted from '%s' to '%s' */ - warning(259, funcname(farg->fa_func), arg, - tyname(tn->tn_type), tyname(tp)); - } - } - - return pt; -} - -/* - * Print warnings for conversions of integer types which may cause - * problems. - */ -/* ARGSUSED */ -static void -iiconv(op_t op, farg_t *farg, tspec_t nt, tspec_t ot, type_t *tp, tnode_t *tn) -{ - int arg = (farg) ? farg->fa_num : 0; - - if (tn->tn_op == CON) - return; - - if (op == CVT) - return; - - /* logical ops return int, so silently convert int to _Bool */ - if (ot == INT && nt == BOOL) - return; - - if (rank(nt) < rank(ot)) { - /* coercion from greater to lesser width */ - if (op == FARG) { - warning(259, funcname(farg->fa_func), arg, - tyname(tn->tn_type), tyname(tp)); - } else { - warning(132, tyname(tn->tn_type), tyname(tp)); - } - } else if (!isutyp(ot) && isutyp(nt)) { - /* signed to unsigned conversion */ - if (op == FARG) { - warning(259, funcname(farg->fa_func), arg, - tyname(tn->tn_type), tyname(tp)); - } else { - warning(132, tyname(tn->tn_type), tyname(tp)); - } - } else if (isutyp(ot) && !isutyp(nt) && rank(nt) == rank(ot)) { - /* signed to unsigned conversion */ - if (op == FARG) { - warning(259, funcname(farg->fa_func), arg, - tyname(tn->tn_type), tyname(tp)); - } else { - warning(132, tyname(tn->tn_type), tyname(tp)); - } - } -} - -/* - * Print warnings for dubious conversions of pointer to integer. - */ -static void -piconv(op_t op, tspec_t nt, type_t *tp, tnode_t *tn) -{ - if (tn->tn_op == CON) - return; - - if (op != CVT) { - /* We already have an error. */ - return; - } - - if (psize(nt) < psize(PTR)) { - if (pflag && size(nt) >= size(PTR)) { - /* conv. of pointer to %s may lose bits */ - warning(134, tyname(tp)); - } else { - /* conv. of pointer to %s loses bits */ - warning(133, tyname(tp)); - } - } -} - -/* - * Print warnings for questionable pointer conversions. - */ -static void -ppconv(op_t op, tnode_t *tn, type_t *tp) -{ - tspec_t nt, ot; - const char *nts, *ots; - - /* - * We already have an error (pointers of different types - * without a cast) or we will not get a warning. - */ - if (op != CVT) - return; - - nt = tp->t_subt->t_tspec; - ot = tn->tn_type->t_subt->t_tspec; - - if (nt == VOID || ot == VOID) { - if (sflag && (nt == FUNC || ot == FUNC)) { - /* (void *)0 already handled in convert() */ - *(nt == FUNC ? &nts : &ots) = "function pointer"; - *(nt == VOID ? &nts : &ots) = "'void *'"; - /* ANSI C forbids conversion of %s to %s */ - warning(303, ots, nts); - } - return; - } else if (nt == FUNC && ot == FUNC) { - return; - } else if (nt == FUNC || ot == FUNC) { - /* questionable conversion of function pointer */ - warning(229); - return; - } - - if (getbound(tp->t_subt) > getbound(tn->tn_type->t_subt)) { - if (hflag) - /* possible pointer alignment problem */ - warning(135); - } - if (((nt == STRUCT || nt == UNION) && - tp->t_subt->t_str != tn->tn_type->t_subt->t_str) || - (psize(nt) != CHAR_BIT && psize(nt) != psize(ot))) { - if (cflag) { - /* pointer casts may be troublesome */ - warning(247); - } - } -} - -/* - * Converts a typed constant to a constant of another type. - * - * op operator which requires conversion - * farg if op is FARG, the passed argument info (else NULL) - * tp type to which to convert the constant - * nv new constant - * v old constant - */ -void -cvtcon(op_t op, farg_t *farg, type_t *tp, val_t *nv, val_t *v) -{ - tspec_t ot, nt; - ldbl_t max = 0, min = 0; - int sz, rchk; - quad_t xmask, xmsk1; - int osz, nsz, arg = (farg) ? farg->fa_num : 0; - - ot = v->v_tspec; - nt = nv->v_tspec = tp->t_tspec; - rchk = 0; - - if (ot == FLOAT || ot == DOUBLE || ot == LDOUBLE) { - switch (nt) { - case BOOL: - max = 1; min = 0; break; - case CHAR: - max = CHAR_MAX; min = CHAR_MIN; break; - case UCHAR: - max = UCHAR_MAX; min = 0; break; - case SCHAR: - max = SCHAR_MAX; min = SCHAR_MIN; break; - case SHORT: - max = SHRT_MAX; min = SHRT_MIN; break; - case USHORT: - max = USHRT_MAX; min = 0; break; - case ENUM: - case INT: - max = INT_MAX; min = INT_MIN; break; - case UINT: - max = (u_int)UINT_MAX; min = 0; break; - case LONG: - max = LONG_MAX; min = LONG_MIN; break; - case ULONG: - max = (u_long)ULONG_MAX; min = 0; break; - case QUAD: - max = QUAD_MAX; min = QUAD_MIN; break; - case UQUAD: - max = (u_quad_t)UQUAD_MAX; min = 0; break; - case FLOAT: - max = FLT_MAX; min = -FLT_MAX; break; - case DOUBLE: - max = DBL_MAX; min = -DBL_MAX; break; - case PTR: - /* Already an error because of float --> ptr */ - case LDOUBLE: - max = LDBL_MAX; min = -LDBL_MAX; break; - case COMPLEX: - max = FLT_MAX; min = -FLT_MAX; break; - case DCOMPLEX: - max = DBL_MAX; min = -DBL_MAX; break; - case LDCOMPLEX: - max = LDBL_MAX; min = -LDBL_MAX; break; - case IMAGINARY: - case DIMAGINARY: - case LDIMAGINARY: - max = 0; min = 0; break; - default: - lerror("cvtcon() 1"); - } - if (v->v_ldbl > max || v->v_ldbl < min) { - if (nt == LDOUBLE || nt == LDCOMPLEX) - lerror("cvtcon() 2"); - if (op == FARG) { - /* %s arg #%d: conv. of %s to %s is out of range */ - warning(295, funcname(farg->fa_func), arg, - tyname(gettyp(ot)), tyname(tp)); - } else { - /* conversion of %s to %s is out of range */ - warning(119, tyname(gettyp(ot)), tyname(tp)); - } - v->v_ldbl = v->v_ldbl > 0 ? max : min; - } - if (nt == FLOAT) { - nv->v_ldbl = (float)v->v_ldbl; - } else if (nt == DOUBLE) { - nv->v_ldbl = (double)v->v_ldbl; - } else if (nt == LDOUBLE) { - nv->v_ldbl = v->v_ldbl; - } else { - nv->v_quad = (nt == PTR || isutyp(nt)) ? - (u_quad_t)v->v_ldbl : (quad_t)v->v_ldbl; - } - } else { - if (nt == FLOAT || nt == COMPLEX) { - nv->v_ldbl = (ot == PTR || isutyp(ot)) ? - (float)(u_quad_t)v->v_quad : (float)v->v_quad; - } else if (nt == DOUBLE || nt == DCOMPLEX) { - nv->v_ldbl = (ot == PTR || isutyp(ot)) ? - (double)(u_quad_t)v->v_quad : (double)v->v_quad; - } else if (nt == LDOUBLE || nt == LDCOMPLEX) { - nv->v_ldbl = (ot == PTR || isutyp(ot)) ? - (ldbl_t)(u_quad_t)v->v_quad : (ldbl_t)v->v_quad; - } else if (nt == IMAGINARY || nt == DIMAGINARY || - nt == LDIMAGINARY) { - nv->v_ldbl = 0; - } else { - rchk = 1; /* Check for lost precision. */ - nv->v_quad = v->v_quad; - } - } - - if (v->v_ansiu && isftyp(nt)) { - /* ANSI C treats constant as unsigned */ - warning(157); - v->v_ansiu = 0; - } else if (v->v_ansiu && (isityp(nt) && !isutyp(nt) && - psize(nt) > psize(ot))) { - /* ANSI C treats constant as unsigned */ - warning(157); - v->v_ansiu = 0; - } - - if (nt != FLOAT && nt != DOUBLE && nt != LDOUBLE) { - sz = tp->t_isfield ? tp->t_flen : size(nt); - nv->v_quad = xsign(nv->v_quad, nt, sz); - } - - if (rchk && op != CVT) { - osz = size(ot); - nsz = tp->t_isfield ? tp->t_flen : size(nt); - xmask = qlmasks[nsz] ^ qlmasks[osz]; - xmsk1 = qlmasks[nsz] ^ qlmasks[osz - 1]; - /* - * For bitwise operations we are not interested in the - * value, but in the bits itself. - */ - if (op == ORASS || op == OR || op == XOR) { - /* - * Print a warning if bits which were set are - * lost due to the conversion. - * This can happen with operator ORASS only. - */ - if (nsz < osz && (v->v_quad & xmask) != 0) { - /* constant truncated by conv., op %s */ - warning(306, modtab[op].m_name); - } - } else if (op == ANDASS || op == AND) { - /* - * Print a warning if additional bits are not all 1 - * and the most significant bit of the old value is 1, - * or if at least one (but not all) removed bit was 0. - */ - if (nsz > osz && - (nv->v_quad & qbmasks[osz - 1]) != 0 && - (nv->v_quad & xmask) != xmask) { - /* - * extra bits set to 0 in conversion - * of '%s' to '%s', op %s - */ - warning(309, tyname(gettyp(ot)), - tyname(tp), modtab[op].m_name); - } else if (nsz < osz && - (v->v_quad & xmask) != xmask && - (v->v_quad & xmask) != 0) { - /* const. truncated by conv., op %s */ - warning(306, modtab[op].m_name); - } - } else if ((nt != PTR && isutyp(nt)) && - (ot != PTR && !isutyp(ot)) && v->v_quad < 0) { - if ((nt == CHAR || nt == UCHAR || nt == SCHAR) && - v->v_lspec == CHAR) { - /* - * Don't warn when assigning a character - * literal to any kind of character (signed, - * unsigned, or unspecified). - */ - } else if (op == ASSIGN) { - /* assignment of negative constant to ... */ - warning(164); - } else if (op == INIT) { - /* initialisation of unsigned with neg. ... */ - warning(221); - } else if (op == FARG) { - /* %s arg #%d: conversion of neg. const... */ - warning(296, funcname(farg->fa_func), arg); - } else if (modtab[op].m_comp) { - /* we get this warning already in chkcomp() */ - } else { - /* conversion of negative constant to ... */ - warning(222); - } - } else if (nv->v_quad != v->v_quad && nsz <= osz && - (v->v_quad & xmask) != 0 && - (isutyp(ot) || (v->v_quad & xmsk1) != xmsk1)) { - /* - * Loss of significant bit(s). All truncated bits - * of unsigned types or all truncated bits plus the - * msb of the target for signed types are considered - * to be significant bits. Loss of significant bits - * means that at least on of the bits was set in an - * unsigned type or that at least one, but not all of - * the bits was set in an signed type. - * Loss of significant bits means that it is not - * possible, also not with necessary casts, to convert - * back to the original type. A example for a - * necessary cast is: - * char c; int i; c = 128; - * i = c; ** yields -128 ** - * i = (unsigned char)c; ** yields 128 ** - */ - if ((nt == CHAR || nt == UCHAR || nt == SCHAR) && - v->v_lspec == CHAR) { - /* - * Don't warn when assigning a character - * literal to any kind of character (signed, - * unsigned, or unspecified). - */ - } else if (op == ASSIGN && tp->t_isfield) { - /* precision lost in bit-field assignment */ - warning(166); - } else if (op == ASSIGN) { - /* constant truncated by assignment */ - warning(165); - } else if (op == INIT && tp->t_isfield) { - /* bit-field initializer does not fit */ - warning(180); - } else if (op == INIT) { - /* initializer does not fit */ - warning(178); - } else if (op == CASE) { - /* case label affected by conversion */ - warning(196); - } else if (op == FARG) { - /* %s arg #%d: conv. of %s to %s is out of rng. */ - warning(295, funcname(farg->fa_func), arg, - tyname(gettyp(ot)), tyname(tp)); - } else { - /* conversion of %s to %s is out of range */ - warning(119, tyname(gettyp(ot)), tyname(tp)); - } - } else if (nv->v_quad != v->v_quad) { - if ((nt == CHAR || nt == UCHAR || nt == SCHAR) && - v->v_lspec == CHAR) { - /* - * Don't warn when assigning a character - * literal to any kind of character (signed, - * unsigned, or unspecified). - */ - } else if (op == ASSIGN && tp->t_isfield) { - /* precision lost in bit-field assignment */ - warning(166); - } else if (op == INIT && tp->t_isfield) { - /* bit-field initializer out of range */ - warning(11); - } else if (op == CASE) { - /* case label affected by conversion */ - warning(196); - } else if (op == FARG) { - /* %s arg #%d: conv. of %s to %s is out of rng. */ - warning(295, funcname(farg->fa_func), arg, - tyname(gettyp(ot)), tyname(tp)); - } else { - /* conversion of %s to %s is out of range */ - warning(119, tyname(gettyp(ot)), tyname(tp)); - } - } - } -} - -/* - * Called if incompatible types were detected. - * Prints a appropriate warning. - */ -static void -incompat(op_t op, tspec_t lt, tspec_t rt) -{ - mod_t *mp; - - mp = &modtab[op]; - - if (lt == VOID || (mp->m_binary && rt == VOID)) { - /* void type illegal in expression */ - error(109); - } else if (op == ASSIGN) { - if ((lt == STRUCT || lt == UNION) && - (rt == STRUCT || rt == UNION)) { - /* assignment of different structures */ - error(240); - } else { - /* assignment type mismatch */ - error(171); - } - } else if (mp->m_binary) { - /* operands of %s have incompatible types */ - error(107, mp->m_name); - } else { - /* operand of %s has incompatible type */ - error(108, mp->m_name); - } -} - -/* - * Called if incompatible pointer types are detected. - * Print an appropriate warning. - */ -static void -illptrc(mod_t *mp, type_t *ltp, type_t *rtp) -{ - tspec_t lt, rt; - - if (ltp->t_tspec != PTR || rtp->t_tspec != PTR) - lerror("illptrc() 1"); - - lt = ltp->t_subt->t_tspec; - rt = rtp->t_subt->t_tspec; - - if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION)) { - if (mp == NULL) { - /* illegal structure pointer combination */ - warning(244); - } else { - /* illegal structure pointer combination, op %s */ - warning(245, mp->m_name); - } - } else { - if (mp == NULL) { - /* illegal pointer combination */ - warning(184); - } else { - /* illegal pointer combination, op %s */ - warning(124, mp->m_name); - } - } -} - -/* - * Make sure type (*tpp)->t_subt has at least the qualifiers - * of tp1->t_subt and tp2->t_subt. - */ -static void -mrgqual(type_t **tpp, type_t *tp1, type_t *tp2) -{ - if ((*tpp)->t_tspec != PTR || - tp1->t_tspec != PTR || tp2->t_tspec != PTR) { - lerror("mrgqual()"); - } - - if ((*tpp)->t_subt->t_const == - (tp1->t_subt->t_const | tp2->t_subt->t_const) && - (*tpp)->t_subt->t_volatile == - (tp1->t_subt->t_volatile | tp2->t_subt->t_volatile)) { - return; - } - - *tpp = tduptyp(*tpp); - (*tpp)->t_subt = tduptyp((*tpp)->t_subt); - (*tpp)->t_subt->t_const = - tp1->t_subt->t_const | tp2->t_subt->t_const; - (*tpp)->t_subt->t_volatile = - tp1->t_subt->t_volatile | tp2->t_subt->t_volatile; -} - -/* - * Returns 1 if the given structure or union has a constant member - * (maybe recursively). - */ -static int -conmemb(type_t *tp) -{ - sym_t *m; - tspec_t t; - - if ((t = tp->t_tspec) != STRUCT && t != UNION) - lerror("conmemb()"); - for (m = tp->t_str->memb; m != NULL; m = m->s_nxt) { - tp = m->s_type; - if (tp->t_const) - return (1); - if ((t = tp->t_tspec) == STRUCT || t == UNION) { - if (conmemb(m->s_type)) - return (1); - } - } - return (0); -} - -const char * -tyname(type_t *tp) -{ - tspec_t t; - const char *s; - - if ((t = tp->t_tspec) == INT && tp->t_isenum) - t = ENUM; - - switch (t) { - case BOOL: s = "_Bool"; break; - case CHAR: s = "char"; break; - case UCHAR: s = "unsigned char"; break; - case SCHAR: s = "signed char"; break; - case SHORT: s = "short"; break; - case USHORT: s = "unsigned short"; break; - case INT: s = "int"; break; - case UINT: s = "unsigned int"; break; - case LONG: s = "long"; break; - case ULONG: s = "unsigned long"; break; - case QUAD: s = "long long"; break; - case UQUAD: s = "unsigned long long"; break; - case FLOAT: s = "float"; break; - case DOUBLE: s = "double"; break; - case LDOUBLE: s = "long double"; break; - case COMPLEX: s = "float _Complex"; break; - case DCOMPLEX: s = "double _Complex"; break; - case LDCOMPLEX: s = "long double _Complex"; break; - case IMAGINARY: s = "float _Imaginary"; break; - case DIMAGINARY: s = "double _Imaginary"; break; - case LDIMAGINARY:s = "long double _Imaginary"; break; - case PTR: s = "pointer"; break; - case ENUM: s = "enum"; break; - case STRUCT: s = "struct"; break; - case UNION: s = "union"; break; - case FUNC: s = "function"; break; - case ARRAY: s = "array"; break; - default: - lerror("tyname()"); - } - return (s); -} - -/* - * Create a new node for one of the operators POINT and ARROW. - */ -static tnode_t * -bldstr(op_t op, tnode_t *ln, tnode_t *rn) -{ - tnode_t *ntn, *ctn; - int nolval; - - if (rn->tn_op != NAME) - lerror("bldstr() 1"); - if (rn->tn_sym->s_value.v_tspec != INT) - lerror("bldstr() 2"); - if (rn->tn_sym->s_scl != MOS && rn->tn_sym->s_scl != MOU) - lerror("bldstr() 3"); - - /* - * Remember if the left operand is an lvalue (structure members - * are lvalues if and only if the structure itself is an lvalue). - */ - nolval = op == POINT && !ln->tn_lvalue; - - if (op == POINT) { - ln = bldamper(ln, 1); - } else if (ln->tn_type->t_tspec != PTR) { - lerror("bldstr() 4"); - ln = convert(NOOP, NULL, tincref(gettyp(VOID), PTR), ln); - } - -#if PTRDIFF_IS_LONG - ctn = getinode(LONG, rn->tn_sym->s_value.v_quad / CHAR_BIT); -#else - ctn = getinode(INT, rn->tn_sym->s_value.v_quad / CHAR_BIT); -#endif - - ntn = mktnode(PLUS, tincref(rn->tn_type, PTR), ln, ctn); - if (ln->tn_op == CON) - ntn = fold(ntn); - - if (rn->tn_type->t_isfield) { - ntn = mktnode(FSEL, ntn->tn_type->t_subt, ntn, NULL); - } else { - ntn = mktnode(STAR, ntn->tn_type->t_subt, ntn, NULL); - } - - if (nolval) - ntn->tn_lvalue = 0; - - return (ntn); -} - -/* - * Create a node for INCAFT, INCBEF, DECAFT and DECBEF. - */ -static tnode_t * -bldincdec(op_t op, tnode_t *ln) -{ - tnode_t *cn, *ntn; - - if (ln == NULL) - lerror("bldincdec() 1"); - - if (ln->tn_type->t_tspec == PTR) { - cn = plength(ln->tn_type); - } else { - cn = getinode(INT, (quad_t)1); - } - ntn = mktnode(op, ln->tn_type, ln, cn); - - return (ntn); -} - -/* - * Create a tree node for the & operator - */ -static tnode_t * -bldamper(tnode_t *tn, int noign) -{ - tnode_t *ntn; - tspec_t t; - - if (!noign && ((t = tn->tn_type->t_tspec) == ARRAY || t == FUNC)) { - /* & before array or function: ignored */ - return (tn); - } - - /* eliminate &* */ - if (tn->tn_op == STAR && - tn->tn_left->tn_type->t_tspec == PTR && - tn->tn_left->tn_type->t_subt == tn->tn_type) { - return (tn->tn_left); - } - - ntn = mktnode(AMPER, tincref(tn->tn_type, PTR), tn, NULL); - - return (ntn); -} - -/* - * Create a node for operators PLUS and MINUS. - */ -static tnode_t * -bldplmi(op_t op, tnode_t *ln, tnode_t *rn) -{ - tnode_t *ntn, *ctn; - type_t *tp; - - /* If pointer and integer, then pointer to the lhs. */ - if (rn->tn_type->t_tspec == PTR && isityp(ln->tn_type->t_tspec)) { - ntn = ln; - ln = rn; - rn = ntn; - } - - if (ln->tn_type->t_tspec == PTR && rn->tn_type->t_tspec != PTR) { - - if (!isityp(rn->tn_type->t_tspec)) - lerror("bldplmi() 1"); - - ctn = plength(ln->tn_type); - if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec) - rn = convert(NOOP, NULL, ctn->tn_type, rn); - rn = mktnode(MULT, rn->tn_type, rn, ctn); - if (rn->tn_left->tn_op == CON) - rn = fold(rn); - ntn = mktnode(op, ln->tn_type, ln, rn); - - } else if (rn->tn_type->t_tspec == PTR) { - - if (ln->tn_type->t_tspec != PTR || op != MINUS) - lerror("bldplmi() 2"); -#if PTRDIFF_IS_LONG - tp = gettyp(LONG); -#else - tp = gettyp(INT); -#endif - ntn = mktnode(op, tp, ln, rn); - if (ln->tn_op == CON && rn->tn_op == CON) - ntn = fold(ntn); - ctn = plength(ln->tn_type); - balance(NOOP, &ntn, &ctn); - ntn = mktnode(DIV, tp, ntn, ctn); - - } else { - - ntn = mktnode(op, ln->tn_type, ln, rn); - - } - return (ntn); -} - -/* - * Create a node for operators SHL and SHR. - */ -static tnode_t * -bldshft(op_t op, tnode_t *ln, tnode_t *rn) -{ - tspec_t t; - tnode_t *ntn; - - if ((t = rn->tn_type->t_tspec) != INT && t != UINT) - rn = convert(CVT, NULL, gettyp(INT), rn); - ntn = mktnode(op, ln->tn_type, ln, rn); - return (ntn); -} - -/* - * Create a node for COLON. - */ -static tnode_t * -bldcol(tnode_t *ln, tnode_t *rn) -{ - tspec_t lt, rt, pdt; - type_t *rtp; - tnode_t *ntn; - - lt = ln->tn_type->t_tspec; - rt = rn->tn_type->t_tspec; -#if PTRDIFF_IS_LONG - pdt = LONG; -#else - pdt = INT; -#endif - - /* - * Arithmetic types are balanced, all other type combinations - * still need to be handled. - */ - if (isatyp(lt) && isatyp(rt)) { - rtp = ln->tn_type; - } else if (lt == VOID || rt == VOID) { - rtp = gettyp(VOID); - } else if (lt == STRUCT || lt == UNION) { - /* Both types must be identical. */ - if (rt != STRUCT && rt != UNION) - lerror("bldcol() 1"); - if (ln->tn_type->t_str != rn->tn_type->t_str) - lerror("bldcol() 2"); - if (incompl(ln->tn_type)) { - /* unknown operand size, op %s */ - error(138, modtab[COLON].m_name); - return (NULL); - } - rtp = ln->tn_type; - } else if (lt == PTR && isityp(rt)) { - if (rt != pdt) { - rn = convert(NOOP, NULL, gettyp(pdt), rn); - rt = pdt; - } - rtp = ln->tn_type; - } else if (rt == PTR && isityp(lt)) { - if (lt != pdt) { - ln = convert(NOOP, NULL, gettyp(pdt), ln); - lt = pdt; - } - rtp = rn->tn_type; - } else if (lt == PTR && ln->tn_type->t_subt->t_tspec == VOID) { - if (rt != PTR) - lerror("bldcol() 4"); - rtp = ln->tn_type; - mrgqual(&rtp, ln->tn_type, rn->tn_type); - } else if (rt == PTR && rn->tn_type->t_subt->t_tspec == VOID) { - if (lt != PTR) - lerror("bldcol() 5"); - rtp = rn->tn_type; - mrgqual(&rtp, ln->tn_type, rn->tn_type); - } else { - if (lt != PTR || rt != PTR) - lerror("bldcol() 6"); - /* - * XXX For now we simply take the left type. This is - * probably wrong, if one type contains a function prototype - * and the other one, at the same place, only an old style - * declaration. - */ - rtp = ln->tn_type; - mrgqual(&rtp, ln->tn_type, rn->tn_type); - } - - ntn = mktnode(COLON, rtp, ln, rn); - - return (ntn); -} - -/* - * Create a node for an assignment operator (both = and op= ). - */ -static tnode_t * -bldasgn(op_t op, tnode_t *ln, tnode_t *rn) -{ - tspec_t lt, rt; - tnode_t *ntn, *ctn; - - if (ln == NULL || rn == NULL) - lerror("bldasgn() 1"); - - lt = ln->tn_type->t_tspec; - rt = rn->tn_type->t_tspec; - - if ((op == ADDASS || op == SUBASS) && lt == PTR) { - if (!isityp(rt)) - lerror("bldasgn() 2"); - ctn = plength(ln->tn_type); - if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec) - rn = convert(NOOP, NULL, ctn->tn_type, rn); - rn = mktnode(MULT, rn->tn_type, rn, ctn); - if (rn->tn_left->tn_op == CON) - rn = fold(rn); - } - - if ((op == ASSIGN || op == RETURN) && (lt == STRUCT || rt == STRUCT)) { - if (rt != lt || ln->tn_type->t_str != rn->tn_type->t_str) - lerror("bldasgn() 3"); - if (incompl(ln->tn_type)) { - if (op == RETURN) { - /* cannot return incomplete type */ - error(212); - } else { - /* unknown operand size, op %s */ - error(138, modtab[op].m_name); - } - return (NULL); - } - } - - if (op == SHLASS || op == SHRASS) { - if (rt != INT) { - rn = convert(NOOP, NULL, gettyp(INT), rn); - rt = INT; - } - } else { - if (op == ASSIGN || lt != PTR) { - if (lt != rt || - (ln->tn_type->t_isfield && rn->tn_op == CON)) { - rn = convert(op, NULL, ln->tn_type, rn); - rt = lt; - } - } - } - - ntn = mktnode(op, ln->tn_type, ln, rn); - - return (ntn); -} - -/* - * Check for division by zero. Returns 1 if a division by zero is - * present, 0 otherwise. - */ -static int -chkdbz(op_t op, tnode_t *rn) -{ - int code; - - switch (op) { - case DIV: - case DIVASS: - code = 139; /* division by 0 */ - break; - case MOD: - case MODASS: - code = 140; /* modular division by 0 */ - break; - default: - return 0; - } - - /* no way of checking unless right side is a constant */ - if (rn->tn_op != CON) - return 0; - - if (isftyp(rn->tn_type->t_tspec)) { - if (rn->tn_val->v_ldbl == 0.0) { - /* division by 0 */ - warning(code); - return 1; - } - } else { - if (rn->tn_val->v_quad == 0) { - /* division by 0 */ - warning(code); - return 1; - } - } - - return 0; -} - -/* - * Get length of type tp->t_subt. - */ -static tnode_t * -plength(type_t *tp) -{ - int elem, elsz; - tspec_t st; - - if (tp->t_tspec != PTR) - lerror("plength() 1"); - tp = tp->t_subt; - - elem = 1; - elsz = 0; - - while (tp->t_tspec == ARRAY) { - elem *= tp->t_dim; - tp = tp->t_subt; - } - - switch (tp->t_tspec) { - case FUNC: - /* pointer to function is not allowed here */ - error(110); - break; - case VOID: - /* cannot do pointer arithmetic on operand of ... */ - (void)gnuism(136); - break; - case STRUCT: - case UNION: - if ((elsz = tp->t_str->size) == 0) - /* cannot do pointer arithmetic on operand of ... */ - error(136); - break; - case ENUM: - if (incompl(tp)) { - /* cannot do pointer arithmetic on operand of ... */ - warning(136); - } - /* FALLTHROUGH */ - default: - if ((elsz = size(tp->t_tspec)) == 0) { - /* cannot do pointer arithmetic on operand of ... */ - error(136); - } else if (elsz == -1) { - lerror("plength() 2"); - } - break; - } - - if (elem == 0 && elsz != 0) { - /* cannot do pointer arithmetic on operand of ... */ - error(136); - } - - if (elsz == 0) - elsz = CHAR_BIT; - -#if PTRDIFF_IS_LONG - st = LONG; -#else - st = INT; -#endif - - return (getinode(st, (quad_t)(elem * elsz / CHAR_BIT))); -} - -/* - * Do only as much as necessary to compute constant expressions. - * Called only if the operator allows folding and (both) operands - * are constants. - */ -static tnode_t * -fold(tnode_t *tn) -{ - val_t *v; - tspec_t t; - int utyp, ovfl; - quad_t sl, sr, q, mask; - u_quad_t ul, ur; - tnode_t *cn; - - v = xcalloc(1, sizeof (val_t)); - v->v_tspec = t = tn->tn_type->t_tspec; - - utyp = t == PTR || isutyp(t); - ul = sl = tn->tn_left->tn_val->v_quad; - if (modtab[tn->tn_op].m_binary) - ur = sr = tn->tn_right->tn_val->v_quad; - - ovfl = 0; - - switch (tn->tn_op) { - case UPLUS: - q = sl; - break; - case UMINUS: - q = -sl; - if (msb(q, t, -1) == msb(sl, t, -1)) - ovfl = 1; - break; - case COMPL: - q = ~sl; - break; - case MULT: - q = utyp ? ul * ur : sl * sr; - if (msb(q, t, -1) != (msb(sl, t, -1) ^ msb(sr, t, -1))) - ovfl = 1; - break; - case DIV: - if (chkdbz(tn->tn_op, tn->tn_right)) { - q = utyp ? 0U: 0; - } else { - q = utyp ? ul / ur : sl / sr; - } - break; - case MOD: - if (chkdbz(tn->tn_op, tn->tn_right)) { - q = 0; - } else { - q = utyp ? ul % ur : sl % sr; - } - break; - case PLUS: - q = utyp ? ul + ur : sl + sr; - if (msb(sl, t, -1) != 0 && msb(sr, t, -1) != 0) { - if (msb(q, t, -1) == 0) - ovfl = 1; - } else if (msb(sl, t, -1) == 0 && msb(sr, t, -1) == 0) { - if (msb(q, t, -1) != 0) - ovfl = 1; - } - break; - case MINUS: - q = utyp ? ul - ur : sl - sr; - if (msb(sl, t, -1) != 0 && msb(sr, t, -1) == 0) { - if (msb(q, t, -1) == 0) - ovfl = 1; - } else if (msb(sl, t, -1) == 0 && msb(sr, t, -1) != 0) { - if (msb(q, t, -1) != 0) - ovfl = 1; - } - break; - case SHL: - q = utyp ? ul << sr : sl << sr; - break; - case SHR: - /* - * The sign must be explicitly extended because - * shifts of signed values are implementation dependent. - */ - q = ul >> sr; - q = xsign(q, t, size(t) - (int)sr); - break; - case LT: - q = utyp ? ul < ur : sl < sr; - break; - case LE: - q = utyp ? ul <= ur : sl <= sr; - break; - case GE: - q = utyp ? ul >= ur : sl >= sr; - break; - case GT: - q = utyp ? ul > ur : sl > sr; - break; - case EQ: - q = utyp ? ul == ur : sl == sr; - break; - case NE: - q = utyp ? ul != ur : sl != sr; - break; - case AND: - q = utyp ? ul & ur : sl & sr; - break; - case XOR: - q = utyp ? ul ^ ur : sl ^ sr; - break; - case OR: - q = utyp ? ul | ur : sl | sr; - break; - case REAL: - case IMAG: - q = sl; - default: - lerror("fold() 5"); - } - - mask = qlmasks[size(t)]; - - /* XXX does not work for quads. */ - if (ovfl || ((q | mask) != ~(u_quad_t)0 && (q & ~mask) != 0)) { - if (hflag) - /* integer overflow detected, op %s */ - warning(141, modtab[tn->tn_op].m_name); - } - - v->v_quad = xsign(q, t, -1); - - cn = getcnode(tn->tn_type, v); - - return (cn); -} - -/* - * Same for operators whose operands are compared with 0 (test context). - */ -static tnode_t * -foldtst(tnode_t *tn) -{ - int l, r; - val_t *v; - - v = xcalloc(1, sizeof (val_t)); - v->v_tspec = tn->tn_type->t_tspec; - if (tn->tn_type->t_tspec != INT) - lerror("foldtst() 1"); - - if (isftyp(tn->tn_left->tn_type->t_tspec)) { - l = tn->tn_left->tn_val->v_ldbl != 0.0; - } else { - l = tn->tn_left->tn_val->v_quad != 0; - } - - if (modtab[tn->tn_op].m_binary) { - if (isftyp(tn->tn_right->tn_type->t_tspec)) { - r = tn->tn_right->tn_val->v_ldbl != 0.0; - } else { - r = tn->tn_right->tn_val->v_quad != 0; - } - } - - switch (tn->tn_op) { - case NOT: - if (hflag) - /* constant argument to NOT */ - warning(239); - v->v_quad = !l; - break; - case LOGAND: - v->v_quad = l && r; - break; - case LOGOR: - v->v_quad = l || r; - break; - default: - lerror("foldtst() 1"); - } - - return (getcnode(tn->tn_type, v)); -} - -/* - * Same for operands with floating point type. - */ -static tnode_t * -foldflt(tnode_t *tn) -{ - val_t *v; - tspec_t t; - ldbl_t l, r; - - v = xcalloc(1, sizeof (val_t)); - v->v_tspec = t = tn->tn_type->t_tspec; - - if (!isftyp(t)) - lerror("foldflt() 1"); - - if (t != tn->tn_left->tn_type->t_tspec) - lerror("foldflt() 2"); - if (modtab[tn->tn_op].m_binary && t != tn->tn_right->tn_type->t_tspec) - lerror("foldflt() 3"); - - l = tn->tn_left->tn_val->v_ldbl; - if (modtab[tn->tn_op].m_binary) - r = tn->tn_right->tn_val->v_ldbl; - - switch (tn->tn_op) { - case UPLUS: - v->v_ldbl = l; - break; - case UMINUS: - v->v_ldbl = -l; - break; - case MULT: - v->v_ldbl = l * r; - break; - case DIV: - if (chkdbz(tn->tn_op, tn->tn_right)) { - if (t == FLOAT) { - v->v_ldbl = l < 0 ? -FLT_MAX : FLT_MAX; - } else if (t == DOUBLE) { - v->v_ldbl = l < 0 ? -DBL_MAX : DBL_MAX; - } else { - v->v_ldbl = l < 0 ? -LDBL_MAX : LDBL_MAX; - } - } else { - v->v_ldbl = l / r; - } - break; - case PLUS: - v->v_ldbl = l + r; - break; - case MINUS: - v->v_ldbl = l - r; - break; - case LT: - v->v_quad = l < r; - break; - case LE: - v->v_quad = l <= r; - break; - case GE: - v->v_quad = l >= r; - break; - case GT: - v->v_quad = l > r; - break; - case EQ: - v->v_quad = l == r; - break; - case NE: - v->v_quad = l != r; - break; - case REAL: - case IMAG: - v->v_ldbl = l; - break; - default: - lerror("foldflt() 4"); - } - - if (isnan((double)v->v_ldbl)) - lerror("foldflt() 5"); - if (isinf((double)v->v_ldbl) || - (t == FLOAT && - (v->v_ldbl > FLT_MAX || v->v_ldbl < -FLT_MAX)) || - (t == DOUBLE && - (v->v_ldbl > DBL_MAX || v->v_ldbl < -DBL_MAX))) { - /* floating point overflow detected, op %s */ - warning(142, modtab[tn->tn_op].m_name); - if (t == FLOAT) { - v->v_ldbl = v->v_ldbl < 0 ? -FLT_MAX : FLT_MAX; - } else if (t == DOUBLE) { - v->v_ldbl = v->v_ldbl < 0 ? -DBL_MAX : DBL_MAX; - } else { - v->v_ldbl = v->v_ldbl < 0 ? -LDBL_MAX: LDBL_MAX; - } - } - - return (getcnode(tn->tn_type, v)); -} - -/* - * Create a constant node for sizeof(term). - */ -tnode_t * -bldszoftrm(tnode_t *tn) -{ - switch (tn->tn_op) { - case POINT: - case STAR: - case NAME: - case STRING: - case REAL: - case IMAG: - break; - default: - warning(312, modtab[tn->tn_op].m_name); - } - - - return bldszof(tn->tn_type); -} - -/* - * Create a constant node for sizeof. - */ -tnode_t * -bldszof(type_t *tp) -{ - int elem, elsz; - tspec_t st; - - elem = 1; - while (tp->t_tspec == ARRAY) { - elem *= tp->t_dim; - tp = tp->t_subt; - } - if (elem == 0) { - /* cannot take size of incomplete type */ - error(143); - elem = 1; - } - switch (tp->t_tspec) { - case FUNC: - /* cannot take size of function */ - error(144); - elsz = 1; - break; - case STRUCT: - case UNION: - if (incompl(tp)) { - /* cannot take size of incomplete type */ - error(143); - elsz = 1; - } else { - elsz = tp->t_str->size; - } - break; - case ENUM: - if (incompl(tp)) { - /* cannot take size of incomplete type */ - warning(143); - } - /* FALLTHROUGH */ - default: - if (tp->t_isfield) { - /* cannot take size of bit-field */ - error(145); - } - if (tp->t_tspec == VOID) { - /* cannot take size of void */ - error(146); - elsz = 1; - } else { - elsz = size(tp->t_tspec); - if (elsz <= 0) - lerror("bldszof() 1"); - } - break; - } - -#if SIZEOF_IS_ULONG - st = ULONG; -#else - st = UINT; -#endif - - return (getinode(st, (quad_t)(elem * elsz / CHAR_BIT))); -} - -/* - * Type casts. - */ -tnode_t * -cast(tnode_t *tn, type_t *tp) -{ - tspec_t nt, ot; - - if (tn == NULL) - return (NULL); - - tn = cconv(tn); - - nt = tp->t_tspec; - ot = tn->tn_type->t_tspec; - - if (nt == VOID) { - /* - * XXX ANSI C requires scalar types or void (Plauger&Brodie). - * But this seams really questionable. - */ - } else if (nt == STRUCT || nt == UNION || nt == ARRAY || nt == FUNC) { - /* invalid cast expression */ - error(147); - return (NULL); - } else if (ot == STRUCT || ot == UNION) { - /* invalid cast expression */ - error(147); - return (NULL); - } else if (ot == VOID) { - /* improper cast of void expression */ - error(148); - return (NULL); - } else if (isityp(nt) && issclt(ot)) { - /* ok */ - } else if (isftyp(nt) && isatyp(ot)) { - /* ok */ - } else if (nt == PTR && isityp(ot)) { - /* ok */ - } else if (nt == PTR && ot == PTR) { - if (!tp->t_subt->t_const && tn->tn_type->t_subt->t_const) { - if (hflag) - /* cast discards 'const' from ... */ - warning(275); - } - } else { - /* invalid cast expression */ - error(147); - return (NULL); - } - - tn = convert(CVT, NULL, tp, tn); - tn->tn_cast = 1; - - return (tn); -} - -/* - * Create the node for a function argument. - * All necessary conversions and type checks are done in funccall(), because - * in funcarg() we have no information about expected argument types. - */ -tnode_t * -funcarg(tnode_t *args, tnode_t *arg) -{ - tnode_t *ntn; - - /* - * If there was a serious error in the expression for the argument, - * create a dummy argument so the positions of the remaining arguments - * will not change. - */ - if (arg == NULL) - arg = getinode(INT, (quad_t)0); - - ntn = mktnode(PUSH, arg->tn_type, arg, args); - - return (ntn); -} - -/* - * Create the node for a function call. Also check types of - * function arguments and insert conversions, if necessary. - */ -tnode_t * -funccall(tnode_t *func, tnode_t *args) -{ - tnode_t *ntn; - op_t fcop; - - if (func == NULL) - return (NULL); - - if (func->tn_op == NAME && func->tn_type->t_tspec == FUNC) { - fcop = CALL; - } else { - fcop = ICALL; - } - - /* - * after cconv() func will always be a pointer to a function - * if it is a valid function designator. - */ - func = cconv(func); - - if (func->tn_type->t_tspec != PTR || - func->tn_type->t_subt->t_tspec != FUNC) { - /* illegal function */ - error(149); - return (NULL); - } - - args = chkfarg(func, args); - - ntn = mktnode(fcop, func->tn_type->t_subt->t_subt, func, args); - - return (ntn); -} - -/* - * Check types of all function arguments and insert conversions, - * if necessary. - * - * func: called function - * args: arguments to function - */ -static tnode_t * -chkfarg(tnode_t *func, tnode_t *args) -{ - type_t *ftp; - tnode_t *arg; - sym_t *asym; - farg_t farg; - tspec_t at; - int narg, npar, n, i; - - ftp = func->tn_type->t_subt; - - /* get # of args in the prototype */ - npar = 0; - for (asym = ftp->t_args; asym != NULL; asym = asym->s_nxt) - npar++; - - /* get # of args in function call */ - narg = 0; - for (arg = args; arg != NULL; arg = arg->tn_right) - narg++; - - asym = ftp->t_args; - if (ftp->t_proto && npar != narg && !(ftp->t_vararg && npar < narg)) { - /* argument mismatch: %d arg%s passed, %d expected */ - error(150, narg, narg > 1 ? "s" : "", npar); - asym = NULL; - } - - for (n = 1; n <= narg; n++) { - - /* - * The rightmost argument is at the top of the argument - * subtree. - */ - for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ; - - /* some things which are never allowed */ - if ((at = arg->tn_left->tn_type->t_tspec) == VOID) { - /* void expressions may not be arguments, arg #%d */ - error(151, n); - return (NULL); - } else if ((at == STRUCT || at == UNION) && - incompl(arg->tn_left->tn_type)) { - /* argument cannot have unknown size, arg #%d */ - error(152, n); - return (NULL); - } else if (isityp(at) && arg->tn_left->tn_type->t_isenum && - incompl(arg->tn_left->tn_type)) { - /* argument cannot have unknown size, arg #%d */ - warning(152, n); - } - - /* class conversions (arg in value context) */ - arg->tn_left = cconv(arg->tn_left); - farg.fa_num = n; - farg.fa_sym = asym; - farg.fa_func = func; - if (asym != NULL) { - arg->tn_left = parg(&farg, arg->tn_left); - } else { - arg->tn_left = promote(NOOP, 1, arg->tn_left); - } - arg->tn_type = arg->tn_left->tn_type; - - if (asym != NULL) - asym = asym->s_nxt; - } - - return (args); -} - -/* - * Compare the type of an argument with the corresponding type of a - * prototype parameter. If it is a valid combination, but both types - * are not the same, insert a conversion to convert the argument into - * the type of the parameter. - * - * n: position of arg - * tp: expected type (from prototype) - * tn: argument - */ -static tnode_t * -parg(farg_t *farg, tnode_t *tn) -{ - tnode_t *ln; - type_t *tp; - int warn; - - tp = farg->fa_sym->s_type; - ln = xcalloc(1, sizeof (tnode_t)); - ln->tn_type = tduptyp(tp); - ln->tn_type->t_const = 0; - ln->tn_lvalue = 1; - if (typeok(FARG, farg, ln, tn)) { - if (!eqtype(tp, tn->tn_type, 1, 0, (warn = 0, &warn)) || warn) - tn = convert(FARG, farg, tp, tn); - } - free(ln); - return (tn); -} - -/* - * Return the value of an integral constant expression. - * If the expression is not constant or its type is not an integer - * type, an error message is printed. - */ -val_t * -constant(tnode_t *tn) -{ - val_t *v; - - if (tn != NULL) - tn = cconv(tn); - if (tn != NULL) - tn = promote(NOOP, 0, tn); - - v = xcalloc(1, sizeof (val_t)); - - if (tn == NULL) { - if (nerr == 0) - lerror("constant() 1"); - v->v_tspec = INT; - v->v_quad = 1; - return (v); - } - - v->v_tspec = tn->tn_type->t_tspec; - - if (tn->tn_op == CON) { - if (tn->tn_type->t_tspec != tn->tn_val->v_tspec) - lerror("constant() 2"); - if (isityp(tn->tn_val->v_tspec)) { - v->v_ansiu = tn->tn_val->v_ansiu; - v->v_quad = tn->tn_val->v_quad; - return (v); - } - v->v_quad = tn->tn_val->v_ldbl; - } else { - v->v_quad = 1; - } - - /* integral constant expression expected */ - error(55); - - if (!isityp(v->v_tspec)) - v->v_tspec = INT; - - return (v); -} - -/* - * Perform some tests on expressions which can't be done in build() and - * functions called by build(). These tests must be done here because - * we need some information about the context in which the operations - * are performed. - * After all tests are performed, expr() frees the memory which is used - * for the expression. - */ -void -expr(tnode_t *tn, int vctx, int tctx) -{ - if (tn == NULL && nerr == 0) - lerror("expr() 1"); - - if (tn == NULL) { - tfreeblk(); - return; - } - - /* expr() is also called in global initialisations */ - if (dcs->d_ctx != EXTERN) - chkreach(); - - chkmisc(tn, vctx, tctx, !tctx, 0, 0, 0); - if (tn->tn_op == ASSIGN) { - if (hflag && tctx && !tn->tn_parn) - /* assignment in conditional context */ - warning(159); - } else if (tn->tn_op == CON) { - if (hflag && tctx && !ccflg) { - if (!isityp(tn->tn_type->t_tspec) || - (tn->tn_val->v_quad != 0 && - tn->tn_val->v_quad != 1)) { - /* constant in conditional context */ - warning(161); - } - } - } else if (tn->tn_op == CALL && tn->tn_left->tn_op == AMPER) { - if (tn->tn_left->tn_left->tn_sym->s_noreturn) - reached = rchflg = 0; - } - - if (!modtab[tn->tn_op].m_sideeff) { - /* - * for left operands of COMMA this warning is already - * printed - */ - if (tn->tn_op != COMMA && !vctx && !tctx) - nulleff(tn); - } - if (dflag) - displexpr(tn, 0); - - /* free the tree memory */ - tfreeblk(); -} - -static void -nulleff(tnode_t *tn) -{ - if (!hflag) - return; - if (nulleffexpr(tn)) { - /* expression has null effect */ - warning(129); - } -} - -static int -nulleffexpr(tnode_t *tn) -{ - int r1, r2; - - if (modtab[tn->tn_op].m_sideeff) - return (0); - - switch (tn->tn_op) { - case CVT: - if (tn->tn_type->t_tspec == VOID) - return (0); - else - return (nulleffexpr(tn->tn_left)); - case LOGAND: - case LOGOR: - /* - * && and || have a null effect if the right operand - * has null effect. - */ - return (nulleffexpr(tn->tn_right)); - case QUEST: - /* - * ? has null effect if both of its right * operands - * have null effect - */ - return (nulleffexpr(tn->tn_right)); - case COLON: - case COMMA: - /* - * : and , have null effect if both of the operands have - * null effect - */ - r1 = nulleffexpr(tn->tn_left); - r2 = nulleffexpr(tn->tn_right); - return (r1 && r2); - default: - return (1); - } -} - -/* - * Dump an expression to stdout - * only used for debugging - */ -void -displexpr(tnode_t *tn, int offs) -{ - u_quad_t uq; - - if (tn == NULL) { - (void)printf("%*s%s\n", offs, "", "NULL"); - return; - } - (void)printf("%*sop %s ", offs, "", modtab[tn->tn_op].m_name); - - if (tn->tn_op == NAME) { - (void)printf("%s: %s ", - tn->tn_sym->s_name, scltoa(tn->tn_sym->s_scl)); - } else if (tn->tn_op == CON && isftyp(tn->tn_type->t_tspec)) { - (void)printf("%#g ", (double)tn->tn_val->v_ldbl); - } else if (tn->tn_op == CON && isityp(tn->tn_type->t_tspec)) { - uq = tn->tn_val->v_quad; - (void)printf("0x %08lx %08lx ", (long)(uq >> 32) & 0xffffffffl, - (long)uq & 0xffffffffl); - } else if (tn->tn_op == CON) { - if (tn->tn_type->t_tspec != PTR) - lerror("displexpr() 1"); - (void)printf("0x%0*lx ", (int)(sizeof (void *) * CHAR_BIT / 4), - (u_long)tn->tn_val->v_quad); - } else if (tn->tn_op == STRING) { - if (tn->tn_strg->st_tspec == CHAR) { - (void)printf("\"%s\"", tn->tn_strg->st_cp); - } else { - char *s; - size_t n; - n = MB_CUR_MAX * (tn->tn_strg->st_len + 1); - s = xmalloc(n); - (void)wcstombs(s, tn->tn_strg->st_wcp, n); - (void)printf("L\"%s\"", s); - free(s); - } - (void)printf(" "); - } else if (tn->tn_op == FSEL) { - (void)printf("o=%d, l=%d ", tn->tn_type->t_foffs, - tn->tn_type->t_flen); - } - (void)printf("%s\n", ttos(tn->tn_type)); - if (tn->tn_op == NAME || tn->tn_op == CON || tn->tn_op == STRING) - return; - displexpr(tn->tn_left, offs + 2); - if (modtab[tn->tn_op].m_binary || - (tn->tn_op == PUSH && tn->tn_right != NULL)) { - displexpr(tn->tn_right, offs + 2); - } -} - -/* - * Called by expr() to recursively perform some tests. - */ -/* ARGSUSED */ -void -chkmisc(tnode_t *tn, int vctx, int tctx, int eqwarn, int fcall, int rvdisc, - int szof) -{ - tnode_t *ln, *rn; - mod_t *mp; - int nrvdisc, cvctx, ctctx; - op_t op; - scl_t sc; - dinfo_t *di; - - if (tn == NULL) - return; - - ln = tn->tn_left; - rn = tn->tn_right; - mp = &modtab[op = tn->tn_op]; - - switch (op) { - case AMPER: - if (ln->tn_op == NAME && (reached || rchflg)) { - if (!szof) - setsflg(ln->tn_sym); - setuflg(ln->tn_sym, fcall, szof); - } - if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS) - /* check the range of array indices */ - chkaidx(ln->tn_left, 1); - break; - case LOAD: - if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS) - /* check the range of array indices */ - chkaidx(ln->tn_left, 0); - /* FALLTHROUGH */ - case PUSH: - case INCBEF: - case DECBEF: - case INCAFT: - case DECAFT: - case ADDASS: - case SUBASS: - case MULASS: - case DIVASS: - case MODASS: - case ANDASS: - case ORASS: - case XORASS: - case SHLASS: - case SHRASS: - case REAL: - case IMAG: - if (ln->tn_op == NAME && (reached || rchflg)) { - sc = ln->tn_sym->s_scl; - /* - * Look if there was an asm statement in one of the - * compound statements we are in. If not, we don't - * print a warning. - */ - for (di = dcs; di != NULL; di = di->d_nxt) { - if (di->d_asm) - break; - } - if (sc != EXTERN && sc != STATIC && - !ln->tn_sym->s_set && !szof && di == NULL) { - /* %s may be used before set */ - warning(158, ln->tn_sym->s_name); - setsflg(ln->tn_sym); - } - setuflg(ln->tn_sym, 0, 0); - } - break; - case ASSIGN: - if (ln->tn_op == NAME && !szof && (reached || rchflg)) { - setsflg(ln->tn_sym); - if (ln->tn_sym->s_scl == EXTERN) - outusg(ln->tn_sym); - } - if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS) - /* check the range of array indices */ - chkaidx(ln->tn_left, 0); - break; - case CALL: - if (ln->tn_op != AMPER || ln->tn_left->tn_op != NAME) - lerror("chkmisc() 1"); - if (!szof) - outcall(tn, vctx || tctx, rvdisc); - break; - case EQ: - /* equality operator "==" found where "=" was exp. */ - if (hflag && eqwarn) - warning(160); - break; - case CON: - case NAME: - case STRING: - return; - /* LINTED (enumeration values not handled in switch) */ - } - - cvctx = mp->m_vctx; - ctctx = mp->m_tctx; - /* - * values of operands of ':' are not used if the type of at least - * one of the operands (for gcc compatibility) is void - * XXX test/value context of QUEST should probably be used as - * context for both operands of COLON - */ - if (op == COLON && tn->tn_type->t_tspec == VOID) - cvctx = ctctx = 0; - nrvdisc = op == CVT && tn->tn_type->t_tspec == VOID; - chkmisc(ln, cvctx, ctctx, mp->m_eqwarn, op == CALL, nrvdisc, szof); - - switch (op) { - case PUSH: - if (rn != NULL) - chkmisc(rn, 0, 0, mp->m_eqwarn, 0, 0, szof); - break; - case LOGAND: - case LOGOR: - chkmisc(rn, 0, 1, mp->m_eqwarn, 0, 0, szof); - break; - case COLON: - chkmisc(rn, cvctx, ctctx, mp->m_eqwarn, 0, 0, szof); - break; - default: - if (mp->m_binary) - chkmisc(rn, 1, 0, mp->m_eqwarn, 0, 0, szof); - break; - } - -} - -/* - * Checks the range of array indices, if possible. - * amper is set if only the address of the element is used. This - * means that the index is allowd to refer to the first element - * after the array. - */ -static void -chkaidx(tnode_t *tn, int amper) -{ - int dim; - tnode_t *ln, *rn; - int elsz; - quad_t con; - - ln = tn->tn_left; - rn = tn->tn_right; - - /* We can only check constant indices. */ - if (rn->tn_op != CON) - return; - - /* Return if the left node does not stem from an array. */ - if (ln->tn_op != AMPER) - return; - if (ln->tn_left->tn_op != STRING && ln->tn_left->tn_op != NAME) - return; - if (ln->tn_left->tn_type->t_tspec != ARRAY) - return; - - /* - * For incomplete array types, we can print a warning only if - * the index is negative. - */ - if (incompl(ln->tn_left->tn_type) && rn->tn_val->v_quad >= 0) - return; - - /* Get the size of one array element */ - if ((elsz = length(ln->tn_type->t_subt, NULL)) == 0) - return; - elsz /= CHAR_BIT; - - /* Change the unit of the index from bytes to element size. */ - if (isutyp(rn->tn_type->t_tspec)) { - con = (u_quad_t)rn->tn_val->v_quad / elsz; - } else { - con = rn->tn_val->v_quad / elsz; - } - - dim = ln->tn_left->tn_type->t_dim + (amper ? 1 : 0); - - if (!isutyp(rn->tn_type->t_tspec) && con < 0) { - /* array subscript cannot be negative: %ld */ - warning(167, (long)con); - } else if (dim > 0 && (u_quad_t)con >= dim) { - /* array subscript cannot be > %d: %ld */ - warning(168, dim - 1, (long)con); - } -} - -/* - * Check for ordered comparisons of unsigned values with 0. - */ -static void -chkcomp(op_t op, tnode_t *ln, tnode_t *rn) -{ - tspec_t lt, rt; - mod_t *mp; - - lt = ln->tn_type->t_tspec; - rt = rn->tn_type->t_tspec; - mp = &modtab[op]; - - if (ln->tn_op != CON && rn->tn_op != CON) - return; - - if (!isityp(lt) || !isityp(rt)) - return; - - if ((hflag || pflag) && lt == CHAR && rn->tn_op == CON && - (rn->tn_val->v_quad < 0 || - rn->tn_val->v_quad > ~(~0 << (CHAR_BIT - 1)))) { - /* nonportable character comparison, op %s */ - warning(230, mp->m_name); - return; - } - if ((hflag || pflag) && rt == CHAR && ln->tn_op == CON && - (ln->tn_val->v_quad < 0 || - ln->tn_val->v_quad > ~(~0 << (CHAR_BIT - 1)))) { - /* nonportable character comparison, op %s */ - warning(230, mp->m_name); - return; - } - if (isutyp(lt) && !isutyp(rt) && - rn->tn_op == CON && rn->tn_val->v_quad <= 0) { - if (rn->tn_val->v_quad < 0) { - /* comparison of %s with %s, op %s */ - warning(162, tyname(ln->tn_type), "negative constant", - mp->m_name); - } else if (op == LT || op == GE || (hflag && op == LE)) { - /* comparison of %s with %s, op %s */ - warning(162, tyname(ln->tn_type), "0", mp->m_name); - } - return; - } - if (isutyp(rt) && !isutyp(lt) && - ln->tn_op == CON && ln->tn_val->v_quad <= 0) { - if (ln->tn_val->v_quad < 0) { - /* comparison of %s with %s, op %s */ - warning(162, "negative constant", tyname(rn->tn_type), - mp->m_name); - } else if (op == GT || op == LE || (hflag && op == GE)) { - /* comparison of %s with %s, op %s */ - warning(162, "0", tyname(rn->tn_type), mp->m_name); - } - return; - } -} - -/* - * Takes an expression and returns 0 if this expression can be used - * for static initialisation, otherwise -1. - * - * Constant initialisation expressions must be costant or an address - * of a static object with an optional offset. In the first case, - * the result is returned in *offsp. In the second case, the static - * object is returned in *symp and the offset in *offsp. - * - * The expression can consist of PLUS, MINUS, AMPER, NAME, STRING and - * CON. Type conversions are allowed if they do not change binary - * representation (including width). - */ -int -conaddr(tnode_t *tn, sym_t **symp, ptrdiff_t *offsp) -{ - sym_t *sym; - ptrdiff_t offs1, offs2; - tspec_t t, ot; - - switch (tn->tn_op) { - case MINUS: - if (tn->tn_right->tn_op != CON) - return (-1); - /* FALLTHROUGH */ - case PLUS: - offs1 = offs2 = 0; - if (tn->tn_left->tn_op == CON) { - offs1 = (ptrdiff_t)tn->tn_left->tn_val->v_quad; - if (conaddr(tn->tn_right, &sym, &offs2) == -1) - return (-1); - } else if (tn->tn_right->tn_op == CON) { - offs2 = (ptrdiff_t)tn->tn_right->tn_val->v_quad; - if (tn->tn_op == MINUS) - offs2 = -offs2; - if (conaddr(tn->tn_left, &sym, &offs1) == -1) - return (-1); - } else { - return (-1); - } - *symp = sym; - *offsp = offs1 + offs2; - break; - case AMPER: - if (tn->tn_left->tn_op == NAME) { - *symp = tn->tn_left->tn_sym; - *offsp = 0; - } else if (tn->tn_left->tn_op == STRING) { - /* - * If this would be the front end of a compiler we - * would return a label instead of 0. - */ - *offsp = 0; - } - break; - case CVT: - t = tn->tn_type->t_tspec; - ot = tn->tn_left->tn_type->t_tspec; - if ((!isityp(t) && t != PTR) || (!isityp(ot) && ot != PTR)) { - return (-1); - } else if (psize(t) != psize(ot)) { - return (-1); - } - if (conaddr(tn->tn_left, symp, offsp) == -1) - return (-1); - break; - default: - return (-1); - } - return (0); -} - -/* - * Concatenate two string constants. - */ -strg_t * -catstrg(strg_t *strg1, strg_t *strg2) -{ - size_t len1, len2, len; - - if (strg1->st_tspec != strg2->st_tspec) { - /* cannot concatenate wide and regular string literals */ - error(292); - return (strg1); - } - - len = (len1 = strg1->st_len) + (len2 = strg2->st_len); - - if (strg1->st_tspec == CHAR) { - strg1->st_cp = xrealloc(strg1->st_cp, len + 1); - (void)memcpy(strg1->st_cp + len1, strg2->st_cp, len2 + 1); - free(strg2->st_cp); - } else { - strg1->st_wcp = xrealloc(strg1->st_wcp, - (len + 1) * sizeof (wchar_t)); - (void)memcpy(strg1->st_wcp + len1, strg2->st_wcp, - (len2 + 1) * sizeof (wchar_t)); - free(strg2->st_wcp); - } - strg1->st_len = len; - free(strg2); - - return (strg1); -} - -/* - * Print a warning if the given node has operands which should be - * parenthesized. - * - * XXX Does not work if an operand is a constant expression. Constant - * expressions are already folded. - */ -static void -precconf(tnode_t *tn) -{ - tnode_t *ln, *rn; - op_t lop, rop = NOOP; - int lparn, rparn; - mod_t *mp; - int warn; - - if (!hflag) - return; - - mp = &modtab[tn->tn_op]; - - lparn = 0; - for (ln = tn->tn_left; ln->tn_op == CVT; ln = ln->tn_left) - lparn |= ln->tn_parn; - lparn |= ln->tn_parn; - lop = ln->tn_op; - - if (mp->m_binary) { - rparn = 0; - for (rn = tn->tn_right; tn->tn_op == CVT; rn = rn->tn_left) - rparn |= rn->tn_parn; - rparn |= rn->tn_parn; - rop = rn->tn_op; - } - - warn = 0; - - switch (tn->tn_op) { - case SHL: - case SHR: - if (!lparn && (lop == PLUS || lop == MINUS)) { - warn = 1; - } else if (!rparn && (rop == PLUS || rop == MINUS)) { - warn = 1; - } - break; - case LOGOR: - if (!lparn && lop == LOGAND) { - warn = 1; - } else if (!rparn && rop == LOGAND) { - warn = 1; - } - break; - case AND: - case XOR: - case OR: - if (!lparn && lop != tn->tn_op) { - if (lop == PLUS || lop == MINUS) { - warn = 1; - } else if (lop == AND || lop == XOR) { - warn = 1; - } - } - if (!warn && !rparn && rop != tn->tn_op) { - if (rop == PLUS || rop == MINUS) { - warn = 1; - } else if (rop == AND || rop == XOR) { - warn = 1; - } - } - break; - /* LINTED (enumeration values not handled in switch) */ - } - - if (warn) { - /* precedence confusion possible: parenthesize! */ - warning(169); - } - -} - -/* - * Return the function name of a function (or of a pointer to a - * function). - */ -const char * -funcname(tnode_t *tn) -{ - /* dereference function pointer */ - switch (tn->tn_op) { - case AMPER: - return funcname(tn->tn_left); - case LOAD: - /* called as (*fptr)(args) */ - return funcname(tn->tn_left); - case CALL: - return funcname(tn->tn_left); - case NAME: - return tn->tn_sym->s_name; - default: - return "<unknown>"; - } -} |