summaryrefslogtreecommitdiff
path: root/usr.bin/xlint/lint1/tree.c
diff options
context:
space:
mode:
authorrillig <rillig@NetBSD.org>2023-02-24 19:18:50 +0000
committerrillig <rillig@NetBSD.org>2023-02-24 19:18:50 +0000
commit241e4fd4f6a26778fbf3c6f0cba0975fe64f07b8 (patch)
treedf33f683178737a9a44f6dda1bb825086866dbdf /usr.bin/xlint/lint1/tree.c
parent099ef1b4e3973712427ffdc720317b2102a890db (diff)
lint: order functions to to reduce forward declarations
No functional change.
Diffstat (limited to 'usr.bin/xlint/lint1/tree.c')
-rw-r--r--usr.bin/xlint/lint1/tree.c3536
1 files changed, 1747 insertions, 1789 deletions
diff --git a/usr.bin/xlint/lint1/tree.c b/usr.bin/xlint/lint1/tree.c
index 3e8116e1b52..5db5eec50a0 100644
--- a/usr.bin/xlint/lint1/tree.c
+++ b/usr.bin/xlint/lint1/tree.c
@@ -1,4 +1,4 @@
-/* $NetBSD: tree.c,v 1.505 2023/02/22 22:30:40 rillig Exp $ */
+/* $NetBSD: tree.c,v 1.506 2023/02/24 19:18:50 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: tree.c,v 1.505 2023/02/22 22:30:40 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.506 2023/02/24 19:18:50 rillig Exp $");
#endif
#include <float.h>
@@ -49,6 +49,7 @@ __RCSID("$NetBSD: tree.c,v 1.505 2023/02/22 22:30:40 rillig Exp $");
#include "lint1.h"
+
typedef struct integer_constraints {
int64_t smin; /* signed minimum */
int64_t smax; /* signed maximum */
@@ -58,52 +59,10 @@ typedef struct integer_constraints {
uint64_t bclr; /* bits that are definitely clear */
} integer_constraints;
-static tnode_t *build_integer_constant(tspec_t, int64_t);
-static void check_pointer_comparison(op_t,
- const tnode_t *, const tnode_t *);
-static bool check_assign_types_compatible(op_t, int,
- const tnode_t *, const tnode_t *);
-static void check_bad_enum_operation(op_t,
- const tnode_t *, const tnode_t *);
-static void check_enum_type_mismatch(op_t, int,
- const tnode_t *, const tnode_t *);
-static void check_enum_int_mismatch(op_t, int,
- const tnode_t *, const tnode_t *);
-static tnode_t *new_tnode(op_t, bool, type_t *, tnode_t *, tnode_t *);
-static void balance(op_t, tnode_t **, tnode_t **);
-static void warn_incompatible_types(op_t, const type_t *, tspec_t,
- const type_t *, tspec_t);
-static void warn_incompatible_pointers(const mod_t *,
- const type_t *, const type_t *);
-static bool has_constant_member(const type_t *);
-static void check_prototype_conversion(int, tspec_t, tspec_t, type_t *,
- tnode_t *);
-static void convert_integer_from_integer(op_t, int, tspec_t, tspec_t,
- type_t *, tnode_t *);
-static void convert_integer_from_pointer(op_t, tspec_t, type_t *,
- tnode_t *);
-static void convert_pointer_from_pointer(type_t *, tnode_t *);
-static tnode_t *build_struct_access(op_t, bool, tnode_t *, tnode_t *);
-static tnode_t *build_prepost_incdec(op_t, bool, tnode_t *);
-static tnode_t *build_real_imag(op_t, bool, tnode_t *);
-static tnode_t *build_address(bool, tnode_t *, bool);
-static tnode_t *build_plus_minus(op_t, bool, tnode_t *, tnode_t *);
-static tnode_t *build_bit_shift(op_t, bool, tnode_t *, tnode_t *);
-static tnode_t *build_colon(bool, tnode_t *, tnode_t *);
-static tnode_t *build_assignment(op_t, bool, tnode_t *, tnode_t *);
-static tnode_t *subt_size_in_bytes(type_t *);
-static tnode_t *fold(tnode_t *);
-static tnode_t *fold_bool(tnode_t *);
-static tnode_t *fold_float(tnode_t *);
-static tnode_t *check_function_arguments(type_t *, tnode_t *);
-static tnode_t *check_prototype_argument(int, type_t *, tnode_t *);
-static void check_null_effect(const tnode_t *);
-static void check_array_index(tnode_t *, bool);
-static void check_integer_comparison(op_t, tnode_t *, tnode_t *);
-static void check_precedence_confusion(tnode_t *);
extern sig_atomic_t fpe;
+
static uint64_t
u64_fill_right(uint64_t x)
{
@@ -116,6 +75,21 @@ u64_fill_right(uint64_t x)
return x;
}
+static bool
+str_endswith(const char *haystack, const char *needle)
+{
+ size_t hlen = strlen(haystack);
+ size_t nlen = strlen(needle);
+
+ return nlen <= hlen &&
+ memcmp(haystack + hlen - nlen, needle, nlen) == 0;
+}
+static const char *
+op_name(op_t op)
+{
+ return modtab[op].m_name;
+}
+
static unsigned
width_in_bits(const type_t *tp)
{
@@ -318,12 +292,6 @@ ic_expr(const tnode_t *tn)
}
}
-static const char *
-op_name(op_t op)
-{
- return modtab[op].m_name;
-}
-
/* Build 'pointer to tp', 'array of tp' or 'function returning tp'. */
type_t *
block_derive_type(type_t *tp, tspec_t t)
@@ -352,6 +320,30 @@ expr_derive_type(type_t *tp, tspec_t t)
}
/*
+ * Build and initialize a new node.
+ */
+static tnode_t *
+new_tnode(op_t op, bool sys, type_t *type, tnode_t *ln, tnode_t *rn)
+{
+
+ tnode_t *ntn = expr_alloc_tnode();
+ ntn->tn_op = op;
+ ntn->tn_type = type;
+ ntn->tn_sys = sys;
+ ntn->tn_left = ln;
+ ntn->tn_right = rn;
+
+ if (op == INDIR || op == FSEL) {
+ lint_assert(ln->tn_type->t_tspec == PTR);
+ tspec_t t = ln->tn_type->t_subt->t_tspec;
+ if (t != FUNC && t != VOID)
+ ntn->tn_lvalue = true;
+ }
+
+ return ntn;
+}
+
+/*
* Create a node for a constant.
*/
tnode_t *
@@ -440,16 +432,6 @@ is_compiler_builtin(const char *name)
return false;
}
-static bool
-str_endswith(const char *haystack, const char *needle)
-{
- size_t hlen = strlen(haystack);
- size_t nlen = strlen(needle);
-
- return nlen <= hlen &&
- memcmp(haystack + hlen - nlen, needle, nlen) == 0;
-}
-
/* https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html */
static bool
is_gcc_bool_builtin(const char *name)
@@ -557,179 +539,1066 @@ build_string(strg_t *strg)
return n;
}
+tnode_t *
+build_generic_selection(const tnode_t *expr,
+ struct generic_association *sel)
+{
+ tnode_t *default_result = NULL;
+
+ for (; sel != NULL; sel = sel->ga_prev) {
+ if (expr != NULL &&
+ types_compatible(sel->ga_arg, expr->tn_type,
+ false, false, NULL))
+ return sel->ga_result;
+ else if (sel->ga_arg == NULL)
+ default_result = sel->ga_result;
+ }
+ return default_result;
+}
+
+static bool
+is_out_of_char_range(const tnode_t *tn)
+{
+ return tn->tn_op == CON &&
+ !(0 <= tn->tn_val->v_quad &&
+ tn->tn_val->v_quad < 1 << (CHAR_SIZE - 1));
+}
+
/*
- * Return whether all struct/union members with the same name have the same
- * type and offset.
+ * Check for ordered comparisons of unsigned values with 0.
*/
-static bool
-all_members_compatible(const sym_t *msym)
+static void
+check_integer_comparison(op_t op, tnode_t *ln, tnode_t *rn)
{
- for (const sym_t *csym = msym;
- csym != NULL; csym = csym->s_symtab_next) {
- if (!is_member(csym))
- continue;
- if (strcmp(msym->s_name, csym->s_name) != 0)
- continue;
+ tspec_t lt, rt;
- for (const sym_t *sym = csym->s_symtab_next;
- sym != NULL; sym = sym->s_symtab_next) {
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
- if (!is_member(sym))
- continue;
- if (strcmp(csym->s_name, sym->s_name) != 0)
- continue;
- if (csym->u.s_member.sm_offset_in_bits !=
- sym->u.s_member.sm_offset_in_bits)
- return false;
+ if (ln->tn_op != CON && rn->tn_op != CON)
+ return;
- bool w = false;
- if (!types_compatible(csym->s_type, sym->s_type,
- false, false, &w) && !w)
- return false;
- if (csym->s_bitfield != sym->s_bitfield)
- return false;
- if (csym->s_bitfield) {
- type_t *tp1 = csym->s_type;
- type_t *tp2 = sym->s_type;
- if (tp1->t_flen != tp2->t_flen)
- return false;
- if (tp1->t_foffs != tp2->t_foffs)
- return false;
- }
+ if (!is_integer(lt) || !is_integer(rt))
+ return;
+
+ if (hflag || pflag) {
+ if (lt == CHAR && is_out_of_char_range(rn)) {
+ char buf[128];
+ (void)snprintf(buf, sizeof(buf), "%s %d",
+ op_name(op), (int)rn->tn_val->v_quad);
+ /* nonportable character comparison '%s' */
+ warning(230, buf);
+ return;
+ }
+ if (rt == CHAR && is_out_of_char_range(ln)) {
+ char buf[128];
+ (void)snprintf(buf, sizeof(buf), "%d %s ?",
+ (int)ln->tn_val->v_quad, op_name(op));
+ /* nonportable character comparison '%s' */
+ warning(230, buf);
+ return;
}
}
- return true;
+
+ if (is_uinteger(lt) && !is_uinteger(rt) &&
+ rn->tn_op == CON && rn->tn_val->v_quad <= 0) {
+ if (rn->tn_val->v_quad < 0) {
+ /* operator '%s' compares '%s' with '%s' */
+ warning(162, op_name(op),
+ type_name(ln->tn_type), "negative constant");
+ } else if (op == LT || op == GE) {
+ /* operator '%s' compares '%s' with '%s' */
+ warning(162, op_name(op), type_name(ln->tn_type), "0");
+ }
+ return;
+ }
+ if (is_uinteger(rt) && !is_uinteger(lt) &&
+ ln->tn_op == CON && ln->tn_val->v_quad <= 0) {
+ if (ln->tn_val->v_quad < 0) {
+ /* operator '%s' compares '%s' with '%s' */
+ warning(162, op_name(op),
+ "negative constant", type_name(rn->tn_type));
+ } else if (op == GT || op == LE) {
+ /* operator '%s' compares '%s' with '%s' */
+ warning(162, op_name(op), "0", type_name(rn->tn_type));
+ }
+ return;
+ }
+}
+
+static const tspec_t arith_rank[] = {
+ LDOUBLE, DOUBLE, FLOAT,
+#ifdef INT128_SIZE
+ UINT128, INT128,
+#endif
+ UQUAD, QUAD,
+ ULONG, LONG,
+ UINT, INT,
+};
+
+/* Keep unsigned in traditional C */
+static tspec_t
+usual_arithmetic_conversion_trad(tspec_t lt, tspec_t rt)
+{
+
+ size_t i;
+ for (i = 0; arith_rank[i] != INT; i++)
+ if (lt == arith_rank[i] || rt == arith_rank[i])
+ break;
+
+ tspec_t t = arith_rank[i];
+ if (is_uinteger(lt) || is_uinteger(rt))
+ if (is_integer(t) && !is_uinteger(t))
+ return unsigned_type(t);
+ return t;
+}
+
+static tspec_t
+usual_arithmetic_conversion_c90(tspec_t lt, tspec_t rt)
+{
+
+ if (lt == rt)
+ return lt;
+
+ if (lt == LCOMPLEX || rt == LCOMPLEX)
+ return LCOMPLEX;
+ if (lt == DCOMPLEX || rt == DCOMPLEX)
+ return DCOMPLEX;
+ if (lt == FCOMPLEX || rt == FCOMPLEX)
+ return FCOMPLEX;
+ if (lt == LDOUBLE || rt == LDOUBLE)
+ return LDOUBLE;
+ if (lt == DOUBLE || rt == DOUBLE)
+ return DOUBLE;
+ if (lt == FLOAT || rt == FLOAT)
+ return FLOAT;
+
+ /*
+ * If type A has more bits than type B, it should be able to hold all
+ * possible values of type B.
+ */
+ if (size_in_bits(lt) > size_in_bits(rt))
+ return lt;
+ if (size_in_bits(lt) < size_in_bits(rt))
+ return rt;
+
+ size_t i;
+ for (i = 3; arith_rank[i] != INT; i++)
+ if (arith_rank[i] == lt || arith_rank[i] == rt)
+ break;
+ if ((is_uinteger(lt) || is_uinteger(rt)) &&
+ !is_uinteger(arith_rank[i]))
+ i--;
+ return arith_rank[i];
+}
+
+static tnode_t *
+apply_usual_arithmetic_conversions(op_t op, tnode_t *tn, tspec_t t)
+{
+ type_t *ntp = expr_dup_type(tn->tn_type);
+ ntp->t_tspec = t;
+ if (tn->tn_op != CON) {
+ /* usual arithmetic conversion for '%s' from '%s' to '%s' */
+ query_message(4, op_name(op),
+ type_name(tn->tn_type), type_name(ntp));
+ }
+ return convert(op, 0, ntp, tn);
}
/*
- * 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.
+ * Apply the "usual arithmetic conversions" (C99 6.3.1.8), which gives both
+ * operands the same type.
*/
-static sym_t *
-struct_or_union_member(tnode_t *tn, op_t op, sym_t *msym)
+static void
+balance(op_t op, tnode_t **lnp, tnode_t **rnp)
+{
+
+ tspec_t lt = (*lnp)->tn_type->t_tspec;
+ tspec_t rt = (*rnp)->tn_type->t_tspec;
+ if (!is_arithmetic(lt) || !is_arithmetic(rt))
+ return;
+
+ tspec_t t = allow_c90
+ ? usual_arithmetic_conversion_c90(lt, rt)
+ : usual_arithmetic_conversion_trad(lt, rt);
+
+ if (t != lt)
+ *lnp = apply_usual_arithmetic_conversions(op, *lnp, t);
+ if (t != rt)
+ *rnp = apply_usual_arithmetic_conversions(op, *rnp, t);
+}
+
+/*
+ * Create a tree node for the unary & operator
+ */
+static tnode_t *
+build_address(bool sys, tnode_t *tn, bool noign)
{
- struct_or_union *str;
- type_t *tp;
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) {
- /* type '%s' does not have member '%s' */
- error(101, type_name(tn->tn_type), msym->s_name);
- rmsym(msym);
- msym->s_kind = FMEMBER;
- msym->s_scl = STRUCT_MEMBER;
+ if (!noign && ((t = tn->tn_type->t_tspec) == ARRAY || t == FUNC)) {
+ if (!allow_c90)
+ /* '&' before array or function: ignored */
+ warning(127);
+ return tn;
+ }
- struct_or_union *sou = expr_zero_alloc(sizeof(*sou));
- sou->sou_tag = expr_zero_alloc(sizeof(*sou->sou_tag));
- sou->sou_tag->s_name = unnamed;
+ /* eliminate &* */
+ if (tn->tn_op == INDIR &&
+ tn->tn_left->tn_type->t_tspec == PTR &&
+ tn->tn_left->tn_type->t_subt == tn->tn_type) {
+ return tn->tn_left;
+ }
- msym->u.s_member.sm_sou_type = sou;
+ return new_tnode(ADDR, sys, expr_derive_type(tn->tn_type, PTR),
+ tn, NULL);
+}
+
+/*
+ * XXX
+ * Note: There appear to be a number of bugs in detecting overflow in
+ * this function. An audit and a set of proper regression tests are needed.
+ * --Perry Metzger, Nov. 16, 2001
+ */
+/*
+ * Do only as much as necessary to compute constant expressions.
+ * Called only if the operator allows folding and all operands are constants.
+ */
+static tnode_t *
+fold(tnode_t *tn)
+{
+ val_t *v;
+ tspec_t t;
+ bool utyp, ovfl;
+ int64_t sl, sr = 0, q = 0, mask;
+ uint64_t ul, ur = 0;
+ tnode_t *cn;
+
+ v = xcalloc(1, sizeof(*v));
+ v->v_tspec = tn->tn_type->t_tspec;
+
+ t = tn->tn_left->tn_type->t_tspec;
+ utyp = !is_integer(t) || is_uinteger(t);
+ ul = sl = tn->tn_left->tn_val->v_quad;
+ if (is_binary(tn))
+ ur = sr = tn->tn_right->tn_val->v_quad;
+
+ mask = value_bits(size_in_bits(t));
+ ovfl = false;
+
+ switch (tn->tn_op) {
+ case UPLUS:
+ q = sl;
+ break;
+ case UMINUS:
+ q = sl == INT64_MIN ? sl : -sl;
+ if (sl != 0 && msb(q, t) == msb(sl, t))
+ ovfl = true;
+ break;
+ case COMPL:
+ q = ~sl;
+ break;
+ case MULT:
+ if (utyp) {
+ q = ul * ur;
+ if (q != (q & mask))
+ ovfl = true;
+ else if ((ul != 0) && ((q / ul) != ur))
+ ovfl = true;
+ } else {
+ q = sl * sr;
+ if (msb(q, t) != (msb(sl, t) ^ msb(sr, t)))
+ ovfl = true;
+ }
+ break;
+ case DIV:
+ if (sr == 0) {
+ /* division by 0 */
+ error(139);
+ q = utyp ? -1 : INT64_MAX;
+ } else {
+ q = utyp ? (int64_t)(ul / ur) : sl / sr;
+ }
+ break;
+ case MOD:
+ if (sr == 0) {
+ /* modulus by 0 */
+ error(140);
+ q = 0;
+ } else {
+ q = utyp ? (int64_t)(ul % ur) : sl % sr;
+ }
+ break;
+ case PLUS:
+ q = utyp ? (int64_t)(ul + ur) : sl + sr;
+ if (msb(sl, t) && msb(sr, t) && !msb(q, t))
+ ovfl = true;
+ if (!utyp && !msb(sl, t) && !msb(sr, t) && msb(q, t))
+ ovfl = true;
+ break;
+ case MINUS:
+ q = utyp ? (int64_t)(ul - ur) : sl - sr;
+ if (!utyp && msb(sl, t) && !msb(sr, t) && !msb(q, t))
+ ovfl = true;
+ if (!msb(sl, t) && msb(sr, t) && msb(q, t))
+ ovfl = true;
+ break;
+ case SHL:
+ /* TODO: warn about out-of-bounds 'sr'. */
+ /* TODO: warn about overflow in signed '<<'. */
+ q = utyp ? (int64_t)(ul << (sr & 63)) : sl << (sr & 63);
+ break;
+ case SHR:
/*
- * The member sm_offset_in_bits is not needed here since this
- * symbol can only be used for error reporting.
+ * The sign must be explicitly extended because
+ * shifts of signed values are implementation dependent.
*/
- return msym;
+ /* TODO: warn about out-of-bounds 'sr'. */
+ q = ul >> (sr & 63);
+ q = convert_integer(q, t, size_in_bits(t) - (int)sr);
+ break;
+ case LT:
+ q = (utyp ? ul < ur : sl < sr) ? 1 : 0;
+ break;
+ case LE:
+ q = (utyp ? ul <= ur : sl <= sr) ? 1 : 0;
+ break;
+ case GE:
+ q = (utyp ? ul >= ur : sl >= sr) ? 1 : 0;
+ break;
+ case GT:
+ q = (utyp ? ul > ur : sl > sr) ? 1 : 0;
+ break;
+ case EQ:
+ q = (utyp ? ul == ur : sl == sr) ? 1 : 0;
+ break;
+ case NE:
+ q = (utyp ? ul != ur : sl != sr) ? 1 : 0;
+ break;
+ case BITAND:
+ q = utyp ? (int64_t)(ul & ur) : sl & sr;
+ break;
+ case BITXOR:
+ q = utyp ? (int64_t)(ul ^ ur) : sl ^ sr;
+ break;
+ case BITOR:
+ q = utyp ? (int64_t)(ul | ur) : sl | sr;
+ break;
+ default:
+ lint_assert(/*CONSTCOND*/false);
}
- /* 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 (is_struct_or_union(t))
- str = tp->t_str;
- } else if (op == ARROW && t == PTR) {
- t = (tp = tp->t_subt)->t_tspec;
- if (is_struct_or_union(t))
- str = tp->t_str;
+ /* XXX does not work for quads. */
+ if (ovfl ||
+ ((uint64_t)(q | mask) != ~(uint64_t)0 && (q & ~mask) != 0)) {
+ if (hflag)
+ /* integer overflow detected, op '%s' */
+ warning(141, op_name(tn->tn_op));
}
+ v->v_quad = convert_integer(q, t, 0);
+
+ cn = build_constant(tn->tn_type, v);
+ if (tn->tn_left->tn_system_dependent)
+ cn->tn_system_dependent = true;
+ if (is_binary(tn) && tn->tn_right->tn_system_dependent)
+ cn->tn_system_dependent = true;
+
+ return cn;
+}
+
+/*
+ * Create a new node for one of the operators POINT and ARROW.
+ */
+static tnode_t *
+build_struct_access(op_t op, bool sys, tnode_t *ln, tnode_t *rn)
+{
+ tnode_t *ntn, *ctn;
+ bool nolval;
+
+ lint_assert(rn->tn_op == NAME);
+ lint_assert(is_member(rn->tn_sym));
+
/*
- * If this struct/union has a member with the name of msym, return it.
+ * Remember if the left operand is an lvalue (structure members
+ * are lvalues if and only if the structure itself is an lvalue).
*/
- if (str != NULL) {
- for (sym_t *sym = msym;
- sym != NULL; sym = sym->s_symtab_next) {
- if (!is_member(sym))
- continue;
- if (sym->u.s_member.sm_sou_type != str)
- continue;
- if (strcmp(sym->s_name, msym->s_name) != 0)
- continue;
- return sym;
- }
+ nolval = op == POINT && !ln->tn_lvalue;
+
+ if (op == POINT) {
+ ln = build_address(sys, ln, true);
+ } else if (ln->tn_type->t_tspec != PTR) {
+ lint_assert(!allow_c90);
+ lint_assert(is_integer(ln->tn_type->t_tspec));
+ ln = convert(NOOP, 0, expr_derive_type(gettyp(VOID), PTR), ln);
}
- bool eq = all_members_compatible(msym);
+ ctn = build_integer_constant(PTRDIFF_TSPEC,
+ rn->tn_sym->u.s_member.sm_offset_in_bits / CHAR_SIZE);
- /*
- * 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) {
- if (eq && !allow_c90) {
- /* illegal use of member '%s' */
- warning(102, msym->s_name);
+ ntn = new_tnode(PLUS, sys, expr_derive_type(rn->tn_type, PTR),
+ ln, ctn);
+ if (ln->tn_op == CON)
+ ntn = fold(ntn);
+
+ if (rn->tn_type->t_bitfield) {
+ ntn = new_tnode(FSEL, sys, ntn->tn_type->t_subt, ntn, NULL);
+ } else {
+ ntn = new_tnode(INDIR, sys, ntn->tn_type->t_subt, ntn, NULL);
+ }
+
+ if (nolval)
+ ntn->tn_lvalue = false;
+
+ return ntn;
+}
+
+/*
+ * Get the size in bytes of type tp->t_subt, as a constant expression of type
+ * ptrdiff_t as seen from the target platform.
+ */
+static tnode_t *
+subt_size_in_bytes(type_t *tp)
+{
+ int elem, elsz_in_bits;
+
+ lint_assert(tp->t_tspec == PTR);
+ tp = tp->t_subt;
+
+ elem = 1;
+ elsz_in_bits = 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 unknown size */
+ gnuism(136);
+ break;
+ case STRUCT:
+ case UNION:
+ if ((elsz_in_bits = tp->t_str->sou_size_in_bits) == 0)
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ break;
+ case ENUM:
+ if (is_incomplete(tp)) {
+ /* cannot do pointer arithmetic on operand of ... */
+ warning(136);
+ }
+ /* FALLTHROUGH */
+ default:
+ if ((elsz_in_bits = size_in_bits(tp->t_tspec)) == 0) {
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
} else {
- /* illegal use of member '%s' */
- error(102, msym->s_name);
+ lint_assert(elsz_in_bits != -1);
}
- return msym;
+ break;
}
+ if (elem == 0 && elsz_in_bits != 0) {
+ /* cannot do pointer arithmetic on operand of unknown size */
+ error(136);
+ }
+
+ if (elsz_in_bits == 0)
+ elsz_in_bits = CHAR_SIZE;
+
+ return build_integer_constant(PTRDIFF_TSPEC,
+ (int64_t)(elem * elsz_in_bits / CHAR_SIZE));
+}
+
+/*
+ * Create a node for INCAFT, INCBEF, DECAFT and DECBEF.
+ */
+static tnode_t *
+build_prepost_incdec(op_t op, bool sys, tnode_t *ln)
+{
+ tnode_t *cn, *ntn;
+
+ lint_assert(ln != NULL);
+
+ if (ln->tn_type->t_tspec == PTR) {
+ cn = subt_size_in_bytes(ln->tn_type);
+ } else {
+ cn = build_integer_constant(INT, (int64_t)1);
+ }
+ ntn = new_tnode(op, sys, ln->tn_type, ln, cn);
+
+ return ntn;
+}
+
+static void
+check_enum_array_index(const tnode_t *ln, const tnode_t *rn)
+{
+ int max_array_index;
+ int64_t max_enum_value;
+ const struct sym *ec, *max_ec;
+ const type_t *lt, *rt;
+
+ if (ln->tn_op != ADDR || ln->tn_left->tn_op != NAME)
+ return;
+
+ lt = ln->tn_left->tn_type;
+ if (lt->t_tspec != ARRAY || lt->t_incomplete_array)
+ return;
+
+ if (rn->tn_op != CVT || !rn->tn_type->t_is_enum)
+ return;
+ if (rn->tn_left->tn_op != LOAD)
+ return;
+
+ rt = rn->tn_left->tn_type;
+ ec = rt->t_enum->en_first_enumerator;
+ max_ec = ec;
+ lint_assert(ec != NULL);
+ for (ec = ec->s_next; ec != NULL; ec = ec->s_next)
+ if (ec->u.s_enum_constant > max_ec->u.s_enum_constant)
+ max_ec = ec;
+
+ max_enum_value = max_ec->u.s_enum_constant;
+ lint_assert(INT_MIN <= max_enum_value && max_enum_value <= INT_MAX);
+
+ max_array_index = lt->t_dim - 1;
+ if (max_enum_value == max_array_index)
+ return;
+
/*
- * Now the left operand of ARROW does not point to a struct/union
- * or the left operand of POINT is no struct/union.
+ * If the name of the largest enum constant contains 'MAX' or 'NUM',
+ * that constant is typically not part of the allowed enum values but
+ * a marker for the number of actual enum values.
*/
- if (eq) {
- if (op == POINT) {
- if (!allow_c90) {
- /* left operand of '.' must be struct ... */
- warning(103, type_name(tn->tn_type));
- } else {
- /* left operand of '.' must be struct ... */
- error(103, type_name(tn->tn_type));
- }
- } else {
- if (!allow_c90 && tn->tn_type->t_tspec == PTR) {
- /* left operand of '->' must be pointer ... */
- warning(104, type_name(tn->tn_type));
+ if (max_enum_value == max_array_index + 1 &&
+ (strstr(max_ec->s_name, "MAX") != NULL ||
+ strstr(max_ec->s_name, "max") != NULL ||
+ strstr(max_ec->s_name, "NUM") != NULL ||
+ strstr(max_ec->s_name, "num") != NULL))
+ return;
+
+ /* maximum value %d of '%s' does not match maximum array index %d */
+ warning(348, (int)max_enum_value, type_name(rt), max_array_index);
+ print_previous_declaration(max_ec);
+}
+
+/*
+ * Create a node for operators PLUS and MINUS.
+ */
+static tnode_t *
+build_plus_minus(op_t op, bool sys, tnode_t *ln, tnode_t *rn)
+{
+
+ /* If pointer and integer, then pointer to the lhs. */
+ if (rn->tn_type->t_tspec == PTR && is_integer(ln->tn_type->t_tspec)) {
+ tnode_t *tmp = ln;
+ ln = rn;
+ rn = tmp;
+ /* pointer addition has integer on the left-hand side */
+ query_message(5);
+ }
+
+ /* pointer +- integer */
+ if (ln->tn_type->t_tspec == PTR && rn->tn_type->t_tspec != PTR) {
+ lint_assert(is_integer(rn->tn_type->t_tspec));
+
+ check_ctype_macro_invocation(ln, rn);
+ check_enum_array_index(ln, rn);
+
+ tnode_t *elsz = subt_size_in_bytes(ln->tn_type);
+ if (rn->tn_type->t_tspec != elsz->tn_type->t_tspec)
+ rn = convert(NOOP, 0, elsz->tn_type, rn);
+
+ tnode_t *prod = new_tnode(MULT, sys, rn->tn_type, rn, elsz);
+ if (rn->tn_op == CON)
+ prod = fold(prod);
+
+ return new_tnode(op, sys, ln->tn_type, ln, prod);
+ }
+
+ /* pointer - pointer */
+ if (rn->tn_type->t_tspec == PTR) {
+ lint_assert(ln->tn_type->t_tspec == PTR);
+ lint_assert(op == MINUS);
+
+ type_t *ptrdiff = gettyp(PTRDIFF_TSPEC);
+ tnode_t *raw_diff = new_tnode(op, sys, ptrdiff, ln, rn);
+ if (ln->tn_op == CON && rn->tn_op == CON)
+ raw_diff = fold(raw_diff);
+
+ tnode_t *elsz = subt_size_in_bytes(ln->tn_type);
+ balance(NOOP, &raw_diff, &elsz);
+
+ return new_tnode(DIV, sys, ptrdiff, raw_diff, elsz);
+ }
+
+ return new_tnode(op, sys, ln->tn_type, ln, rn);
+}
+
+/*
+ * Create a node for operators SHL and SHR.
+ */
+static tnode_t *
+build_bit_shift(op_t op, bool sys, tnode_t *ln, tnode_t *rn)
+{
+
+ if (!allow_c90 && rn->tn_type->t_tspec != INT)
+ rn = convert(NOOP, 0, gettyp(INT), rn);
+ return new_tnode(op, sys, ln->tn_type, ln, rn);
+}
+
+static bool
+is_null_pointer(const tnode_t *tn)
+{
+ tspec_t t = tn->tn_type->t_tspec;
+
+ return ((t == PTR && tn->tn_type->t_subt->t_tspec == VOID) ||
+ is_integer(t))
+ && (tn->tn_op == CON && tn->tn_val->v_quad == 0);
+}
+
+/* Return a type based on tp1, with added qualifiers from tp2. */
+static type_t *
+merge_qualifiers(type_t *tp1, const type_t *tp2)
+{
+ type_t *ntp, *nstp;
+ bool c1, c2, v1, v2;
+
+ lint_assert(tp1->t_tspec == PTR);
+ lint_assert(tp2->t_tspec == PTR);
+
+ c1 = tp1->t_subt->t_const;
+ c2 = tp2->t_subt->t_const;
+ v1 = tp1->t_subt->t_volatile;
+ v2 = tp2->t_subt->t_volatile;
+
+ if (c1 == (c1 | c2) && v1 == (v1 | v2))
+ return tp1;
+
+ nstp = expr_dup_type(tp1->t_subt);
+ nstp->t_const |= c2;
+ nstp->t_volatile |= v2;
+
+ ntp = expr_dup_type(tp1);
+ ntp->t_subt = nstp;
+ return ntp;
+}
+
+/* See C99 6.5.15 "Conditional operator". */
+static tnode_t *
+build_colon(bool sys, tnode_t *ln, tnode_t *rn)
+{
+ tspec_t lt, rt;
+ type_t *tp;
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+
+ if (is_arithmetic(lt) && is_arithmetic(rt)) {
+ /* The operands were already balanced in build_binary. */
+ tp = ln->tn_type;
+ } else if (lt == BOOL && rt == BOOL) {
+ tp = ln->tn_type;
+ } else if (lt == VOID || rt == VOID) {
+ tp = gettyp(VOID);
+ } else if (is_struct_or_union(lt)) {
+ /* Both types must be identical. */
+ lint_assert(is_struct_or_union(rt));
+ lint_assert(ln->tn_type->t_str == rn->tn_type->t_str);
+ if (is_incomplete(ln->tn_type)) {
+ /* unknown operand size, op '%s' */
+ error(138, op_name(COLON));
+ return NULL;
+ }
+ tp = ln->tn_type;
+ } else if (lt == PTR && is_integer(rt)) {
+ if (rt != PTRDIFF_TSPEC)
+ rn = convert(NOOP, 0, gettyp(PTRDIFF_TSPEC), rn);
+ tp = ln->tn_type;
+ } else if (rt == PTR && is_integer(lt)) {
+ if (lt != PTRDIFF_TSPEC)
+ ln = convert(NOOP, 0, gettyp(PTRDIFF_TSPEC), ln);
+ tp = rn->tn_type;
+ } else if (lt == PTR && is_null_pointer(rn)) {
+ tp = merge_qualifiers(ln->tn_type, rn->tn_type);
+ } else if (rt == PTR && is_null_pointer(ln)) {
+ tp = merge_qualifiers(rn->tn_type, ln->tn_type);
+ } else if (lt == PTR && ln->tn_type->t_subt->t_tspec == VOID) {
+ tp = merge_qualifiers(ln->tn_type, rn->tn_type);
+ } else if (rt == PTR && rn->tn_type->t_subt->t_tspec == VOID) {
+ tp = merge_qualifiers(rn->tn_type, ln->tn_type);
+ } else {
+ /*
+ * 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.
+ */
+ tp = merge_qualifiers(ln->tn_type, rn->tn_type);
+ }
+
+ return new_tnode(COLON, sys, tp, ln, rn);
+}
+
+/* TODO: check for varargs */
+static bool
+is_cast_redundant(const tnode_t *tn)
+{
+ const type_t *ntp = tn->tn_type, *otp = tn->tn_left->tn_type;
+ tspec_t nt = ntp->t_tspec, ot = otp->t_tspec;
+
+ if (nt == BOOL || ot == BOOL)
+ return nt == BOOL && ot == BOOL;
+
+ if (is_integer(nt) && is_integer(ot)) {
+ unsigned int nw = width_in_bits(ntp), ow = width_in_bits(otp);
+ if (is_uinteger(nt) == is_uinteger(ot))
+ return nw >= ow;
+ return is_uinteger(ot) && nw > ow;
+ }
+
+ if (is_complex(nt) || is_complex(ot))
+ return is_complex(nt) && is_complex(ot) &&
+ size_in_bits(nt) >= size_in_bits(ot);
+
+ if (is_floating(nt) && is_floating(ot))
+ return size_in_bits(nt) >= size_in_bits(ot);
+
+ if (nt == PTR && ot == PTR) {
+ if (!ntp->t_subt->t_const && otp->t_subt->t_const)
+ return false;
+ if (!ntp->t_subt->t_volatile && otp->t_subt->t_volatile)
+ return false;
+
+ if (ntp->t_subt->t_tspec == VOID ||
+ otp->t_subt->t_tspec == VOID ||
+ types_compatible(ntp->t_subt, otp->t_subt,
+ false, false, NULL))
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Create a node for an assignment operator (both = and op= ).
+ */
+static tnode_t *
+build_assignment(op_t op, bool sys, tnode_t *ln, tnode_t *rn)
+{
+ tspec_t lt, rt;
+ tnode_t *ntn, *ctn;
+
+ lint_assert(ln != NULL);
+ lint_assert(rn != NULL);
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+
+ if ((op == ADDASS || op == SUBASS) && lt == PTR) {
+ lint_assert(is_integer(rt));
+ ctn = subt_size_in_bytes(ln->tn_type);
+ if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec)
+ rn = convert(NOOP, 0, ctn->tn_type, rn);
+ rn = new_tnode(MULT, sys, rn->tn_type, rn, ctn);
+ if (rn->tn_left->tn_op == CON)
+ rn = fold(rn);
+ }
+
+ if ((op == ASSIGN || op == RETURN || op == INIT) &&
+ (lt == STRUCT || rt == STRUCT)) {
+ lint_assert(lt == rt);
+ lint_assert(ln->tn_type->t_str == rn->tn_type->t_str);
+ if (is_incomplete(ln->tn_type)) {
+ if (op == RETURN) {
+ /* cannot return incomplete type */
+ error(212);
} else {
- /* left operand of '->' must be pointer ... */
- error(104, type_name(tn->tn_type));
+ /* unknown operand size, op '%s' */
+ error(138, op_name(op));
}
+ return NULL;
}
- } else {
- if (!allow_c90) {
- /* non-unique member requires struct/union %s */
- error(105, op == POINT ? "object" : "pointer");
- } else {
- /* unacceptable operand of '%s' */
- error(111, op_name(op));
+ }
+
+ if (op == SHLASS) {
+ if (portable_size_in_bits(lt) < portable_size_in_bits(rt)) {
+ if (hflag)
+ /* semantics of '%s' change in ANSI C; ... */
+ warning(118, "<<=");
+ }
+ } else if (op != SHRASS) {
+ if (op == ASSIGN || lt != PTR) {
+ if (lt != rt ||
+ (ln->tn_type->t_bitfield && rn->tn_op == CON)) {
+ rn = convert(op, 0, ln->tn_type, rn);
+ rt = lt;
+ }
}
}
- return msym;
+ if (any_query_enabled && rn->tn_op == CVT && rn->tn_cast &&
+ types_compatible(ln->tn_type, rn->tn_type, false, false, NULL) &&
+ is_cast_redundant(rn)) {
+ /* redundant cast from '%s' to '%s' before assignment */
+ query_message(7,
+ type_name(rn->tn_left->tn_type), type_name(rn->tn_type));
+ }
+
+ ntn = new_tnode(op, sys, ln->tn_type, ln, rn);
+
+ return ntn;
}
-tnode_t *
-build_generic_selection(const tnode_t *expr,
- struct generic_association *sel)
+/*
+ * Create a node for REAL, IMAG
+ */
+static tnode_t *
+build_real_imag(op_t op, bool sys, tnode_t *ln)
{
- tnode_t *default_result = NULL;
+ tnode_t *cn, *ntn;
- for (; sel != NULL; sel = sel->ga_prev) {
- if (expr != NULL &&
- types_compatible(sel->ga_arg, expr->tn_type,
- false, false, NULL))
- return sel->ga_result;
- else if (sel->ga_arg == NULL)
- default_result = sel->ga_result;
+ lint_assert(ln != NULL);
+
+ if (ln->tn_op == NAME) {
+ /*
+ * This may be too much, but it avoids wrong warnings.
+ * See d_c99_complex_split.c.
+ */
+ mark_as_used(ln->tn_sym, false, false);
+ mark_as_set(ln->tn_sym);
}
- return default_result;
+
+ switch (ln->tn_type->t_tspec) {
+ case LCOMPLEX:
+ /* XXX: integer and LDOUBLE don't match. */
+ cn = build_integer_constant(LDOUBLE, (int64_t)1);
+ break;
+ case DCOMPLEX:
+ /* XXX: integer and DOUBLE don't match. */
+ cn = build_integer_constant(DOUBLE, (int64_t)1);
+ break;
+ case FCOMPLEX:
+ /* XXX: integer and FLOAT don't match. */
+ cn = build_integer_constant(FLOAT, (int64_t)1);
+ break;
+ default:
+ /* '__%s__' is illegal for type '%s' */
+ error(276, op == REAL ? "real" : "imag",
+ type_name(ln->tn_type));
+ return NULL;
+ }
+ ntn = new_tnode(op, sys, cn->tn_type, ln, cn);
+ ntn->tn_lvalue = true;
+
+ return ntn;
+}
+
+static bool
+is_confusing_precedence(op_t op, op_t lop, bool lparen, op_t rop, bool rparen)
+{
+
+ if (op == SHL || op == SHR) {
+ if (!lparen && (lop == PLUS || lop == MINUS))
+ return true;
+ if (!rparen && (rop == PLUS || rop == MINUS))
+ return true;
+ return false;
+ }
+
+ if (op == LOGOR) {
+ if (!lparen && lop == LOGAND)
+ return true;
+ if (!rparen && rop == LOGAND)
+ return true;
+ return false;
+ }
+
+ lint_assert(op == BITAND || op == BITXOR || op == BITOR);
+ if (!lparen && lop != op) {
+ if (lop == PLUS || lop == MINUS)
+ return true;
+ if (lop == BITAND || lop == BITXOR)
+ return true;
+ }
+ if (!rparen && rop != op) {
+ if (rop == PLUS || rop == MINUS)
+ return true;
+ if (rop == BITAND || rop == BITXOR)
+ return true;
+ }
+ return false;
+}
+
+/*
+ * 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
+check_precedence_confusion(tnode_t *tn)
+{
+ tnode_t *ln, *rn;
+
+ if (!hflag)
+ return;
+
+ debug_node(tn);
+
+ lint_assert(is_binary(tn));
+ for (ln = tn->tn_left; ln->tn_op == CVT; ln = ln->tn_left)
+ continue;
+ for (rn = tn->tn_right; rn->tn_op == CVT; rn = rn->tn_left)
+ continue;
+
+ if (is_confusing_precedence(tn->tn_op,
+ ln->tn_op, ln->tn_parenthesized,
+ rn->tn_op, rn->tn_parenthesized)) {
+ /* precedence confusion possible: parenthesize! */
+ warning(169);
+ }
+}
+
+/*
+ * Fold constant nodes, as much as is needed for comparing the value with 0.
+ */
+static tnode_t *
+fold_bool(tnode_t *tn)
+{
+ bool l, r;
+ val_t *v;
+
+ v = xcalloc(1, sizeof(*v));
+ v->v_tspec = tn->tn_type->t_tspec;
+ lint_assert(v->v_tspec == INT || (Tflag && v->v_tspec == BOOL));
+
+ l = constant_is_nonzero(tn->tn_left);
+ r = is_binary(tn) && constant_is_nonzero(tn->tn_right);
+
+ switch (tn->tn_op) {
+ case NOT:
+ if (hflag && !constcond_flag)
+ /* constant argument to '!' */
+ warning(239);
+ v->v_quad = !l ? 1 : 0;
+ break;
+ case LOGAND:
+ v->v_quad = l && r ? 1 : 0;
+ break;
+ case LOGOR:
+ v->v_quad = l || r ? 1 : 0;
+ break;
+ default:
+ lint_assert(/*CONSTCOND*/false);
+ }
+
+ return build_constant(tn->tn_type, v);
+}
+
+static ldbl_t
+floating_error_value(tspec_t t, ldbl_t lv)
+{
+ if (t == FLOAT) {
+ return lv < 0 ? -FLT_MAX : FLT_MAX;
+ } else if (t == DOUBLE) {
+ return lv < 0 ? -DBL_MAX : DBL_MAX;
+ } else {
+ /* LINTED 248: floating-point constant out of range */
+ ldbl_t max = LDBL_MAX;
+ return lv < 0 ? -max : max;
+ }
+}
+
+/*
+ * Fold constant nodes having operands with floating point type.
+ */
+static tnode_t *
+fold_float(tnode_t *tn)
+{
+ val_t *v;
+ tspec_t t;
+ ldbl_t lv, rv = 0;
+
+ fpe = 0;
+ v = xcalloc(1, sizeof(*v));
+ v->v_tspec = t = tn->tn_type->t_tspec;
+
+ lint_assert(is_floating(t));
+ lint_assert(t == tn->tn_left->tn_type->t_tspec);
+ lint_assert(!is_binary(tn) || t == tn->tn_right->tn_type->t_tspec);
+
+ lv = tn->tn_left->tn_val->v_ldbl;
+ if (is_binary(tn))
+ rv = tn->tn_right->tn_val->v_ldbl;
+
+ switch (tn->tn_op) {
+ case UPLUS:
+ v->v_ldbl = lv;
+ break;
+ case UMINUS:
+ v->v_ldbl = -lv;
+ break;
+ case MULT:
+ v->v_ldbl = lv * rv;
+ break;
+ case DIV:
+ if (rv == 0.0) {
+ /* division by 0 */
+ error(139);
+ v->v_ldbl = floating_error_value(t, lv);
+ } else {
+ v->v_ldbl = lv / rv;
+ }
+ break;
+ case PLUS:
+ v->v_ldbl = lv + rv;
+ break;
+ case MINUS:
+ v->v_ldbl = lv - rv;
+ break;
+ case LT:
+ v->v_quad = lv < rv ? 1 : 0;
+ break;
+ case LE:
+ v->v_quad = lv <= rv ? 1 : 0;
+ break;
+ case GE:
+ v->v_quad = lv >= rv ? 1 : 0;
+ break;
+ case GT:
+ v->v_quad = lv > rv ? 1 : 0;
+ break;
+ case EQ:
+ v->v_quad = lv == rv ? 1 : 0;
+ break;
+ case NE:
+ v->v_quad = lv != rv ? 1 : 0;
+ break;
+ default:
+ lint_assert(/*CONSTCOND*/false);
+ }
+
+ lint_assert(fpe != 0 || isnan((double)v->v_ldbl) == 0);
+ if (fpe != 0 || isfinite((double)v->v_ldbl) == 0 ||
+ (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 on operator '%s' */
+ warning(142, op_name(tn->tn_op));
+ v->v_ldbl = floating_error_value(t, v->v_ldbl);
+ fpe = 0;
+ }
+
+ return build_constant(tn->tn_type, v);
}
/*
@@ -917,6 +1786,164 @@ build_unary(op_t op, bool sys, tnode_t *tn)
return build_binary(tn, op, sys, NULL);
}
+/*
+ * Return whether all struct/union members with the same name have the same
+ * type and offset.
+ */
+static bool
+all_members_compatible(const sym_t *msym)
+{
+ for (const sym_t *csym = msym;
+ csym != NULL; csym = csym->s_symtab_next) {
+ if (!is_member(csym))
+ continue;
+ if (strcmp(msym->s_name, csym->s_name) != 0)
+ continue;
+
+ for (const sym_t *sym = csym->s_symtab_next;
+ sym != NULL; sym = sym->s_symtab_next) {
+
+ if (!is_member(sym))
+ continue;
+ if (strcmp(csym->s_name, sym->s_name) != 0)
+ continue;
+ if (csym->u.s_member.sm_offset_in_bits !=
+ sym->u.s_member.sm_offset_in_bits)
+ return false;
+
+ bool w = false;
+ if (!types_compatible(csym->s_type, sym->s_type,
+ false, false, &w) && !w)
+ return false;
+ if (csym->s_bitfield != sym->s_bitfield)
+ return false;
+ if (csym->s_bitfield) {
+ type_t *tp1 = csym->s_type;
+ type_t *tp2 = sym->s_type;
+ if (tp1->t_flen != tp2->t_flen)
+ return false;
+ if (tp1->t_foffs != tp2->t_foffs)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/*
+ * 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.
+ */
+static sym_t *
+struct_or_union_member(tnode_t *tn, op_t op, sym_t *msym)
+{
+ struct_or_union *str;
+ type_t *tp;
+ 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) {
+ /* type '%s' does not have member '%s' */
+ error(101, type_name(tn->tn_type), msym->s_name);
+ rmsym(msym);
+ msym->s_kind = FMEMBER;
+ msym->s_scl = STRUCT_MEMBER;
+
+ struct_or_union *sou = expr_zero_alloc(sizeof(*sou));
+ sou->sou_tag = expr_zero_alloc(sizeof(*sou->sou_tag));
+ sou->sou_tag->s_name = unnamed;
+
+ msym->u.s_member.sm_sou_type = sou;
+ /*
+ * The member sm_offset_in_bits is not needed here since this
+ * symbol can only be used for error reporting.
+ */
+ 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 (is_struct_or_union(t))
+ str = tp->t_str;
+ } else if (op == ARROW && t == PTR) {
+ t = (tp = tp->t_subt)->t_tspec;
+ if (is_struct_or_union(t))
+ str = tp->t_str;
+ }
+
+ /*
+ * If this struct/union has a member with the name of msym, return it.
+ */
+ if (str != NULL) {
+ for (sym_t *sym = msym;
+ sym != NULL; sym = sym->s_symtab_next) {
+ if (!is_member(sym))
+ continue;
+ if (sym->u.s_member.sm_sou_type != str)
+ continue;
+ if (strcmp(sym->s_name, msym->s_name) != 0)
+ continue;
+ return sym;
+ }
+ }
+
+ bool eq = all_members_compatible(msym);
+
+ /*
+ * 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) {
+ if (eq && !allow_c90) {
+ /* illegal use of member '%s' */
+ warning(102, msym->s_name);
+ } else {
+ /* illegal use of member '%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) {
+ if (!allow_c90) {
+ /* left operand of '.' must be struct ... */
+ warning(103, type_name(tn->tn_type));
+ } else {
+ /* left operand of '.' must be struct ... */
+ error(103, type_name(tn->tn_type));
+ }
+ } else {
+ if (!allow_c90 && tn->tn_type->t_tspec == PTR) {
+ /* left operand of '->' must be pointer ... */
+ warning(104, type_name(tn->tn_type));
+ } else {
+ /* left operand of '->' must be pointer ... */
+ error(104, type_name(tn->tn_type));
+ }
+ }
+ } else {
+ if (!allow_c90) {
+ /* non-unique member requires struct/union %s */
+ error(105, op == POINT ? "object" : "pointer");
+ } else {
+ /* unacceptable operand of '%s' */
+ error(111, op_name(op));
+ }
+ }
+
+ return msym;
+}
+
tnode_t *
build_member_access(tnode_t *ln, op_t op, bool sys, sbuf_t *member)
{
@@ -990,16 +2017,6 @@ before_conversion(const tnode_t *tn)
return tn;
}
-static bool
-is_null_pointer(const tnode_t *tn)
-{
- tspec_t t = tn->tn_type->t_tspec;
-
- return ((t == PTR && tn->tn_type->t_subt->t_tspec == VOID) ||
- is_integer(t))
- && (tn->tn_op == CON && tn->tn_val->v_quad == 0);
-}
-
/*
* Most errors required by ANSI C are reported in struct_or_union_member().
* Here we only check for totally wrong things.
@@ -1117,6 +2134,35 @@ typeok_indir(const type_t *tp, tspec_t t)
return true;
}
+/*
+ * Called if incompatible types were detected.
+ * Prints a appropriate warning.
+ */
+static void
+warn_incompatible_types(op_t op,
+ const type_t *ltp, tspec_t lt,
+ const type_t *rtp, tspec_t rt)
+{
+ const 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) {
+ /* cannot assign to '%s' from '%s' */
+ error(171, type_name(ltp), type_name(rtp));
+ } else if (mp->m_binary) {
+ /* operands of '%s' have incompatible types '%s' and '%s' */
+ error(107, mp->m_name, tspec_name(lt), tspec_name(rt));
+ } else {
+ lint_assert(rt == NOTSPEC);
+ /* operand of '%s' has invalid type '%s' */
+ error(108, mp->m_name, type_name(ltp));
+ }
+}
+
static bool
typeok_plus(op_t op,
const type_t *ltp, tspec_t lt,
@@ -1256,6 +2302,78 @@ is_typeok_eq(const tnode_t *ln, tspec_t lt, const tnode_t *rn, tspec_t rt)
return false;
}
+/*
+ * Called if incompatible pointer types are detected.
+ * Print an appropriate warning.
+ */
+static void
+warn_incompatible_pointers(const mod_t *mp,
+ const type_t *ltp, const type_t *rtp)
+{
+ tspec_t lt, rt;
+
+ lint_assert(ltp->t_tspec == PTR);
+ lint_assert(rtp->t_tspec == PTR);
+
+ lt = ltp->t_subt->t_tspec;
+ rt = rtp->t_subt->t_tspec;
+
+ if (is_struct_or_union(lt) && is_struct_or_union(rt)) {
+ if (mp == NULL) {
+ /* illegal structure pointer combination */
+ warning(244);
+ } else {
+ /* incompatible structure pointers: '%s' '%s' '%s' */
+ warning(245, type_name(ltp), mp->m_name, type_name(rtp));
+ }
+ } else {
+ if (mp == NULL) {
+ /* illegal combination of '%s' and '%s' */
+ warning(184, type_name(ltp), type_name(rtp));
+ } else {
+ /* illegal combination of '%s' and '%s', op '%s' */
+ warning(124,
+ type_name(ltp), type_name(rtp), mp->m_name);
+ }
+ }
+}
+
+static void
+check_pointer_comparison(op_t op, const tnode_t *ln, const tnode_t *rn)
+{
+ type_t *ltp, *rtp;
+ tspec_t lst, rst;
+ const char *lsts, *rsts;
+
+ lst = (ltp = ln->tn_type)->t_subt->t_tspec;
+ rst = (rtp = rn->tn_type)->t_subt->t_tspec;
+
+ if (lst == VOID || rst == VOID) {
+ /* TODO: C99 behaves like C90 here. */
+ if ((!allow_trad && !allow_c99) &&
+ (lst == FUNC || rst == FUNC)) {
+ /* (void *)0 already handled in typeok() */
+ *(lst == FUNC ? &lsts : &rsts) = "function pointer";
+ *(lst == VOID ? &lsts : &rsts) = "'void *'";
+ /* ANSI C forbids comparison of %s with %s */
+ warning(274, lsts, rsts);
+ }
+ return;
+ }
+
+ if (!types_compatible(ltp->t_subt, rtp->t_subt, true, false, NULL)) {
+ warn_incompatible_pointers(&modtab[op], ltp, rtp);
+ return;
+ }
+
+ if (lst == FUNC && rst == FUNC) {
+ /* TODO: C99 behaves like C90 here, see C99 6.5.8p2. */
+ if ((!allow_trad && !allow_c99) && op != EQ && op != NE)
+ /* ANSI C forbids ordered comparisons of ... */
+ warning(125);
+ }
+}
+
static bool
typeok_compare(op_t op,
const tnode_t *ln, const type_t *ltp, tspec_t lt,
@@ -1366,6 +2484,28 @@ typeok_colon(const mod_t *mp,
return false;
}
+/*
+ * Returns true if the given structure or union has a constant member
+ * (maybe recursively).
+ */
+static bool
+has_constant_member(const type_t *tp)
+{
+ sym_t *m;
+
+ lint_assert(is_struct_or_union(tp->t_tspec));
+
+ for (m = tp->t_str->sou_first_member; m != NULL; m = m->s_next) {
+ const type_t *mtp = m->s_type;
+ if (mtp->t_const)
+ return true;
+ if (is_struct_or_union(mtp->t_tspec) &&
+ has_constant_member(mtp))
+ return true;
+ }
+ return false;
+}
+
static bool
typeok_assign(op_t op, const tnode_t *ln, const type_t *ltp, tspec_t lt)
{
@@ -1424,183 +2564,39 @@ typeok_scalar(op_t op, const mod_t *mp,
return true;
}
-/*
- * Check the types for specific operators and type combinations.
- *
- * At this point, the operands already conform to the type requirements of
- * the operator, such as being integer, floating or scalar.
- */
-static bool
-typeok_op(op_t op, const mod_t *mp, int arg,
- const tnode_t *ln, const type_t *ltp, tspec_t lt,
- const tnode_t *rn, const type_t *rtp, tspec_t rt)
-{
- switch (op) {
- case ARROW:
- return typeok_arrow(lt);
- case POINT:
- return typeok_point(ln, ltp, lt);
- case INCBEF:
- case DECBEF:
- case INCAFT:
- case DECAFT:
- return typeok_incdec(op, ln, ltp);
- case INDIR:
- return typeok_indir(ltp, lt);
- case ADDR:
- return typeok_address(mp, ln, ltp, lt);
- case PLUS:
- return typeok_plus(op, ltp, lt, rtp, rt);
- case MINUS:
- return typeok_minus(op, ltp, lt, rtp, rt);
- case SHL:
- typeok_shl(mp, lt, rt);
- goto shift;
- case SHR:
- typeok_shr(mp, ln, lt, rn, rt);
- shift:
- typeok_shift(ltp, lt, rn, rt);
- break;
- case LT:
- case LE:
- case GT:
- case GE:
- compare:
- return typeok_compare(op, ln, ltp, lt, rn, rtp, rt);
- case EQ:
- case NE:
- if (is_typeok_eq(ln, lt, rn, rt))
- break;
- goto compare;
- case QUEST:
- return typeok_quest(lt, rn);
- case COLON:
- return typeok_colon(mp, ln, ltp, lt, rn, rtp, rt);
- case ASSIGN:
- case INIT:
- case FARG:
- case RETURN:
- if (!check_assign_types_compatible(op, arg, ln, rn))
- return false;
- goto assign;
- case MULASS:
- case DIVASS:
- case MODASS:
- goto assign;
- case ADDASS:
- case SUBASS:
- if ((lt == PTR && !is_integer(rt)) || rt == PTR) {
- warn_incompatible_types(op, ltp, lt, rtp, rt);
- return false;
- }
- goto assign;
- case SHLASS:
- goto assign;
- case SHRASS:
- if (pflag && !is_uinteger(lt) &&
- !(!allow_c90 && is_uinteger(rt))) {
- /* bitwise '%s' on signed value possibly nonportable */
- warning(117, mp->m_name);
- }
- goto assign;
- case ANDASS:
- case XORASS:
- case ORASS:
- assign:
- return typeok_assign(op, ln, ltp, lt);
- case COMMA:
- if (!modtab[ln->tn_op].m_has_side_effect)
- check_null_effect(ln);
- break;
- default:
- break;
- }
- return true;
-}
-
-static void
-typeok_enum(op_t op, const mod_t *mp, int arg,
- const tnode_t *ln, const type_t *ltp,
- const tnode_t *rn, const type_t *rtp)
-{
- if (mp->m_bad_on_enum &&
- (ltp->t_is_enum || (mp->m_binary && rtp->t_is_enum))) {
- check_bad_enum_operation(op, ln, rn);
- } else if (mp->m_valid_on_enum &&
- (ltp->t_is_enum && rtp != NULL && rtp->t_is_enum)) {
- check_enum_type_mismatch(op, arg, ln, rn);
- } else if (mp->m_valid_on_enum &&
- (ltp->t_is_enum || (rtp != NULL && rtp->t_is_enum))) {
- check_enum_int_mismatch(op, arg, ln, rn);
- }
-}
-
-/* Perform most type checks. Return whether the types are ok. */
-bool
-typeok(op_t op, int arg, const tnode_t *ln, const tnode_t *rn)
-{
- const mod_t *mp;
- tspec_t lt, rt;
- type_t *ltp, *rtp;
-
- mp = &modtab[op];
-
- lint_assert((ltp = ln->tn_type) != NULL);
- lt = ltp->t_tspec;
-
- if (mp->m_binary) {
- lint_assert((rtp = rn->tn_type) != NULL);
- rt = rtp->t_tspec;
- } else {
- rtp = NULL;
- rt = NOTSPEC;
- }
-
- if (Tflag && !typeok_scalar_strict_bool(op, mp, arg, ln, rn))
- return false;
- if (!typeok_scalar(op, mp, ltp, lt, rtp, rt))
- return false;
-
- if (!typeok_op(op, mp, arg, ln, ltp, lt, rn, rtp, rt))
- return false;
-
- typeok_enum(op, mp, arg, ln, ltp, rn, rtp);
- return true;
-}
-
static void
-check_pointer_comparison(op_t op, const tnode_t *ln, const tnode_t *rn)
+check_assign_void_pointer(op_t op, int arg,
+ tspec_t lt, tspec_t lst,
+ tspec_t rt, tspec_t rst)
{
- type_t *ltp, *rtp;
- tspec_t lst, rst;
- const char *lsts, *rsts;
-
- lst = (ltp = ln->tn_type)->t_subt->t_tspec;
- rst = (rtp = rn->tn_type)->t_subt->t_tspec;
+ const char *lts, *rts;
- if (lst == VOID || rst == VOID) {
- /* TODO: C99 behaves like C90 here. */
- if ((!allow_trad && !allow_c99) &&
- (lst == FUNC || rst == FUNC)) {
- /* (void *)0 already handled in typeok() */
- *(lst == FUNC ? &lsts : &rsts) = "function pointer";
- *(lst == VOID ? &lsts : &rsts) = "'void *'";
- /* ANSI C forbids comparison of %s with %s */
- warning(274, lsts, rsts);
- }
+ if (!(lt == PTR && rt == PTR && (lst == VOID || rst == VOID)))
return;
- }
+ /* two pointers, at least one pointer to void */
- if (!types_compatible(ltp->t_subt, rtp->t_subt, true, false, NULL)) {
- warn_incompatible_pointers(&modtab[op], ltp, rtp);
+ /* TODO: C99 behaves like C90 here. */
+ if (!((!allow_trad && !allow_c99) && (lst == FUNC || rst == FUNC)))
return;
- }
+ /* comb. of ptr to func and ptr to void */
- if (lst == FUNC && rst == FUNC) {
- /* TODO: C99 behaves like C90 here, see C99 6.5.8p2. */
- if ((!allow_trad && !allow_c99) && op != EQ && op != NE)
- /* ANSI C forbids ordered comparisons of ... */
- warning(125);
+ *(lst == FUNC ? &lts : &rts) = "function pointer";
+ *(lst == VOID ? &lts : &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 conversion of %s to %s, arg #%d */
+ warning(304, rts, lts, arg);
+ break;
+ default:
+ /* ANSI C forbids conversion of %s to %s, op %s */
+ warning(305, rts, lts, op_name(op));
+ break;
}
}
@@ -1656,15 +2652,6 @@ is_const_char_pointer(const tnode_t *tn)
}
static bool
-is_const_pointer(const tnode_t *tn)
-{
- const type_t *tp;
-
- tp = before_conversion(tn)->tn_type;
- return tp->t_tspec == PTR && tp->t_subt->t_const;
-}
-
-static bool
is_first_arg_const_char_pointer(const tnode_t *tn)
{
const tnode_t *an;
@@ -1679,6 +2666,15 @@ is_first_arg_const_char_pointer(const tnode_t *tn)
}
static bool
+is_const_pointer(const tnode_t *tn)
+{
+ const type_t *tp;
+
+ tp = before_conversion(tn)->tn_type;
+ return tp->t_tspec == PTR && tp->t_subt->t_const;
+}
+
+static bool
is_second_arg_const_pointer(const tnode_t *tn)
{
const tnode_t *an;
@@ -1714,42 +2710,6 @@ check_unconst_function(const type_t *lstp, const tnode_t *rn)
}
}
-static void
-check_assign_void_pointer(op_t op, int arg,
- tspec_t lt, tspec_t lst,
- tspec_t rt, tspec_t rst)
-{
- const char *lts, *rts;
-
- if (!(lt == PTR && rt == PTR && (lst == VOID || rst == VOID)))
- return;
- /* two pointers, at least one pointer to void */
-
- /* TODO: C99 behaves like C90 here. */
- if (!((!allow_trad && !allow_c99) && (lst == FUNC || rst == FUNC)))
- return;
- /* comb. of ptr to func and ptr to void */
-
- *(lst == FUNC ? &lts : &rts) = "function pointer";
- *(lst == VOID ? &lts : &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 conversion of %s to %s, arg #%d */
- warning(304, rts, lts, arg);
- break;
- default:
- /* ANSI C forbids conversion of %s to %s, op %s */
- warning(305, rts, lts, op_name(op));
- break;
- }
-}
-
static bool
check_assign_void_pointer_compat(op_t op, int arg,
const type_t *const ltp, tspec_t const lt,
@@ -1920,6 +2880,170 @@ check_assign_types_compatible(op_t op, int arg,
return false;
}
+static bool
+has_side_effect(const tnode_t *tn) /* NOLINT(misc-no-recursion) */
+{
+ op_t op = tn->tn_op;
+
+ if (modtab[op].m_has_side_effect)
+ return true;
+
+ if (op == CVT && tn->tn_type->t_tspec == VOID)
+ return has_side_effect(tn->tn_left);
+
+ /* XXX: Why not has_side_effect(tn->tn_left) as well? */
+ if (op == LOGAND || op == LOGOR)
+ return has_side_effect(tn->tn_right);
+
+ /* XXX: Why not has_side_effect(tn->tn_left) as well? */
+ if (op == QUEST)
+ return has_side_effect(tn->tn_right);
+
+ if (op == COLON || op == COMMA) {
+ return has_side_effect(tn->tn_left) ||
+ has_side_effect(tn->tn_right);
+ }
+
+ return false;
+}
+
+static bool
+is_void_cast(const tnode_t *tn)
+{
+
+ return tn->tn_op == CVT && tn->tn_cast &&
+ tn->tn_type->t_tspec == VOID;
+}
+
+static bool
+is_local_symbol(const tnode_t *tn)
+{
+
+ return tn->tn_op == LOAD &&
+ tn->tn_left->tn_op == NAME &&
+ tn->tn_left->tn_sym->s_scl == AUTO;
+}
+
+static bool
+is_int_constant_zero(const tnode_t *tn)
+{
+
+ return tn->tn_op == CON &&
+ tn->tn_type->t_tspec == INT &&
+ tn->tn_val->v_quad == 0;
+}
+
+static void
+check_null_effect(const tnode_t *tn)
+{
+
+ if (!hflag)
+ return;
+ if (has_side_effect(tn))
+ return;
+ if (is_void_cast(tn) && is_local_symbol(tn->tn_left))
+ return;
+ if (is_void_cast(tn) && is_int_constant_zero(tn->tn_left))
+ return;
+
+ /* expression has null effect */
+ warning(129);
+}
+
+/*
+ * Check the types for specific operators and type combinations.
+ *
+ * At this point, the operands already conform to the type requirements of
+ * the operator, such as being integer, floating or scalar.
+ */
+static bool
+typeok_op(op_t op, const mod_t *mp, int arg,
+ const tnode_t *ln, const type_t *ltp, tspec_t lt,
+ const tnode_t *rn, const type_t *rtp, tspec_t rt)
+{
+ switch (op) {
+ case ARROW:
+ return typeok_arrow(lt);
+ case POINT:
+ return typeok_point(ln, ltp, lt);
+ case INCBEF:
+ case DECBEF:
+ case INCAFT:
+ case DECAFT:
+ return typeok_incdec(op, ln, ltp);
+ case INDIR:
+ return typeok_indir(ltp, lt);
+ case ADDR:
+ return typeok_address(mp, ln, ltp, lt);
+ case PLUS:
+ return typeok_plus(op, ltp, lt, rtp, rt);
+ case MINUS:
+ return typeok_minus(op, ltp, lt, rtp, rt);
+ case SHL:
+ typeok_shl(mp, lt, rt);
+ goto shift;
+ case SHR:
+ typeok_shr(mp, ln, lt, rn, rt);
+ shift:
+ typeok_shift(ltp, lt, rn, rt);
+ break;
+ case LT:
+ case LE:
+ case GT:
+ case GE:
+ compare:
+ return typeok_compare(op, ln, ltp, lt, rn, rtp, rt);
+ case EQ:
+ case NE:
+ if (is_typeok_eq(ln, lt, rn, rt))
+ break;
+ goto compare;
+ case QUEST:
+ return typeok_quest(lt, rn);
+ case COLON:
+ return typeok_colon(mp, ln, ltp, lt, rn, rtp, rt);
+ case ASSIGN:
+ case INIT:
+ case FARG:
+ case RETURN:
+ if (!check_assign_types_compatible(op, arg, ln, rn))
+ return false;
+ goto assign;
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ goto assign;
+ case ADDASS:
+ case SUBASS:
+ if ((lt == PTR && !is_integer(rt)) || rt == PTR) {
+ warn_incompatible_types(op, ltp, lt, rtp, rt);
+ return false;
+ }
+ goto assign;
+ case SHLASS:
+ goto assign;
+ case SHRASS:
+ if (pflag && !is_uinteger(lt) &&
+ !(!allow_c90 && is_uinteger(rt))) {
+ /* bitwise '%s' on signed value possibly nonportable */
+ warning(117, mp->m_name);
+ }
+ goto assign;
+ case ANDASS:
+ case XORASS:
+ case ORASS:
+ assign:
+ return typeok_assign(op, ln, ltp, lt);
+ case COMMA:
+ if (!modtab[ln->tn_op].m_has_side_effect)
+ check_null_effect(ln);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
/* Prints a warning if a strange operator is used on an enum type. */
static void
check_bad_enum_operation(op_t op, const tnode_t *ln, const tnode_t *rn)
@@ -2023,79 +3147,53 @@ check_enum_int_mismatch(op_t op, int arg, const tnode_t *ln, const tnode_t *rn)
}
static void
-check_enum_array_index(const tnode_t *ln, const tnode_t *rn)
+typeok_enum(op_t op, const mod_t *mp, int arg,
+ const tnode_t *ln, const type_t *ltp,
+ const tnode_t *rn, const type_t *rtp)
{
- int max_array_index;
- int64_t max_enum_value;
- const struct sym *ec, *max_ec;
- const type_t *lt, *rt;
-
- if (ln->tn_op != ADDR || ln->tn_left->tn_op != NAME)
- return;
-
- lt = ln->tn_left->tn_type;
- if (lt->t_tspec != ARRAY || lt->t_incomplete_array)
- return;
-
- if (rn->tn_op != CVT || !rn->tn_type->t_is_enum)
- return;
- if (rn->tn_left->tn_op != LOAD)
- return;
-
- rt = rn->tn_left->tn_type;
- ec = rt->t_enum->en_first_enumerator;
- max_ec = ec;
- lint_assert(ec != NULL);
- for (ec = ec->s_next; ec != NULL; ec = ec->s_next)
- if (ec->u.s_enum_constant > max_ec->u.s_enum_constant)
- max_ec = ec;
-
- max_enum_value = max_ec->u.s_enum_constant;
- lint_assert(INT_MIN <= max_enum_value && max_enum_value <= INT_MAX);
-
- max_array_index = lt->t_dim - 1;
- if (max_enum_value == max_array_index)
- return;
-
- /*
- * If the name of the largest enum constant contains 'MAX' or 'NUM',
- * that constant is typically not part of the allowed enum values but
- * a marker for the number of actual enum values.
- */
- if (max_enum_value == max_array_index + 1 &&
- (strstr(max_ec->s_name, "MAX") != NULL ||
- strstr(max_ec->s_name, "max") != NULL ||
- strstr(max_ec->s_name, "NUM") != NULL ||
- strstr(max_ec->s_name, "num") != NULL))
- return;
-
- /* maximum value %d of '%s' does not match maximum array index %d */
- warning(348, (int)max_enum_value, type_name(rt), max_array_index);
- print_previous_declaration(max_ec);
+ if (mp->m_bad_on_enum &&
+ (ltp->t_is_enum || (mp->m_binary && rtp->t_is_enum))) {
+ check_bad_enum_operation(op, ln, rn);
+ } else if (mp->m_valid_on_enum &&
+ (ltp->t_is_enum && rtp != NULL && rtp->t_is_enum)) {
+ check_enum_type_mismatch(op, arg, ln, rn);
+ } else if (mp->m_valid_on_enum &&
+ (ltp->t_is_enum || (rtp != NULL && rtp->t_is_enum))) {
+ check_enum_int_mismatch(op, arg, ln, rn);
+ }
}
-/*
- * Build and initialize a new node.
- */
-static tnode_t *
-new_tnode(op_t op, bool sys, type_t *type, tnode_t *ln, tnode_t *rn)
+/* Perform most type checks. Return whether the types are ok. */
+bool
+typeok(op_t op, int arg, const tnode_t *ln, const tnode_t *rn)
{
+ const mod_t *mp;
+ tspec_t lt, rt;
+ type_t *ltp, *rtp;
- tnode_t *ntn = expr_alloc_tnode();
- ntn->tn_op = op;
- ntn->tn_type = type;
- ntn->tn_sys = sys;
- ntn->tn_left = ln;
- ntn->tn_right = rn;
+ mp = &modtab[op];
- if (op == INDIR || op == FSEL) {
- lint_assert(ln->tn_type->t_tspec == PTR);
- tspec_t t = ln->tn_type->t_subt->t_tspec;
- if (t != FUNC && t != VOID)
- ntn->tn_lvalue = true;
+ lint_assert((ltp = ln->tn_type) != NULL);
+ lt = ltp->t_tspec;
+
+ if (mp->m_binary) {
+ lint_assert((rtp = rn->tn_type) != NULL);
+ rt = rtp->t_tspec;
+ } else {
+ rtp = NULL;
+ rt = NOTSPEC;
}
- return ntn;
+ if (Tflag && !typeok_scalar_strict_bool(op, mp, arg, ln, rn))
+ return false;
+ if (!typeok_scalar(op, mp, ltp, lt, rtp, rt))
+ return false;
+
+ if (!typeok_op(op, mp, arg, ln, ltp, lt, rn, rtp, rt))
+ return false;
+
+ typeok_enum(op, mp, arg, ln, ltp, rn, rtp);
+ return true;
}
/* In traditional C, keep unsigned and promote FLOAT to DOUBLE. */
@@ -2176,108 +3274,6 @@ promote(op_t op, bool farg, tnode_t *tn)
return convert(op, 0, ntp, tn);
}
-static tnode_t *
-apply_usual_arithmetic_conversions(op_t op, tnode_t *tn, tspec_t t)
-{
- type_t *ntp = expr_dup_type(tn->tn_type);
- ntp->t_tspec = t;
- if (tn->tn_op != CON) {
- /* usual arithmetic conversion for '%s' from '%s' to '%s' */
- query_message(4, op_name(op),
- type_name(tn->tn_type), type_name(ntp));
- }
- return convert(op, 0, ntp, tn);
-}
-
-static const tspec_t arith_rank[] = {
- LDOUBLE, DOUBLE, FLOAT,
-#ifdef INT128_SIZE
- UINT128, INT128,
-#endif
- UQUAD, QUAD,
- ULONG, LONG,
- UINT, INT,
-};
-
-/* Keep unsigned in traditional C */
-static tspec_t
-usual_arithmetic_conversion_trad(tspec_t lt, tspec_t rt)
-{
-
- size_t i;
- for (i = 0; arith_rank[i] != INT; i++)
- if (lt == arith_rank[i] || rt == arith_rank[i])
- break;
-
- tspec_t t = arith_rank[i];
- if (is_uinteger(lt) || is_uinteger(rt))
- if (is_integer(t) && !is_uinteger(t))
- return unsigned_type(t);
- return t;
-}
-
-static tspec_t
-usual_arithmetic_conversion_c90(tspec_t lt, tspec_t rt)
-{
-
- if (lt == rt)
- return lt;
-
- if (lt == LCOMPLEX || rt == LCOMPLEX)
- return LCOMPLEX;
- if (lt == DCOMPLEX || rt == DCOMPLEX)
- return DCOMPLEX;
- if (lt == FCOMPLEX || rt == FCOMPLEX)
- return FCOMPLEX;
- if (lt == LDOUBLE || rt == LDOUBLE)
- return LDOUBLE;
- if (lt == DOUBLE || rt == DOUBLE)
- return DOUBLE;
- if (lt == FLOAT || rt == FLOAT)
- return FLOAT;
-
- /*
- * If type A has more bits than type B, it should be able to hold all
- * possible values of type B.
- */
- if (size_in_bits(lt) > size_in_bits(rt))
- return lt;
- if (size_in_bits(lt) < size_in_bits(rt))
- return rt;
-
- size_t i;
- for (i = 3; arith_rank[i] != INT; i++)
- if (arith_rank[i] == lt || arith_rank[i] == rt)
- break;
- if ((is_uinteger(lt) || is_uinteger(rt)) &&
- !is_uinteger(arith_rank[i]))
- i--;
- return arith_rank[i];
-}
-
-/*
- * Apply the "usual arithmetic conversions" (C99 6.3.1.8), which gives both
- * operands the same type.
- */
-static void
-balance(op_t op, tnode_t **lnp, tnode_t **rnp)
-{
-
- tspec_t lt = (*lnp)->tn_type->t_tspec;
- tspec_t rt = (*rnp)->tn_type->t_tspec;
- if (!is_arithmetic(lt) || !is_arithmetic(rt))
- return;
-
- tspec_t t = allow_c90
- ? usual_arithmetic_conversion_c90(lt, rt)
- : usual_arithmetic_conversion_trad(lt, rt);
-
- if (t != lt)
- *lnp = apply_usual_arithmetic_conversions(op, *lnp, t);
- if (t != rt)
- *rnp = apply_usual_arithmetic_conversions(op, *rnp, t);
-}
-
static void
convert_integer_from_floating(op_t op, const type_t *tp, const tnode_t *tn)
{
@@ -2290,74 +3286,6 @@ convert_integer_from_floating(op_t op, const type_t *tp, const tnode_t *tn)
query_message(1, type_name(tn->tn_type), type_name(tp));
}
-/*
- * Insert a conversion operator, which converts the type of the node
- * to another given type.
- *
- * Possible values for 'op':
- * CVT a cast-expression
- * binary integer promotion for one of the operands, or a usual
- * arithmetic conversion
- * binary plain or compound assignments to bit-fields
- * FARG 'arg' is the number of the argument (used for warnings)
- * NOOP several other implicit conversions
- * ...
- */
-tnode_t *
-convert(op_t op, int arg, type_t *tp, tnode_t *tn)
-{
- tnode_t *ntn;
- tspec_t nt, ot;
-
- nt = tp->t_tspec;
- ot = tn->tn_type->t_tspec;
-
- if (allow_trad && allow_c90 && op == FARG)
- check_prototype_conversion(arg, nt, ot, tp, tn);
-
- if (nt == BOOL) {
- /* No further checks. */
-
- } else if (is_integer(nt)) {
- if (ot == BOOL) {
- /* No further checks. */
- } else if (is_integer(ot)) {
- convert_integer_from_integer(op, arg, nt, ot, tp, tn);
- } else if (is_floating(ot)) {
- convert_integer_from_floating(op, tp, tn);
- } else if (ot == PTR) {
- convert_integer_from_pointer(op, nt, tp, tn);
- }
-
- } else if (is_floating(nt)) {
- /* No further checks. */
-
- } else if (nt == PTR) {
- if (is_null_pointer(tn)) {
- /* a null pointer may be assigned to any pointer. */
- } else if (ot == PTR && op == CVT) {
- convert_pointer_from_pointer(tp, tn);
- }
- }
-
- ntn = expr_alloc_tnode();
- ntn->tn_op = CVT;
- ntn->tn_type = tp;
- ntn->tn_cast = op == CVT;
- ntn->tn_sys |= tn->tn_sys;
- ntn->tn_right = NULL;
- if (tn->tn_op != CON || nt == VOID) {
- ntn->tn_left = tn;
- } else {
- ntn->tn_op = CON;
- ntn->tn_val = expr_zero_alloc(sizeof(*ntn->tn_val));
- convert_constant(op, arg, ntn->tn_type, ntn->tn_val,
- tn->tn_val);
- }
-
- return ntn;
-}
-
static bool
should_warn_about_prototype_conversion(tspec_t nt,
tspec_t ot, const tnode_t *ptn)
@@ -2637,6 +3565,74 @@ convert_pointer_from_pointer(type_t *ntp, tnode_t *tn)
}
}
+/*
+ * Insert a conversion operator, which converts the type of the node
+ * to another given type.
+ *
+ * Possible values for 'op':
+ * CVT a cast-expression
+ * binary integer promotion for one of the operands, or a usual
+ * arithmetic conversion
+ * binary plain or compound assignments to bit-fields
+ * FARG 'arg' is the number of the argument (used for warnings)
+ * NOOP several other implicit conversions
+ * ...
+ */
+tnode_t *
+convert(op_t op, int arg, type_t *tp, tnode_t *tn)
+{
+ tnode_t *ntn;
+ tspec_t nt, ot;
+
+ nt = tp->t_tspec;
+ ot = tn->tn_type->t_tspec;
+
+ if (allow_trad && allow_c90 && op == FARG)
+ check_prototype_conversion(arg, nt, ot, tp, tn);
+
+ if (nt == BOOL) {
+ /* No further checks. */
+
+ } else if (is_integer(nt)) {
+ if (ot == BOOL) {
+ /* No further checks. */
+ } else if (is_integer(ot)) {
+ convert_integer_from_integer(op, arg, nt, ot, tp, tn);
+ } else if (is_floating(ot)) {
+ convert_integer_from_floating(op, tp, tn);
+ } else if (ot == PTR) {
+ convert_integer_from_pointer(op, nt, tp, tn);
+ }
+
+ } else if (is_floating(nt)) {
+ /* No further checks. */
+
+ } else if (nt == PTR) {
+ if (is_null_pointer(tn)) {
+ /* a null pointer may be assigned to any pointer. */
+ } else if (ot == PTR && op == CVT) {
+ convert_pointer_from_pointer(tp, tn);
+ }
+ }
+
+ ntn = expr_alloc_tnode();
+ ntn->tn_op = CVT;
+ ntn->tn_type = tp;
+ ntn->tn_cast = op == CVT;
+ ntn->tn_sys |= tn->tn_sys;
+ ntn->tn_right = NULL;
+ if (tn->tn_op != CON || nt == VOID) {
+ ntn->tn_left = tn;
+ } else {
+ ntn->tn_op = CON;
+ ntn->tn_val = expr_zero_alloc(sizeof(*ntn->tn_val));
+ convert_constant(op, arg, ntn->tn_type, ntn->tn_val,
+ tn->tn_val);
+ }
+
+ return ntn;
+}
+
static void
convert_constant_floating(op_t op, int arg, tspec_t ot, const type_t *tp,
tspec_t nt, val_t *v, val_t *nv)
@@ -2944,838 +3940,6 @@ convert_constant(op_t op, int arg, const type_t *tp, val_t *nv, val_t *v)
}
/*
- * Called if incompatible types were detected.
- * Prints a appropriate warning.
- */
-static void
-warn_incompatible_types(op_t op,
- const type_t *ltp, tspec_t lt,
- const type_t *rtp, tspec_t rt)
-{
- const 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) {
- /* cannot assign to '%s' from '%s' */
- error(171, type_name(ltp), type_name(rtp));
- } else if (mp->m_binary) {
- /* operands of '%s' have incompatible types '%s' and '%s' */
- error(107, mp->m_name, tspec_name(lt), tspec_name(rt));
- } else {
- lint_assert(rt == NOTSPEC);
- /* operand of '%s' has invalid type '%s' */
- error(108, mp->m_name, type_name(ltp));
- }
-}
-
-/*
- * Called if incompatible pointer types are detected.
- * Print an appropriate warning.
- */
-static void
-warn_incompatible_pointers(const mod_t *mp,
- const type_t *ltp, const type_t *rtp)
-{
- tspec_t lt, rt;
-
- lint_assert(ltp->t_tspec == PTR);
- lint_assert(rtp->t_tspec == PTR);
-
- lt = ltp->t_subt->t_tspec;
- rt = rtp->t_subt->t_tspec;
-
- if (is_struct_or_union(lt) && is_struct_or_union(rt)) {
- if (mp == NULL) {
- /* illegal structure pointer combination */
- warning(244);
- } else {
- /* incompatible structure pointers: '%s' '%s' '%s' */
- warning(245, type_name(ltp), mp->m_name, type_name(rtp));
- }
- } else {
- if (mp == NULL) {
- /* illegal combination of '%s' and '%s' */
- warning(184, type_name(ltp), type_name(rtp));
- } else {
- /* illegal combination of '%s' and '%s', op '%s' */
- warning(124,
- type_name(ltp), type_name(rtp), mp->m_name);
- }
- }
-}
-
-/* Return a type based on tp1, with added qualifiers from tp2. */
-static type_t *
-merge_qualifiers(type_t *tp1, const type_t *tp2)
-{
- type_t *ntp, *nstp;
- bool c1, c2, v1, v2;
-
- lint_assert(tp1->t_tspec == PTR);
- lint_assert(tp2->t_tspec == PTR);
-
- c1 = tp1->t_subt->t_const;
- c2 = tp2->t_subt->t_const;
- v1 = tp1->t_subt->t_volatile;
- v2 = tp2->t_subt->t_volatile;
-
- if (c1 == (c1 | c2) && v1 == (v1 | v2))
- return tp1;
-
- nstp = expr_dup_type(tp1->t_subt);
- nstp->t_const |= c2;
- nstp->t_volatile |= v2;
-
- ntp = expr_dup_type(tp1);
- ntp->t_subt = nstp;
- return ntp;
-}
-
-/*
- * Returns true if the given structure or union has a constant member
- * (maybe recursively).
- */
-static bool
-has_constant_member(const type_t *tp)
-{
- sym_t *m;
-
- lint_assert(is_struct_or_union(tp->t_tspec));
-
- for (m = tp->t_str->sou_first_member; m != NULL; m = m->s_next) {
- const type_t *mtp = m->s_type;
- if (mtp->t_const)
- return true;
- if (is_struct_or_union(mtp->t_tspec) &&
- has_constant_member(mtp))
- return true;
- }
- return false;
-}
-
-/*
- * Create a new node for one of the operators POINT and ARROW.
- */
-static tnode_t *
-build_struct_access(op_t op, bool sys, tnode_t *ln, tnode_t *rn)
-{
- tnode_t *ntn, *ctn;
- bool nolval;
-
- lint_assert(rn->tn_op == NAME);
- lint_assert(is_member(rn->tn_sym));
-
- /*
- * 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 = build_address(sys, ln, true);
- } else if (ln->tn_type->t_tspec != PTR) {
- lint_assert(!allow_c90);
- lint_assert(is_integer(ln->tn_type->t_tspec));
- ln = convert(NOOP, 0, expr_derive_type(gettyp(VOID), PTR), ln);
- }
-
- ctn = build_integer_constant(PTRDIFF_TSPEC,
- rn->tn_sym->u.s_member.sm_offset_in_bits / CHAR_SIZE);
-
- ntn = new_tnode(PLUS, sys, expr_derive_type(rn->tn_type, PTR),
- ln, ctn);
- if (ln->tn_op == CON)
- ntn = fold(ntn);
-
- if (rn->tn_type->t_bitfield) {
- ntn = new_tnode(FSEL, sys, ntn->tn_type->t_subt, ntn, NULL);
- } else {
- ntn = new_tnode(INDIR, sys, ntn->tn_type->t_subt, ntn, NULL);
- }
-
- if (nolval)
- ntn->tn_lvalue = false;
-
- return ntn;
-}
-
-/*
- * Create a node for INCAFT, INCBEF, DECAFT and DECBEF.
- */
-static tnode_t *
-build_prepost_incdec(op_t op, bool sys, tnode_t *ln)
-{
- tnode_t *cn, *ntn;
-
- lint_assert(ln != NULL);
-
- if (ln->tn_type->t_tspec == PTR) {
- cn = subt_size_in_bytes(ln->tn_type);
- } else {
- cn = build_integer_constant(INT, (int64_t)1);
- }
- ntn = new_tnode(op, sys, ln->tn_type, ln, cn);
-
- return ntn;
-}
-
-/*
- * Create a node for REAL, IMAG
- */
-static tnode_t *
-build_real_imag(op_t op, bool sys, tnode_t *ln)
-{
- tnode_t *cn, *ntn;
-
- lint_assert(ln != NULL);
-
- if (ln->tn_op == NAME) {
- /*
- * This may be too much, but it avoids wrong warnings.
- * See d_c99_complex_split.c.
- */
- mark_as_used(ln->tn_sym, false, false);
- mark_as_set(ln->tn_sym);
- }
-
- switch (ln->tn_type->t_tspec) {
- case LCOMPLEX:
- /* XXX: integer and LDOUBLE don't match. */
- cn = build_integer_constant(LDOUBLE, (int64_t)1);
- break;
- case DCOMPLEX:
- /* XXX: integer and DOUBLE don't match. */
- cn = build_integer_constant(DOUBLE, (int64_t)1);
- break;
- case FCOMPLEX:
- /* XXX: integer and FLOAT don't match. */
- cn = build_integer_constant(FLOAT, (int64_t)1);
- break;
- default:
- /* '__%s__' is illegal for type '%s' */
- error(276, op == REAL ? "real" : "imag",
- type_name(ln->tn_type));
- return NULL;
- }
- ntn = new_tnode(op, sys, cn->tn_type, ln, cn);
- ntn->tn_lvalue = true;
-
- return ntn;
-}
-
-/*
- * Create a tree node for the unary & operator
- */
-static tnode_t *
-build_address(bool sys, tnode_t *tn, bool noign)
-{
- tspec_t t;
-
- if (!noign && ((t = tn->tn_type->t_tspec) == ARRAY || t == FUNC)) {
- if (!allow_c90)
- /* '&' before array or function: ignored */
- warning(127);
- return tn;
- }
-
- /* eliminate &* */
- if (tn->tn_op == INDIR &&
- tn->tn_left->tn_type->t_tspec == PTR &&
- tn->tn_left->tn_type->t_subt == tn->tn_type) {
- return tn->tn_left;
- }
-
- return new_tnode(ADDR, sys, expr_derive_type(tn->tn_type, PTR),
- tn, NULL);
-}
-
-/*
- * Create a node for operators PLUS and MINUS.
- */
-static tnode_t *
-build_plus_minus(op_t op, bool sys, tnode_t *ln, tnode_t *rn)
-{
-
- /* If pointer and integer, then pointer to the lhs. */
- if (rn->tn_type->t_tspec == PTR && is_integer(ln->tn_type->t_tspec)) {
- tnode_t *tmp = ln;
- ln = rn;
- rn = tmp;
- /* pointer addition has integer on the left-hand side */
- query_message(5);
- }
-
- /* pointer +- integer */
- if (ln->tn_type->t_tspec == PTR && rn->tn_type->t_tspec != PTR) {
- lint_assert(is_integer(rn->tn_type->t_tspec));
-
- check_ctype_macro_invocation(ln, rn);
- check_enum_array_index(ln, rn);
-
- tnode_t *elsz = subt_size_in_bytes(ln->tn_type);
- if (rn->tn_type->t_tspec != elsz->tn_type->t_tspec)
- rn = convert(NOOP, 0, elsz->tn_type, rn);
-
- tnode_t *prod = new_tnode(MULT, sys, rn->tn_type, rn, elsz);
- if (rn->tn_op == CON)
- prod = fold(prod);
-
- return new_tnode(op, sys, ln->tn_type, ln, prod);
- }
-
- /* pointer - pointer */
- if (rn->tn_type->t_tspec == PTR) {
- lint_assert(ln->tn_type->t_tspec == PTR);
- lint_assert(op == MINUS);
-
- type_t *ptrdiff = gettyp(PTRDIFF_TSPEC);
- tnode_t *raw_diff = new_tnode(op, sys, ptrdiff, ln, rn);
- if (ln->tn_op == CON && rn->tn_op == CON)
- raw_diff = fold(raw_diff);
-
- tnode_t *elsz = subt_size_in_bytes(ln->tn_type);
- balance(NOOP, &raw_diff, &elsz);
-
- return new_tnode(DIV, sys, ptrdiff, raw_diff, elsz);
- }
-
- return new_tnode(op, sys, ln->tn_type, ln, rn);
-}
-
-/*
- * Create a node for operators SHL and SHR.
- */
-static tnode_t *
-build_bit_shift(op_t op, bool sys, tnode_t *ln, tnode_t *rn)
-{
-
- if (!allow_c90 && rn->tn_type->t_tspec != INT)
- rn = convert(NOOP, 0, gettyp(INT), rn);
- return new_tnode(op, sys, ln->tn_type, ln, rn);
-}
-
-/* See C99 6.5.15 "Conditional operator". */
-static tnode_t *
-build_colon(bool sys, tnode_t *ln, tnode_t *rn)
-{
- tspec_t lt, rt;
- type_t *tp;
-
- lt = ln->tn_type->t_tspec;
- rt = rn->tn_type->t_tspec;
-
- if (is_arithmetic(lt) && is_arithmetic(rt)) {
- /* The operands were already balanced in build_binary. */
- tp = ln->tn_type;
- } else if (lt == BOOL && rt == BOOL) {
- tp = ln->tn_type;
- } else if (lt == VOID || rt == VOID) {
- tp = gettyp(VOID);
- } else if (is_struct_or_union(lt)) {
- /* Both types must be identical. */
- lint_assert(is_struct_or_union(rt));
- lint_assert(ln->tn_type->t_str == rn->tn_type->t_str);
- if (is_incomplete(ln->tn_type)) {
- /* unknown operand size, op '%s' */
- error(138, op_name(COLON));
- return NULL;
- }
- tp = ln->tn_type;
- } else if (lt == PTR && is_integer(rt)) {
- if (rt != PTRDIFF_TSPEC)
- rn = convert(NOOP, 0, gettyp(PTRDIFF_TSPEC), rn);
- tp = ln->tn_type;
- } else if (rt == PTR && is_integer(lt)) {
- if (lt != PTRDIFF_TSPEC)
- ln = convert(NOOP, 0, gettyp(PTRDIFF_TSPEC), ln);
- tp = rn->tn_type;
- } else if (lt == PTR && is_null_pointer(rn)) {
- tp = merge_qualifiers(ln->tn_type, rn->tn_type);
- } else if (rt == PTR && is_null_pointer(ln)) {
- tp = merge_qualifiers(rn->tn_type, ln->tn_type);
- } else if (lt == PTR && ln->tn_type->t_subt->t_tspec == VOID) {
- tp = merge_qualifiers(ln->tn_type, rn->tn_type);
- } else if (rt == PTR && rn->tn_type->t_subt->t_tspec == VOID) {
- tp = merge_qualifiers(rn->tn_type, ln->tn_type);
- } else {
- /*
- * 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.
- */
- tp = merge_qualifiers(ln->tn_type, rn->tn_type);
- }
-
- return new_tnode(COLON, sys, tp, ln, rn);
-}
-
-/* TODO: check for varargs */
-static bool
-is_cast_redundant(const tnode_t *tn)
-{
- const type_t *ntp = tn->tn_type, *otp = tn->tn_left->tn_type;
- tspec_t nt = ntp->t_tspec, ot = otp->t_tspec;
-
- if (nt == BOOL || ot == BOOL)
- return nt == BOOL && ot == BOOL;
-
- if (is_integer(nt) && is_integer(ot)) {
- unsigned int nw = width_in_bits(ntp), ow = width_in_bits(otp);
- if (is_uinteger(nt) == is_uinteger(ot))
- return nw >= ow;
- return is_uinteger(ot) && nw > ow;
- }
-
- if (is_complex(nt) || is_complex(ot))
- return is_complex(nt) && is_complex(ot) &&
- size_in_bits(nt) >= size_in_bits(ot);
-
- if (is_floating(nt) && is_floating(ot))
- return size_in_bits(nt) >= size_in_bits(ot);
-
- if (nt == PTR && ot == PTR) {
- if (!ntp->t_subt->t_const && otp->t_subt->t_const)
- return false;
- if (!ntp->t_subt->t_volatile && otp->t_subt->t_volatile)
- return false;
-
- if (ntp->t_subt->t_tspec == VOID ||
- otp->t_subt->t_tspec == VOID ||
- types_compatible(ntp->t_subt, otp->t_subt,
- false, false, NULL))
- return true;
- }
-
- return false;
-}
-
-/*
- * Create a node for an assignment operator (both = and op= ).
- */
-static tnode_t *
-build_assignment(op_t op, bool sys, tnode_t *ln, tnode_t *rn)
-{
- tspec_t lt, rt;
- tnode_t *ntn, *ctn;
-
- lint_assert(ln != NULL);
- lint_assert(rn != NULL);
-
- lt = ln->tn_type->t_tspec;
- rt = rn->tn_type->t_tspec;
-
- if ((op == ADDASS || op == SUBASS) && lt == PTR) {
- lint_assert(is_integer(rt));
- ctn = subt_size_in_bytes(ln->tn_type);
- if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec)
- rn = convert(NOOP, 0, ctn->tn_type, rn);
- rn = new_tnode(MULT, sys, rn->tn_type, rn, ctn);
- if (rn->tn_left->tn_op == CON)
- rn = fold(rn);
- }
-
- if ((op == ASSIGN || op == RETURN || op == INIT) &&
- (lt == STRUCT || rt == STRUCT)) {
- lint_assert(lt == rt);
- lint_assert(ln->tn_type->t_str == rn->tn_type->t_str);
- if (is_incomplete(ln->tn_type)) {
- if (op == RETURN) {
- /* cannot return incomplete type */
- error(212);
- } else {
- /* unknown operand size, op '%s' */
- error(138, op_name(op));
- }
- return NULL;
- }
- }
-
- if (op == SHLASS) {
- if (portable_size_in_bits(lt) < portable_size_in_bits(rt)) {
- if (hflag)
- /* semantics of '%s' change in ANSI C; ... */
- warning(118, "<<=");
- }
- } else if (op != SHRASS) {
- if (op == ASSIGN || lt != PTR) {
- if (lt != rt ||
- (ln->tn_type->t_bitfield && rn->tn_op == CON)) {
- rn = convert(op, 0, ln->tn_type, rn);
- rt = lt;
- }
- }
- }
-
- if (any_query_enabled && rn->tn_op == CVT && rn->tn_cast &&
- types_compatible(ln->tn_type, rn->tn_type, false, false, NULL) &&
- is_cast_redundant(rn)) {
- /* redundant cast from '%s' to '%s' before assignment */
- query_message(7,
- type_name(rn->tn_left->tn_type), type_name(rn->tn_type));
- }
-
- ntn = new_tnode(op, sys, ln->tn_type, ln, rn);
-
- return ntn;
-}
-
-/*
- * Get the size in bytes of type tp->t_subt, as a constant expression of type
- * ptrdiff_t as seen from the target platform.
- */
-static tnode_t *
-subt_size_in_bytes(type_t *tp)
-{
- int elem, elsz_in_bits;
-
- lint_assert(tp->t_tspec == PTR);
- tp = tp->t_subt;
-
- elem = 1;
- elsz_in_bits = 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 unknown size */
- gnuism(136);
- break;
- case STRUCT:
- case UNION:
- if ((elsz_in_bits = tp->t_str->sou_size_in_bits) == 0)
- /* cannot do pointer arithmetic on operand of ... */
- error(136);
- break;
- case ENUM:
- if (is_incomplete(tp)) {
- /* cannot do pointer arithmetic on operand of ... */
- warning(136);
- }
- /* FALLTHROUGH */
- default:
- if ((elsz_in_bits = size_in_bits(tp->t_tspec)) == 0) {
- /* cannot do pointer arithmetic on operand of ... */
- error(136);
- } else {
- lint_assert(elsz_in_bits != -1);
- }
- break;
- }
-
- if (elem == 0 && elsz_in_bits != 0) {
- /* cannot do pointer arithmetic on operand of unknown size */
- error(136);
- }
-
- if (elsz_in_bits == 0)
- elsz_in_bits = CHAR_SIZE;
-
- return build_integer_constant(PTRDIFF_TSPEC,
- (int64_t)(elem * elsz_in_bits / CHAR_SIZE));
-}
-
-/*
- * XXX
- * Note: There appear to be a number of bugs in detecting overflow in
- * this function. An audit and a set of proper regression tests are needed.
- * --Perry Metzger, Nov. 16, 2001
- */
-/*
- * Do only as much as necessary to compute constant expressions.
- * Called only if the operator allows folding and all operands are constants.
- */
-static tnode_t *
-fold(tnode_t *tn)
-{
- val_t *v;
- tspec_t t;
- bool utyp, ovfl;
- int64_t sl, sr = 0, q = 0, mask;
- uint64_t ul, ur = 0;
- tnode_t *cn;
-
- v = xcalloc(1, sizeof(*v));
- v->v_tspec = tn->tn_type->t_tspec;
-
- t = tn->tn_left->tn_type->t_tspec;
- utyp = !is_integer(t) || is_uinteger(t);
- ul = sl = tn->tn_left->tn_val->v_quad;
- if (is_binary(tn))
- ur = sr = tn->tn_right->tn_val->v_quad;
-
- mask = value_bits(size_in_bits(t));
- ovfl = false;
-
- switch (tn->tn_op) {
- case UPLUS:
- q = sl;
- break;
- case UMINUS:
- q = sl == INT64_MIN ? sl : -sl;
- if (sl != 0 && msb(q, t) == msb(sl, t))
- ovfl = true;
- break;
- case COMPL:
- q = ~sl;
- break;
- case MULT:
- if (utyp) {
- q = ul * ur;
- if (q != (q & mask))
- ovfl = true;
- else if ((ul != 0) && ((q / ul) != ur))
- ovfl = true;
- } else {
- q = sl * sr;
- if (msb(q, t) != (msb(sl, t) ^ msb(sr, t)))
- ovfl = true;
- }
- break;
- case DIV:
- if (sr == 0) {
- /* division by 0 */
- error(139);
- q = utyp ? -1 : INT64_MAX;
- } else {
- q = utyp ? (int64_t)(ul / ur) : sl / sr;
- }
- break;
- case MOD:
- if (sr == 0) {
- /* modulus by 0 */
- error(140);
- q = 0;
- } else {
- q = utyp ? (int64_t)(ul % ur) : sl % sr;
- }
- break;
- case PLUS:
- q = utyp ? (int64_t)(ul + ur) : sl + sr;
- if (msb(sl, t) && msb(sr, t) && !msb(q, t))
- ovfl = true;
- if (!utyp && !msb(sl, t) && !msb(sr, t) && msb(q, t))
- ovfl = true;
- break;
- case MINUS:
- q = utyp ? (int64_t)(ul - ur) : sl - sr;
- if (!utyp && msb(sl, t) && !msb(sr, t) && !msb(q, t))
- ovfl = true;
- if (!msb(sl, t) && msb(sr, t) && msb(q, t))
- ovfl = true;
- break;
- case SHL:
- /* TODO: warn about out-of-bounds 'sr'. */
- /* TODO: warn about overflow in signed '<<'. */
- q = utyp ? (int64_t)(ul << (sr & 63)) : sl << (sr & 63);
- break;
- case SHR:
- /*
- * The sign must be explicitly extended because
- * shifts of signed values are implementation dependent.
- */
- /* TODO: warn about out-of-bounds 'sr'. */
- q = ul >> (sr & 63);
- q = convert_integer(q, t, size_in_bits(t) - (int)sr);
- break;
- case LT:
- q = (utyp ? ul < ur : sl < sr) ? 1 : 0;
- break;
- case LE:
- q = (utyp ? ul <= ur : sl <= sr) ? 1 : 0;
- break;
- case GE:
- q = (utyp ? ul >= ur : sl >= sr) ? 1 : 0;
- break;
- case GT:
- q = (utyp ? ul > ur : sl > sr) ? 1 : 0;
- break;
- case EQ:
- q = (utyp ? ul == ur : sl == sr) ? 1 : 0;
- break;
- case NE:
- q = (utyp ? ul != ur : sl != sr) ? 1 : 0;
- break;
- case BITAND:
- q = utyp ? (int64_t)(ul & ur) : sl & sr;
- break;
- case BITXOR:
- q = utyp ? (int64_t)(ul ^ ur) : sl ^ sr;
- break;
- case BITOR:
- q = utyp ? (int64_t)(ul | ur) : sl | sr;
- break;
- default:
- lint_assert(/*CONSTCOND*/false);
- }
-
- /* XXX does not work for quads. */
- if (ovfl ||
- ((uint64_t)(q | mask) != ~(uint64_t)0 && (q & ~mask) != 0)) {
- if (hflag)
- /* integer overflow detected, op '%s' */
- warning(141, op_name(tn->tn_op));
- }
-
- v->v_quad = convert_integer(q, t, 0);
-
- cn = build_constant(tn->tn_type, v);
- if (tn->tn_left->tn_system_dependent)
- cn->tn_system_dependent = true;
- if (is_binary(tn) && tn->tn_right->tn_system_dependent)
- cn->tn_system_dependent = true;
-
- return cn;
-}
-
-/*
- * Fold constant nodes, as much as is needed for comparing the value with 0.
- */
-static tnode_t *
-fold_bool(tnode_t *tn)
-{
- bool l, r;
- val_t *v;
-
- v = xcalloc(1, sizeof(*v));
- v->v_tspec = tn->tn_type->t_tspec;
- lint_assert(v->v_tspec == INT || (Tflag && v->v_tspec == BOOL));
-
- l = constant_is_nonzero(tn->tn_left);
- r = is_binary(tn) && constant_is_nonzero(tn->tn_right);
-
- switch (tn->tn_op) {
- case NOT:
- if (hflag && !constcond_flag)
- /* constant argument to '!' */
- warning(239);
- v->v_quad = !l ? 1 : 0;
- break;
- case LOGAND:
- v->v_quad = l && r ? 1 : 0;
- break;
- case LOGOR:
- v->v_quad = l || r ? 1 : 0;
- break;
- default:
- lint_assert(/*CONSTCOND*/false);
- }
-
- return build_constant(tn->tn_type, v);
-}
-
-static ldbl_t
-floating_error_value(tspec_t t, ldbl_t lv)
-{
- if (t == FLOAT) {
- return lv < 0 ? -FLT_MAX : FLT_MAX;
- } else if (t == DOUBLE) {
- return lv < 0 ? -DBL_MAX : DBL_MAX;
- } else {
- /* LINTED 248: floating-point constant out of range */
- ldbl_t max = LDBL_MAX;
- return lv < 0 ? -max : max;
- }
-}
-
-/*
- * Fold constant nodes having operands with floating point type.
- */
-static tnode_t *
-fold_float(tnode_t *tn)
-{
- val_t *v;
- tspec_t t;
- ldbl_t lv, rv = 0;
-
- fpe = 0;
- v = xcalloc(1, sizeof(*v));
- v->v_tspec = t = tn->tn_type->t_tspec;
-
- lint_assert(is_floating(t));
- lint_assert(t == tn->tn_left->tn_type->t_tspec);
- lint_assert(!is_binary(tn) || t == tn->tn_right->tn_type->t_tspec);
-
- lv = tn->tn_left->tn_val->v_ldbl;
- if (is_binary(tn))
- rv = tn->tn_right->tn_val->v_ldbl;
-
- switch (tn->tn_op) {
- case UPLUS:
- v->v_ldbl = lv;
- break;
- case UMINUS:
- v->v_ldbl = -lv;
- break;
- case MULT:
- v->v_ldbl = lv * rv;
- break;
- case DIV:
- if (rv == 0.0) {
- /* division by 0 */
- error(139);
- v->v_ldbl = floating_error_value(t, lv);
- } else {
- v->v_ldbl = lv / rv;
- }
- break;
- case PLUS:
- v->v_ldbl = lv + rv;
- break;
- case MINUS:
- v->v_ldbl = lv - rv;
- break;
- case LT:
- v->v_quad = lv < rv ? 1 : 0;
- break;
- case LE:
- v->v_quad = lv <= rv ? 1 : 0;
- break;
- case GE:
- v->v_quad = lv >= rv ? 1 : 0;
- break;
- case GT:
- v->v_quad = lv > rv ? 1 : 0;
- break;
- case EQ:
- v->v_quad = lv == rv ? 1 : 0;
- break;
- case NE:
- v->v_quad = lv != rv ? 1 : 0;
- break;
- default:
- lint_assert(/*CONSTCOND*/false);
- }
-
- lint_assert(fpe != 0 || isnan((double)v->v_ldbl) == 0);
- if (fpe != 0 || isfinite((double)v->v_ldbl) == 0 ||
- (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 on operator '%s' */
- warning(142, op_name(tn->tn_op));
- v->v_ldbl = floating_error_value(t, v->v_ldbl);
- fpe = 0;
- }
-
- return build_constant(tn->tn_type, v);
-}
-
-
-/*
* Create a constant node for sizeof.
*/
tnode_t *
@@ -4027,44 +4191,30 @@ build_function_argument(tnode_t *args, tnode_t *arg)
}
/*
- * Create the node for a function call. Also check types of
- * function arguments and insert conversions, if necessary.
+ * 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.
*/
-tnode_t *
-build_function_call(tnode_t *func, bool sys, tnode_t *args)
+static tnode_t *
+check_prototype_argument(
+ int n, /* pos of arg */
+ type_t *tp, /* expected type (from prototype) */
+ tnode_t *tn) /* argument */
{
- 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;
- }
-
- check_ctype_function_call(func, args);
-
- /*
- * after cconv() func will always be a pointer to a function
- * if it is a valid function designator.
- */
- func = cconv(func);
+ tnode_t *ln;
+ bool dowarn;
- if (func->tn_type->t_tspec != PTR ||
- func->tn_type->t_subt->t_tspec != FUNC) {
- /* cannot call '%s', must be a function */
- error(149, type_name(func->tn_type));
- return NULL;
+ ln = xcalloc(1, sizeof(*ln));
+ ln->tn_type = expr_unqualified_type(tp);
+ ln->tn_lvalue = true;
+ if (typeok(FARG, n, ln, tn)) {
+ if (!types_compatible(tp, tn->tn_type,
+ true, false, (dowarn = false, &dowarn)) || dowarn)
+ tn = convert(FARG, n, tp, tn);
}
-
- args = check_function_arguments(func->tn_type->t_subt, args);
-
- ntn = new_tnode(fcop, sys, func->tn_type->t_subt->t_subt, func, args);
-
- return ntn;
+ free(ln);
+ return tn;
}
/*
@@ -4141,30 +4291,44 @@ check_function_arguments(type_t *ftp, tnode_t *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.
+ * Create the node for a function call. Also check types of
+ * function arguments and insert conversions, if necessary.
*/
-static tnode_t *
-check_prototype_argument(
- int n, /* pos of arg */
- type_t *tp, /* expected type (from prototype) */
- tnode_t *tn) /* argument */
+tnode_t *
+build_function_call(tnode_t *func, bool sys, tnode_t *args)
{
- tnode_t *ln;
- bool dowarn;
+ tnode_t *ntn;
+ op_t fcop;
- ln = xcalloc(1, sizeof(*ln));
- ln->tn_type = expr_unqualified_type(tp);
- ln->tn_lvalue = true;
- if (typeok(FARG, n, ln, tn)) {
- if (!types_compatible(tp, tn->tn_type,
- true, false, (dowarn = false, &dowarn)) || dowarn)
- tn = convert(FARG, n, tp, tn);
+ if (func == NULL)
+ return NULL;
+
+ if (func->tn_op == NAME && func->tn_type->t_tspec == FUNC) {
+ fcop = CALL;
+ } else {
+ fcop = ICALL;
}
- free(ln);
- return tn;
+
+ check_ctype_function_call(func, args);
+
+ /*
+ * 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) {
+ /* cannot call '%s', must be a function */
+ error(149, type_name(func->tn_type));
+ return NULL;
+ }
+
+ args = check_function_arguments(func->tn_type->t_subt, args);
+
+ ntn = new_tnode(fcop, sys, func->tn_type->t_subt->t_subt, func, args);
+
+ return ntn;
}
/*
@@ -4276,74 +4440,63 @@ expr(tnode_t *tn, bool vctx, bool cond, bool dofreeblk, bool is_do_while)
expr_free_all();
}
-static bool
-has_side_effect(const tnode_t *tn) /* NOLINT(misc-no-recursion) */
-{
- op_t op = tn->tn_op;
-
- if (modtab[op].m_has_side_effect)
- return true;
-
- if (op == CVT && tn->tn_type->t_tspec == VOID)
- return has_side_effect(tn->tn_left);
-
- /* XXX: Why not has_side_effect(tn->tn_left) as well? */
- if (op == LOGAND || op == LOGOR)
- return has_side_effect(tn->tn_right);
-
- /* XXX: Why not has_side_effect(tn->tn_left) as well? */
- if (op == QUEST)
- return has_side_effect(tn->tn_right);
-
- if (op == COLON || op == COMMA) {
- return has_side_effect(tn->tn_left) ||
- has_side_effect(tn->tn_right);
- }
-
- return false;
-}
-
-static bool
-is_void_cast(const tnode_t *tn)
-{
-
- return tn->tn_op == CVT && tn->tn_cast &&
- tn->tn_type->t_tspec == VOID;
-}
-
-static bool
-is_local_symbol(const tnode_t *tn)
-{
-
- return tn->tn_op == LOAD &&
- tn->tn_left->tn_op == NAME &&
- tn->tn_left->tn_sym->s_scl == AUTO;
-}
-
-static bool
-is_int_constant_zero(const tnode_t *tn)
+/*
+ * 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 allowed to refer to the first element
+ * after the array.
+ */
+static void
+check_array_index(tnode_t *tn, bool amper)
{
+ int dim;
+ tnode_t *ln, *rn;
+ int elsz;
+ int64_t con;
- return tn->tn_op == CON &&
- tn->tn_type->t_tspec == INT &&
- tn->tn_val->v_quad == 0;
-}
+ ln = tn->tn_left;
+ rn = tn->tn_right;
-static void
-check_null_effect(const tnode_t *tn)
-{
+ /* We can only check constant indices. */
+ if (rn->tn_op != CON)
+ return;
- if (!hflag)
+ /* Return if the left node does not stem from an array. */
+ if (ln->tn_op != ADDR)
return;
- if (has_side_effect(tn))
+ if (ln->tn_left->tn_op != STRING && ln->tn_left->tn_op != NAME)
return;
- if (is_void_cast(tn) && is_local_symbol(tn->tn_left))
+ if (ln->tn_left->tn_type->t_tspec != ARRAY)
return;
- if (is_void_cast(tn) && is_int_constant_zero(tn->tn_left))
+
+ /*
+ * For incomplete array types, we can print a warning only if
+ * the index is negative.
+ */
+ if (is_incomplete(ln->tn_left->tn_type) && rn->tn_val->v_quad >= 0)
return;
- /* expression has null effect */
- warning(129);
+ /* Get the size of one array element */
+ if ((elsz = length_in_bits(ln->tn_type->t_subt, NULL)) == 0)
+ return;
+ elsz /= CHAR_SIZE;
+
+ /* Change the unit of the index from bytes to element size. */
+ if (is_uinteger(rn->tn_type->t_tspec)) {
+ con = (uint64_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 (!is_uinteger(rn->tn_type->t_tspec) && con < 0) {
+ /* array subscript cannot be negative: %ld */
+ warning(167, (long)con);
+ } else if (dim > 0 && (uint64_t)con >= (uint64_t)dim) {
+ /* array subscript cannot be > %d: %ld */
+ warning(168, dim - 1, (long)con);
+ }
}
static void
@@ -4549,135 +4702,6 @@ check_expr_misc(const tnode_t *tn, bool vctx, bool cond,
}
/*
- * 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 allowed to refer to the first element
- * after the array.
- */
-static void
-check_array_index(tnode_t *tn, bool amper)
-{
- int dim;
- tnode_t *ln, *rn;
- int elsz;
- int64_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 != ADDR)
- 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 (is_incomplete(ln->tn_left->tn_type) && rn->tn_val->v_quad >= 0)
- return;
-
- /* Get the size of one array element */
- if ((elsz = length_in_bits(ln->tn_type->t_subt, NULL)) == 0)
- return;
- elsz /= CHAR_SIZE;
-
- /* Change the unit of the index from bytes to element size. */
- if (is_uinteger(rn->tn_type->t_tspec)) {
- con = (uint64_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 (!is_uinteger(rn->tn_type->t_tspec) && con < 0) {
- /* array subscript cannot be negative: %ld */
- warning(167, (long)con);
- } else if (dim > 0 && (uint64_t)con >= (uint64_t)dim) {
- /* array subscript cannot be > %d: %ld */
- warning(168, dim - 1, (long)con);
- }
-}
-
-static bool
-is_out_of_char_range(const tnode_t *tn)
-{
- return tn->tn_op == CON &&
- !(0 <= tn->tn_val->v_quad &&
- tn->tn_val->v_quad < 1 << (CHAR_SIZE - 1));
-}
-
-/*
- * Check for ordered comparisons of unsigned values with 0.
- */
-static void
-check_integer_comparison(op_t op, tnode_t *ln, tnode_t *rn)
-{
- tspec_t lt, rt;
-
- lt = ln->tn_type->t_tspec;
- rt = rn->tn_type->t_tspec;
-
- if (ln->tn_op != CON && rn->tn_op != CON)
- return;
-
- if (!is_integer(lt) || !is_integer(rt))
- return;
-
- if (hflag || pflag) {
- if (lt == CHAR && is_out_of_char_range(rn)) {
- char buf[128];
- (void)snprintf(buf, sizeof(buf), "%s %d",
- op_name(op), (int)rn->tn_val->v_quad);
- /* nonportable character comparison '%s' */
- warning(230, buf);
- return;
- }
- if (rt == CHAR && is_out_of_char_range(ln)) {
- char buf[128];
- (void)snprintf(buf, sizeof(buf), "%d %s ?",
- (int)ln->tn_val->v_quad, op_name(op));
- /* nonportable character comparison '%s' */
- warning(230, buf);
- return;
- }
- }
-
- if (is_uinteger(lt) && !is_uinteger(rt) &&
- rn->tn_op == CON && rn->tn_val->v_quad <= 0) {
- if (rn->tn_val->v_quad < 0) {
- /* operator '%s' compares '%s' with '%s' */
- warning(162, op_name(op),
- type_name(ln->tn_type), "negative constant");
- } else if (op == LT || op == GE) {
- /* operator '%s' compares '%s' with '%s' */
- warning(162, op_name(op), type_name(ln->tn_type), "0");
- }
- return;
- }
- if (is_uinteger(rt) && !is_uinteger(lt) &&
- ln->tn_op == CON && ln->tn_val->v_quad <= 0) {
- if (ln->tn_val->v_quad < 0) {
- /* operator '%s' compares '%s' with '%s' */
- warning(162, op_name(op),
- "negative constant", type_name(rn->tn_type));
- } else if (op == GT || op == LE) {
- /* operator '%s' compares '%s' with '%s' */
- warning(162, op_name(op), "0", type_name(rn->tn_type));
- }
- return;
- }
-}
-
-/*
* Return whether the expression can be used for static initialization.
*
* Constant initialization expressions must be constant or an address
@@ -4793,72 +4817,6 @@ cat_strings(strg_t *s1, strg_t *s2)
return s1;
}
-static bool
-is_confusing_precedence(op_t op, op_t lop, bool lparen, op_t rop, bool rparen)
-{
-
- if (op == SHL || op == SHR) {
- if (!lparen && (lop == PLUS || lop == MINUS))
- return true;
- if (!rparen && (rop == PLUS || rop == MINUS))
- return true;
- return false;
- }
-
- if (op == LOGOR) {
- if (!lparen && lop == LOGAND)
- return true;
- if (!rparen && rop == LOGAND)
- return true;
- return false;
- }
-
- lint_assert(op == BITAND || op == BITXOR || op == BITOR);
- if (!lparen && lop != op) {
- if (lop == PLUS || lop == MINUS)
- return true;
- if (lop == BITAND || lop == BITXOR)
- return true;
- }
- if (!rparen && rop != op) {
- if (rop == PLUS || rop == MINUS)
- return true;
- if (rop == BITAND || rop == BITXOR)
- return true;
- }
- return false;
-}
-
-/*
- * 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
-check_precedence_confusion(tnode_t *tn)
-{
- tnode_t *ln, *rn;
-
- if (!hflag)
- return;
-
- debug_node(tn);
-
- lint_assert(is_binary(tn));
- for (ln = tn->tn_left; ln->tn_op == CVT; ln = ln->tn_left)
- continue;
- for (rn = tn->tn_right; rn->tn_op == CVT; rn = rn->tn_left)
- continue;
-
- if (is_confusing_precedence(tn->tn_op,
- ln->tn_op, ln->tn_parenthesized,
- rn->tn_op, rn->tn_parenthesized)) {
- /* precedence confusion possible: parenthesize! */
- warning(169);
- }
-}
typedef struct stmt_expr {
memory_pool se_mem;