summaryrefslogtreecommitdiff
path: root/usr/src/tools/smatch/src/evaluate.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/tools/smatch/src/evaluate.c')
-rw-r--r--usr/src/tools/smatch/src/evaluate.c3666
1 files changed, 3666 insertions, 0 deletions
diff --git a/usr/src/tools/smatch/src/evaluate.c b/usr/src/tools/smatch/src/evaluate.c
new file mode 100644
index 0000000000..8f07d08cf5
--- /dev/null
+++ b/usr/src/tools/smatch/src/evaluate.c
@@ -0,0 +1,3666 @@
+/*
+ * sparse/evaluate.c
+ *
+ * Copyright (C) 2003 Transmeta Corp.
+ * 2003-2004 Linus Torvalds
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Evaluate constant expressions.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include "lib.h"
+#include "allocate.h"
+#include "parse.h"
+#include "token.h"
+#include "symbol.h"
+#include "target.h"
+#include "expression.h"
+
+struct symbol *current_fn;
+
+static struct symbol *degenerate(struct expression *expr);
+static struct symbol *evaluate_symbol(struct symbol *sym);
+
+static struct symbol *evaluate_symbol_expression(struct expression *expr)
+{
+ struct expression *addr;
+ struct symbol *sym = expr->symbol;
+ struct symbol *base_type;
+
+ if (!sym) {
+ expression_error(expr, "undefined identifier '%s'", show_ident(expr->symbol_name));
+ return NULL;
+ }
+
+ examine_symbol_type(sym);
+
+ base_type = get_base_type(sym);
+ if (!base_type) {
+ expression_error(expr, "identifier '%s' has no type", show_ident(expr->symbol_name));
+ return NULL;
+ }
+
+ addr = alloc_expression(expr->pos, EXPR_SYMBOL);
+ addr->symbol = sym;
+ addr->symbol_name = expr->symbol_name;
+ addr->ctype = &lazy_ptr_ctype; /* Lazy evaluation: we need to do a proper job if somebody does &sym */
+ addr->flags = expr->flags;
+ expr->type = EXPR_PREOP;
+ expr->op = '*';
+ expr->unop = addr;
+ expr->flags = CEF_NONE;
+
+ /* The type of a symbol is the symbol itself! */
+ expr->ctype = sym;
+ return sym;
+}
+
+static struct symbol *evaluate_string(struct expression *expr)
+{
+ struct symbol *sym = alloc_symbol(expr->pos, SYM_NODE);
+ struct symbol *array = alloc_symbol(expr->pos, SYM_ARRAY);
+ struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
+ struct expression *initstr = alloc_expression(expr->pos, EXPR_STRING);
+ unsigned int length = expr->string->length;
+
+ sym->array_size = alloc_const_expression(expr->pos, length);
+ sym->bit_size = bytes_to_bits(length);
+ sym->ctype.alignment = 1;
+ sym->string = 1;
+ sym->ctype.modifiers = MOD_STATIC;
+ sym->ctype.base_type = array;
+ sym->initializer = initstr;
+
+ initstr->ctype = sym;
+ initstr->string = expr->string;
+
+ array->array_size = sym->array_size;
+ array->bit_size = bytes_to_bits(length);
+ array->ctype.alignment = 1;
+ array->ctype.modifiers = MOD_STATIC;
+ array->ctype.base_type = &char_ctype;
+
+ addr->symbol = sym;
+ addr->ctype = &lazy_ptr_ctype;
+ addr->flags = CEF_ADDR;
+
+ expr->type = EXPR_PREOP;
+ expr->op = '*';
+ expr->unop = addr;
+ expr->ctype = sym;
+ return sym;
+}
+
+/* type has come from classify_type and is an integer type */
+static inline struct symbol *integer_promotion(struct symbol *type)
+{
+ unsigned long mod = type->ctype.modifiers;
+ int width = type->bit_size;
+
+ /*
+ * Bitfields always promote to the base type,
+ * even if the bitfield might be bigger than
+ * an "int".
+ */
+ if (type->type == SYM_BITFIELD) {
+ type = type->ctype.base_type;
+ }
+ mod = type->ctype.modifiers;
+ if (width < bits_in_int)
+ return &int_ctype;
+
+ /* If char/short has as many bits as int, it still gets "promoted" */
+ if (mod & (MOD_CHAR | MOD_SHORT)) {
+ if (mod & MOD_UNSIGNED)
+ return &uint_ctype;
+ return &int_ctype;
+ }
+ return type;
+}
+
+/*
+ * integer part of usual arithmetic conversions:
+ * integer promotions are applied
+ * if left and right are identical, we are done
+ * if signedness is the same, convert one with lower rank
+ * unless unsigned argument has rank lower than signed one, convert the
+ * signed one.
+ * if signed argument is bigger than unsigned one, convert the unsigned.
+ * otherwise, convert signed.
+ *
+ * Leaving aside the integer promotions, that is equivalent to
+ * if identical, don't convert
+ * if left is bigger than right, convert right
+ * if right is bigger than left, convert right
+ * otherwise, if signedness is the same, convert one with lower rank
+ * otherwise convert the signed one.
+ */
+static struct symbol *bigger_int_type(struct symbol *left, struct symbol *right)
+{
+ unsigned long lmod, rmod;
+
+ left = integer_promotion(left);
+ right = integer_promotion(right);
+
+ if (left == right)
+ goto left;
+
+ if (left->bit_size > right->bit_size)
+ goto left;
+
+ if (right->bit_size > left->bit_size)
+ goto right;
+
+ lmod = left->ctype.modifiers;
+ rmod = right->ctype.modifiers;
+ if ((lmod ^ rmod) & MOD_UNSIGNED) {
+ if (lmod & MOD_UNSIGNED)
+ goto left;
+ } else if ((lmod & ~rmod) & (MOD_LONG_ALL))
+ goto left;
+right:
+ left = right;
+left:
+ return left;
+}
+
+static int same_cast_type(struct symbol *orig, struct symbol *new)
+{
+ return orig->bit_size == new->bit_size &&
+ orig->bit_offset == new->bit_offset;
+}
+
+static struct symbol *base_type(struct symbol *node, unsigned long *modp, unsigned long *asp)
+{
+ unsigned long mod, as;
+
+ mod = 0; as = 0;
+ while (node) {
+ mod |= node->ctype.modifiers;
+ as |= node->ctype.as;
+ if (node->type == SYM_NODE) {
+ node = node->ctype.base_type;
+ continue;
+ }
+ break;
+ }
+ *modp = mod & ~MOD_IGNORE;
+ *asp = as;
+ return node;
+}
+
+static int is_same_type(struct expression *expr, struct symbol *new)
+{
+ struct symbol *old = expr->ctype;
+ unsigned long oldmod, newmod, oldas, newas;
+
+ old = base_type(old, &oldmod, &oldas);
+ new = base_type(new, &newmod, &newas);
+
+ /* Same base type, same address space? */
+ if (old == new && oldas == newas) {
+ unsigned long difmod;
+
+ /* Check the modifier bits. */
+ difmod = (oldmod ^ newmod) & ~MOD_NOCAST;
+
+ /* Exact same type? */
+ if (!difmod)
+ return 1;
+
+ /*
+ * Not the same type, but differs only in "const".
+ * Don't warn about MOD_NOCAST.
+ */
+ if (difmod == MOD_CONST)
+ return 0;
+ }
+ if ((oldmod | newmod) & MOD_NOCAST) {
+ const char *tofrom = "to/from";
+ if (!(newmod & MOD_NOCAST))
+ tofrom = "from";
+ if (!(oldmod & MOD_NOCAST))
+ tofrom = "to";
+ warning(expr->pos, "implicit cast %s nocast type", tofrom);
+ }
+ return 0;
+}
+
+static void
+warn_for_different_enum_types (struct position pos,
+ struct symbol *typea,
+ struct symbol *typeb)
+{
+ if (!Wenum_mismatch)
+ return;
+ if (typea->type == SYM_NODE)
+ typea = typea->ctype.base_type;
+ if (typeb->type == SYM_NODE)
+ typeb = typeb->ctype.base_type;
+
+ if (typea == typeb)
+ return;
+
+ if (typea->type == SYM_ENUM && typeb->type == SYM_ENUM) {
+ warning(pos, "mixing different enum types");
+ info(pos, " %s versus", show_typename(typea));
+ info(pos, " %s", show_typename(typeb));
+ }
+}
+
+static int cast_flags(struct expression *expr, struct expression *target);
+static struct symbol *cast_to_bool(struct expression *expr);
+
+/*
+ * This gets called for implicit casts in assignments and
+ * integer promotion. We often want to try to move the
+ * cast down, because the ops involved may have been
+ * implicitly cast up, and we can get rid of the casts
+ * early.
+ */
+static struct expression * cast_to(struct expression *old, struct symbol *type)
+{
+ struct expression *expr;
+
+ warn_for_different_enum_types (old->pos, old->ctype, type);
+
+ if (old->ctype != &null_ctype && is_same_type(old, type))
+ return old;
+
+ /*
+ * See if we can simplify the op. Move the cast down.
+ */
+ switch (old->type) {
+ case EXPR_PREOP:
+ if (old->ctype->bit_size < type->bit_size)
+ break;
+ if (old->op == '~') {
+ old->ctype = type;
+ old->unop = cast_to(old->unop, type);
+ return old;
+ }
+ break;
+
+ case EXPR_IMPLIED_CAST:
+ warn_for_different_enum_types(old->pos, old->ctype, type);
+
+ if (old->ctype->bit_size >= type->bit_size) {
+ struct expression *orig = old->cast_expression;
+ if (same_cast_type(orig->ctype, type))
+ return orig;
+ if (old->ctype->bit_offset == type->bit_offset) {
+ old->ctype = type;
+ old->cast_type = type;
+ return old;
+ }
+ }
+ break;
+
+ default:
+ /* nothing */;
+ }
+
+ expr = alloc_expression(old->pos, EXPR_IMPLIED_CAST);
+ expr->ctype = type;
+ expr->cast_type = type;
+ expr->cast_expression = old;
+ expr->flags = cast_flags(expr, old);
+
+ if (is_bool_type(type))
+ cast_to_bool(expr);
+
+ return expr;
+}
+
+enum {
+ TYPE_NUM = 1,
+ TYPE_BITFIELD = 2,
+ TYPE_RESTRICT = 4,
+ TYPE_FLOAT = 8,
+ TYPE_PTR = 16,
+ TYPE_COMPOUND = 32,
+ TYPE_FOULED = 64,
+ TYPE_FN = 128,
+};
+
+static inline int classify_type(struct symbol *type, struct symbol **base)
+{
+ static int type_class[SYM_BAD + 1] = {
+ [SYM_PTR] = TYPE_PTR,
+ [SYM_FN] = TYPE_PTR | TYPE_FN,
+ [SYM_ARRAY] = TYPE_PTR | TYPE_COMPOUND,
+ [SYM_STRUCT] = TYPE_COMPOUND,
+ [SYM_UNION] = TYPE_COMPOUND,
+ [SYM_BITFIELD] = TYPE_NUM | TYPE_BITFIELD,
+ [SYM_RESTRICT] = TYPE_NUM | TYPE_RESTRICT,
+ [SYM_FOULED] = TYPE_NUM | TYPE_RESTRICT | TYPE_FOULED,
+ };
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ if (type->type == SYM_TYPEOF) {
+ type = evaluate_expression(type->initializer);
+ if (!type)
+ type = &bad_ctype;
+ else if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ }
+ if (type->type == SYM_ENUM)
+ type = type->ctype.base_type;
+ *base = type;
+ if (type->type == SYM_BASETYPE) {
+ if (type->ctype.base_type == &int_type)
+ return TYPE_NUM;
+ if (type->ctype.base_type == &fp_type)
+ return TYPE_NUM | TYPE_FLOAT;
+ }
+ return type_class[type->type];
+}
+
+#define is_int(class) ((class & (TYPE_NUM | TYPE_FLOAT)) == TYPE_NUM)
+
+static inline int is_string_type(struct symbol *type)
+{
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ return type->type == SYM_ARRAY && is_byte_type(type->ctype.base_type);
+}
+
+static struct symbol *bad_expr_type(struct expression *expr)
+{
+ sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
+ switch (expr->type) {
+ case EXPR_BINOP:
+ case EXPR_COMPARE:
+ info(expr->pos, " left side has type %s", show_typename(expr->left->ctype));
+ info(expr->pos, " right side has type %s", show_typename(expr->right->ctype));
+ break;
+ case EXPR_PREOP:
+ case EXPR_POSTOP:
+ info(expr->pos, " argument has type %s", show_typename(expr->unop->ctype));
+ break;
+ default:
+ break;
+ }
+
+ expr->flags = CEF_NONE;
+ return expr->ctype = &bad_ctype;
+}
+
+static int restricted_value(struct expression *v, struct symbol *type)
+{
+ if (v->type != EXPR_VALUE)
+ return 1;
+ if (v->value != 0)
+ return 1;
+ return 0;
+}
+
+static int restricted_binop(int op, struct symbol *type)
+{
+ switch (op) {
+ case '&':
+ case '=':
+ case SPECIAL_AND_ASSIGN:
+ case SPECIAL_OR_ASSIGN:
+ case SPECIAL_XOR_ASSIGN:
+ return 1; /* unfoul */
+ case '|':
+ case '^':
+ case '?':
+ return 2; /* keep fouled */
+ case SPECIAL_EQUAL:
+ case SPECIAL_NOTEQUAL:
+ return 3; /* warn if fouled */
+ default:
+ return 0; /* warn */
+ }
+}
+
+static int restricted_unop(int op, struct symbol **type)
+{
+ if (op == '~') {
+ if ((*type)->bit_size < bits_in_int)
+ *type = befoul(*type);
+ return 0;
+ } if (op == '+')
+ return 0;
+ return 1;
+}
+
+/* type should be SYM_FOULED */
+static inline struct symbol *unfoul(struct symbol *type)
+{
+ return type->ctype.base_type;
+}
+
+static struct symbol *restricted_binop_type(int op,
+ struct expression *left,
+ struct expression *right,
+ int lclass, int rclass,
+ struct symbol *ltype,
+ struct symbol *rtype)
+{
+ struct symbol *ctype = NULL;
+ if (lclass & TYPE_RESTRICT) {
+ if (rclass & TYPE_RESTRICT) {
+ if (ltype == rtype) {
+ ctype = ltype;
+ } else if (lclass & TYPE_FOULED) {
+ if (unfoul(ltype) == rtype)
+ ctype = ltype;
+ } else if (rclass & TYPE_FOULED) {
+ if (unfoul(rtype) == ltype)
+ ctype = rtype;
+ }
+ } else {
+ if (!restricted_value(right, ltype))
+ ctype = ltype;
+ }
+ } else if (!restricted_value(left, rtype))
+ ctype = rtype;
+
+ if (ctype) {
+ switch (restricted_binop(op, ctype)) {
+ case 1:
+ if ((lclass ^ rclass) & TYPE_FOULED)
+ ctype = unfoul(ctype);
+ break;
+ case 3:
+ if (!(lclass & rclass & TYPE_FOULED))
+ break;
+ case 0:
+ ctype = NULL;
+ default:
+ break;
+ }
+ }
+
+ return ctype;
+}
+
+static inline void unrestrict(struct expression *expr,
+ int class, struct symbol **ctype)
+{
+ if (class & TYPE_RESTRICT) {
+ if (class & TYPE_FOULED)
+ *ctype = unfoul(*ctype);
+ warning(expr->pos, "%s degrades to integer",
+ show_typename(*ctype));
+ *ctype = (*ctype)->ctype.base_type; /* get to arithmetic type */
+ }
+}
+
+static struct symbol *usual_conversions(int op,
+ struct expression *left,
+ struct expression *right,
+ int lclass, int rclass,
+ struct symbol *ltype,
+ struct symbol *rtype)
+{
+ struct symbol *ctype;
+
+ warn_for_different_enum_types(right->pos, left->ctype, right->ctype);
+
+ if ((lclass | rclass) & TYPE_RESTRICT)
+ goto Restr;
+
+Normal:
+ if (!(lclass & TYPE_FLOAT)) {
+ if (!(rclass & TYPE_FLOAT))
+ return bigger_int_type(ltype, rtype);
+ else
+ return rtype;
+ } else if (rclass & TYPE_FLOAT) {
+ unsigned long lmod = ltype->ctype.modifiers;
+ unsigned long rmod = rtype->ctype.modifiers;
+ if (rmod & ~lmod & (MOD_LONG_ALL))
+ return rtype;
+ else
+ return ltype;
+ } else
+ return ltype;
+
+Restr:
+ ctype = restricted_binop_type(op, left, right,
+ lclass, rclass, ltype, rtype);
+ if (ctype)
+ return ctype;
+
+ unrestrict(left, lclass, &ltype);
+ unrestrict(right, rclass, &rtype);
+
+ goto Normal;
+}
+
+static inline int lvalue_expression(struct expression *expr)
+{
+ return expr->type == EXPR_PREOP && expr->op == '*';
+}
+
+static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *itype)
+{
+ struct expression *index = expr->right;
+ struct symbol *ctype, *base;
+ int multiply;
+
+ classify_type(degenerate(expr->left), &ctype);
+ base = examine_pointer_target(ctype);
+
+ /*
+ * An address constant +/- an integer constant expression
+ * yields an address constant again [6.6(7)].
+ */
+ if ((expr->left->flags & CEF_ADDR) && (expr->right->flags & CEF_ICE))
+ expr->flags = CEF_ADDR;
+
+ if (!base) {
+ expression_error(expr, "missing type information");
+ return NULL;
+ }
+ if (is_function(base)) {
+ expression_error(expr, "arithmetics on pointers to functions");
+ return NULL;
+ }
+
+ /* Get the size of whatever the pointer points to */
+ multiply = is_void_type(base) ? 1 : bits_to_bytes(base->bit_size);
+
+ if (ctype == &null_ctype)
+ ctype = &ptr_ctype;
+ expr->ctype = ctype;
+
+ if (multiply == 1 && itype->bit_size >= bits_in_pointer)
+ return ctype;
+
+ if (index->type == EXPR_VALUE) {
+ struct expression *val = alloc_expression(expr->pos, EXPR_VALUE);
+ unsigned long long v = index->value, mask;
+ mask = 1ULL << (itype->bit_size - 1);
+ if (v & mask)
+ v |= -mask;
+ else
+ v &= mask - 1;
+ v *= multiply;
+ mask = 1ULL << (bits_in_pointer - 1);
+ v &= mask | (mask - 1);
+ val->value = v;
+ val->ctype = ssize_t_ctype;
+ expr->right = val;
+ return ctype;
+ }
+
+ if (itype->bit_size < bits_in_pointer)
+ index = cast_to(index, ssize_t_ctype);
+
+ if (multiply > 1) {
+ struct expression *val = alloc_expression(expr->pos, EXPR_VALUE);
+ struct expression *mul = alloc_expression(expr->pos, EXPR_BINOP);
+
+ val->ctype = ssize_t_ctype;
+ val->value = multiply;
+
+ mul->op = '*';
+ mul->ctype = ssize_t_ctype;
+ mul->left = index;
+ mul->right = val;
+ index = mul;
+ }
+
+ expr->right = index;
+ return ctype;
+}
+
+static void examine_fn_arguments(struct symbol *fn);
+
+#define MOD_IGN (MOD_VOLATILE | MOD_CONST | MOD_PURE)
+
+const char *type_difference(struct ctype *c1, struct ctype *c2,
+ unsigned long mod1, unsigned long mod2)
+{
+ unsigned long as1 = c1->as, as2 = c2->as;
+ struct symbol *t1 = c1->base_type;
+ struct symbol *t2 = c2->base_type;
+ int move1 = 1, move2 = 1;
+ mod1 |= c1->modifiers;
+ mod2 |= c2->modifiers;
+ for (;;) {
+ unsigned long diff;
+ int type;
+ struct symbol *base1 = t1->ctype.base_type;
+ struct symbol *base2 = t2->ctype.base_type;
+
+ /*
+ * FIXME! Collect alignment and context too here!
+ */
+ if (move1) {
+ if (t1 && t1->type != SYM_PTR) {
+ mod1 |= t1->ctype.modifiers;
+ as1 |= t1->ctype.as;
+ }
+ move1 = 0;
+ }
+
+ if (move2) {
+ if (t2 && t2->type != SYM_PTR) {
+ mod2 |= t2->ctype.modifiers;
+ as2 |= t2->ctype.as;
+ }
+ move2 = 0;
+ }
+
+ if (t1 == t2)
+ break;
+ if (!t1 || !t2)
+ return "different types";
+
+ if (t1->type == SYM_NODE || t1->type == SYM_ENUM) {
+ t1 = base1;
+ move1 = 1;
+ if (!t1)
+ return "bad types";
+ continue;
+ }
+
+ if (t2->type == SYM_NODE || t2->type == SYM_ENUM) {
+ t2 = base2;
+ move2 = 1;
+ if (!t2)
+ return "bad types";
+ continue;
+ }
+
+ move1 = move2 = 1;
+ type = t1->type;
+ if (type != t2->type)
+ return "different base types";
+
+ switch (type) {
+ default:
+ sparse_error(t1->pos,
+ "internal error: bad type in derived(%d)",
+ type);
+ return "bad types";
+ case SYM_RESTRICT:
+ return "different base types";
+ case SYM_UNION:
+ case SYM_STRUCT:
+ /* allow definition of incomplete structs and unions */
+ if (t1->ident == t2->ident)
+ return NULL;
+ return "different base types";
+ case SYM_ARRAY:
+ /* XXX: we ought to compare sizes */
+ break;
+ case SYM_PTR:
+ if (as1 != as2)
+ return "different address spaces";
+ /* MOD_SPECIFIER is due to idiocy in parse.c */
+ if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SPECIFIER)
+ return "different modifiers";
+ /* we could be lazier here */
+ base1 = examine_pointer_target(t1);
+ base2 = examine_pointer_target(t2);
+ mod1 = t1->ctype.modifiers;
+ as1 = t1->ctype.as;
+ mod2 = t2->ctype.modifiers;
+ as2 = t2->ctype.as;
+ break;
+ case SYM_FN: {
+ struct symbol *arg1, *arg2;
+ int i;
+
+ if (as1 != as2)
+ return "different address spaces";
+ if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SIGNEDNESS)
+ return "different modifiers";
+ mod1 = t1->ctype.modifiers;
+ as1 = t1->ctype.as;
+ mod2 = t2->ctype.modifiers;
+ as2 = t2->ctype.as;
+
+ if (t1->variadic != t2->variadic)
+ return "incompatible variadic arguments";
+ examine_fn_arguments(t1);
+ examine_fn_arguments(t2);
+ PREPARE_PTR_LIST(t1->arguments, arg1);
+ PREPARE_PTR_LIST(t2->arguments, arg2);
+ i = 1;
+ for (;;) {
+ const char *diffstr;
+ if (!arg1 && !arg2)
+ break;
+ if (!arg1 || !arg2)
+ return "different argument counts";
+ diffstr = type_difference(&arg1->ctype,
+ &arg2->ctype,
+ MOD_IGN, MOD_IGN);
+ if (diffstr) {
+ static char argdiff[80];
+ sprintf(argdiff, "incompatible argument %d (%s)", i, diffstr);
+ return argdiff;
+ }
+ NEXT_PTR_LIST(arg1);
+ NEXT_PTR_LIST(arg2);
+ i++;
+ }
+ FINISH_PTR_LIST(arg2);
+ FINISH_PTR_LIST(arg1);
+ break;
+ }
+ case SYM_BASETYPE:
+ if (as1 != as2)
+ return "different address spaces";
+ if (base1 != base2)
+ return "different base types";
+ diff = (mod1 ^ mod2) & ~MOD_IGNORE;
+ if (!diff)
+ return NULL;
+ if (diff & MOD_SIZE)
+ return "different type sizes";
+ else if (diff & ~MOD_SIGNEDNESS)
+ return "different modifiers";
+ else
+ return "different signedness";
+ }
+ t1 = base1;
+ t2 = base2;
+ }
+ if (as1 != as2)
+ return "different address spaces";
+ if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SIGNEDNESS)
+ return "different modifiers";
+ return NULL;
+}
+
+static void bad_null(struct expression *expr)
+{
+ if (Wnon_pointer_null)
+ warning(expr->pos, "Using plain integer as NULL pointer");
+}
+
+static unsigned long target_qualifiers(struct symbol *type)
+{
+ unsigned long mod = type->ctype.modifiers & MOD_IGN;
+ if (type->ctype.base_type && type->ctype.base_type->type == SYM_ARRAY)
+ mod = 0;
+ return mod;
+}
+
+static struct symbol *evaluate_ptr_sub(struct expression *expr)
+{
+ const char *typediff;
+ struct symbol *ltype, *rtype;
+ struct expression *l = expr->left;
+ struct expression *r = expr->right;
+ struct symbol *lbase;
+
+ classify_type(degenerate(l), &ltype);
+ classify_type(degenerate(r), &rtype);
+
+ lbase = examine_pointer_target(ltype);
+ examine_pointer_target(rtype);
+ typediff = type_difference(&ltype->ctype, &rtype->ctype,
+ target_qualifiers(rtype),
+ target_qualifiers(ltype));
+ if (typediff)
+ expression_error(expr, "subtraction of different types can't work (%s)", typediff);
+
+ if (is_function(lbase)) {
+ expression_error(expr, "subtraction of functions? Share your drugs");
+ return NULL;
+ }
+
+ expr->ctype = ssize_t_ctype;
+ if (lbase->bit_size > bits_in_char) {
+ struct expression *sub = alloc_expression(expr->pos, EXPR_BINOP);
+ struct expression *div = expr;
+ struct expression *val = alloc_expression(expr->pos, EXPR_VALUE);
+ unsigned long value = bits_to_bytes(lbase->bit_size);
+
+ val->ctype = size_t_ctype;
+ val->value = value;
+
+ if (value & (value-1)) {
+ if (Wptr_subtraction_blows)
+ warning(expr->pos, "potentially expensive pointer subtraction");
+ }
+
+ sub->op = '-';
+ sub->ctype = ssize_t_ctype;
+ sub->left = l;
+ sub->right = r;
+
+ div->op = '/';
+ div->left = sub;
+ div->right = val;
+ }
+
+ return ssize_t_ctype;
+}
+
+#define is_safe_type(type) ((type)->ctype.modifiers & MOD_SAFE)
+
+static struct symbol *evaluate_conditional(struct expression *expr, int iterator)
+{
+ struct symbol *ctype;
+
+ if (!expr)
+ return NULL;
+
+ if (!iterator && expr->type == EXPR_ASSIGNMENT && expr->op == '=')
+ warning(expr->pos, "assignment expression in conditional");
+
+ ctype = evaluate_expression(expr);
+ if (ctype) {
+ if (is_safe_type(ctype))
+ warning(expr->pos, "testing a 'safe expression'");
+ if (is_func_type(ctype)) {
+ if (Waddress)
+ warning(expr->pos, "the address of %s will always evaluate as true", "a function");
+ } else if (is_array_type(ctype)) {
+ if (Waddress)
+ warning(expr->pos, "the address of %s will always evaluate as true", "an array");
+ } else if (!is_scalar_type(ctype)) {
+ sparse_error(expr->pos, "incorrect type in conditional");
+ info(expr->pos, " got %s", show_typename(ctype));
+ ctype = NULL;
+ }
+ }
+ ctype = degenerate(expr);
+
+ return ctype;
+}
+
+static struct symbol *evaluate_logical(struct expression *expr)
+{
+ if (!evaluate_conditional(expr->left, 0))
+ return NULL;
+ if (!evaluate_conditional(expr->right, 0))
+ return NULL;
+
+ /* the result is int [6.5.13(3), 6.5.14(3)] */
+ expr->ctype = &int_ctype;
+ expr->flags = expr->left->flags & expr->right->flags;
+ expr->flags &= ~(CEF_CONST_MASK | CEF_ADDR);
+ return &int_ctype;
+}
+
+static struct symbol *evaluate_binop(struct expression *expr)
+{
+ struct symbol *ltype, *rtype, *ctype;
+ int lclass = classify_type(expr->left->ctype, &ltype);
+ int rclass = classify_type(expr->right->ctype, &rtype);
+ int op = expr->op;
+
+ /* number op number */
+ if (lclass & rclass & TYPE_NUM) {
+ expr->flags = expr->left->flags & expr->right->flags;
+ expr->flags &= ~CEF_CONST_MASK;
+
+ if ((lclass | rclass) & TYPE_FLOAT) {
+ switch (op) {
+ case '+': case '-': case '*': case '/':
+ break;
+ default:
+ return bad_expr_type(expr);
+ }
+ }
+
+ if (op == SPECIAL_LEFTSHIFT || op == SPECIAL_RIGHTSHIFT) {
+ // shifts do integer promotions, but that's it.
+ unrestrict(expr->left, lclass, &ltype);
+ unrestrict(expr->right, rclass, &rtype);
+ ctype = ltype = integer_promotion(ltype);
+ rtype = integer_promotion(rtype);
+ } else {
+ // The rest do usual conversions
+ const unsigned left_not = expr->left->type == EXPR_PREOP
+ && expr->left->op == '!';
+ const unsigned right_not = expr->right->type == EXPR_PREOP
+ && expr->right->op == '!';
+ if ((op == '&' || op == '|') && (left_not || right_not))
+ warning(expr->pos, "dubious: %sx %c %sy",
+ left_not ? "!" : "",
+ op,
+ right_not ? "!" : "");
+
+ ltype = usual_conversions(op, expr->left, expr->right,
+ lclass, rclass, ltype, rtype);
+ ctype = rtype = ltype;
+ }
+
+ expr->left = cast_to(expr->left, ltype);
+ expr->right = cast_to(expr->right, rtype);
+ expr->ctype = ctype;
+ return ctype;
+ }
+
+ /* pointer (+|-) integer */
+ if (lclass & TYPE_PTR && is_int(rclass) && (op == '+' || op == '-')) {
+ unrestrict(expr->right, rclass, &rtype);
+ return evaluate_ptr_add(expr, rtype);
+ }
+
+ /* integer + pointer */
+ if (rclass & TYPE_PTR && is_int(lclass) && op == '+') {
+ struct expression *index = expr->left;
+ unrestrict(index, lclass, &ltype);
+ expr->left = expr->right;
+ expr->right = index;
+ return evaluate_ptr_add(expr, ltype);
+ }
+
+ /* pointer - pointer */
+ if (lclass & rclass & TYPE_PTR && expr->op == '-')
+ return evaluate_ptr_sub(expr);
+
+ return bad_expr_type(expr);
+}
+
+static struct symbol *evaluate_comma(struct expression *expr)
+{
+ expr->ctype = degenerate(expr->right);
+ if (expr->ctype == &null_ctype)
+ expr->ctype = &ptr_ctype;
+ expr->flags &= expr->left->flags & expr->right->flags;
+ return expr->ctype;
+}
+
+static int modify_for_unsigned(int op)
+{
+ if (op == '<')
+ op = SPECIAL_UNSIGNED_LT;
+ else if (op == '>')
+ op = SPECIAL_UNSIGNED_GT;
+ else if (op == SPECIAL_LTE)
+ op = SPECIAL_UNSIGNED_LTE;
+ else if (op == SPECIAL_GTE)
+ op = SPECIAL_UNSIGNED_GTE;
+ return op;
+}
+
+static inline int is_null_pointer_constant(struct expression *e)
+{
+ if (e->ctype == &null_ctype)
+ return 1;
+ if (!(e->flags & CEF_ICE))
+ return 0;
+ return is_zero_constant(e) ? 2 : 0;
+}
+
+static struct symbol *evaluate_compare(struct expression *expr)
+{
+ struct expression *left = expr->left, *right = expr->right;
+ struct symbol *ltype, *rtype, *lbase, *rbase;
+ int lclass = classify_type(degenerate(left), &ltype);
+ int rclass = classify_type(degenerate(right), &rtype);
+ struct symbol *ctype;
+ const char *typediff;
+
+ /* Type types? */
+ if (is_type_type(ltype) && is_type_type(rtype)) {
+ /*
+ * __builtin_types_compatible_p() yields an integer
+ * constant expression
+ */
+ expr->flags = CEF_SET_ICE;
+ goto OK;
+ }
+
+ if (is_safe_type(left->ctype) || is_safe_type(right->ctype))
+ warning(expr->pos, "testing a 'safe expression'");
+
+ expr->flags = left->flags & right->flags & ~CEF_CONST_MASK & ~CEF_ADDR;
+
+ /* number on number */
+ if (lclass & rclass & TYPE_NUM) {
+ ctype = usual_conversions(expr->op, expr->left, expr->right,
+ lclass, rclass, ltype, rtype);
+ expr->left = cast_to(expr->left, ctype);
+ expr->right = cast_to(expr->right, ctype);
+ if (ctype->ctype.modifiers & MOD_UNSIGNED)
+ expr->op = modify_for_unsigned(expr->op);
+ goto OK;
+ }
+
+ /* at least one must be a pointer */
+ if (!((lclass | rclass) & TYPE_PTR))
+ return bad_expr_type(expr);
+
+ /* equality comparisons can be with null pointer constants */
+ if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) {
+ int is_null1 = is_null_pointer_constant(left);
+ int is_null2 = is_null_pointer_constant(right);
+ if (is_null1 == 2)
+ bad_null(left);
+ if (is_null2 == 2)
+ bad_null(right);
+ if (is_null1 && is_null2) {
+ int positive = expr->op == SPECIAL_EQUAL;
+ expr->type = EXPR_VALUE;
+ expr->value = positive;
+ goto OK;
+ }
+ if (is_null1 && (rclass & TYPE_PTR)) {
+ left = cast_to(left, rtype);
+ goto OK;
+ }
+ if (is_null2 && (lclass & TYPE_PTR)) {
+ right = cast_to(right, ltype);
+ goto OK;
+ }
+ }
+ /* both should be pointers */
+ if (!(lclass & rclass & TYPE_PTR))
+ return bad_expr_type(expr);
+ expr->op = modify_for_unsigned(expr->op);
+
+ lbase = examine_pointer_target(ltype);
+ rbase = examine_pointer_target(rtype);
+
+ /* they also have special treatment for pointers to void */
+ if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) {
+ if (ltype->ctype.as == rtype->ctype.as) {
+ if (lbase == &void_ctype) {
+ right = cast_to(right, ltype);
+ goto OK;
+ }
+ if (rbase == &void_ctype) {
+ left = cast_to(left, rtype);
+ goto OK;
+ }
+ }
+ }
+
+ typediff = type_difference(&ltype->ctype, &rtype->ctype,
+ target_qualifiers(rtype),
+ target_qualifiers(ltype));
+ if (!typediff)
+ goto OK;
+
+ expression_error(expr, "incompatible types in comparison expression (%s)", typediff);
+ return NULL;
+
+OK:
+ /* the result is int [6.5.8(6), 6.5.9(3)]*/
+ expr->ctype = &int_ctype;
+ return &int_ctype;
+}
+
+/*
+ * NOTE! The degenerate case of "x ? : y", where we don't
+ * have a true case, this will possibly promote "x" to the
+ * same type as "y", and thus _change_ the conditional
+ * test in the expression. But since promotion is "safe"
+ * for testing, that's OK.
+ */
+static struct symbol *evaluate_conditional_expression(struct expression *expr)
+{
+ struct expression **true;
+ struct symbol *ctype, *ltype, *rtype, *lbase, *rbase;
+ int lclass, rclass;
+ const char * typediff;
+ int qual;
+
+ if (!evaluate_conditional(expr->conditional, 0))
+ return NULL;
+ if (!evaluate_expression(expr->cond_false))
+ return NULL;
+
+ ctype = degenerate(expr->conditional);
+ rtype = degenerate(expr->cond_false);
+
+ true = &expr->conditional;
+ ltype = ctype;
+ if (expr->cond_true) {
+ if (!evaluate_expression(expr->cond_true))
+ return NULL;
+ ltype = degenerate(expr->cond_true);
+ true = &expr->cond_true;
+ }
+
+ expr->flags = (expr->conditional->flags & (*true)->flags &
+ expr->cond_false->flags & ~CEF_CONST_MASK);
+ /*
+ * A conditional operator yields a particular constant
+ * expression type only if all of its three subexpressions are
+ * of that type [6.6(6), 6.6(8)].
+ * As an extension, relax this restriction by allowing any
+ * constant expression type for the condition expression.
+ *
+ * A conditional operator never yields an address constant
+ * [6.6(9)].
+ * However, as an extension, if the condition is any constant
+ * expression, and the true and false expressions are both
+ * address constants, mark the result as an address constant.
+ */
+ if (expr->conditional->flags & (CEF_ACE | CEF_ADDR))
+ expr->flags = (*true)->flags & expr->cond_false->flags & ~CEF_CONST_MASK;
+
+ lclass = classify_type(ltype, &ltype);
+ rclass = classify_type(rtype, &rtype);
+ if (lclass & rclass & TYPE_NUM) {
+ ctype = usual_conversions('?', *true, expr->cond_false,
+ lclass, rclass, ltype, rtype);
+ *true = cast_to(*true, ctype);
+ expr->cond_false = cast_to(expr->cond_false, ctype);
+ goto out;
+ }
+
+ if ((lclass | rclass) & TYPE_PTR) {
+ int is_null1 = is_null_pointer_constant(*true);
+ int is_null2 = is_null_pointer_constant(expr->cond_false);
+
+ if (is_null1 && is_null2) {
+ *true = cast_to(*true, &ptr_ctype);
+ expr->cond_false = cast_to(expr->cond_false, &ptr_ctype);
+ ctype = &ptr_ctype;
+ goto out;
+ }
+ if (is_null1 && (rclass & TYPE_PTR)) {
+ if (is_null1 == 2)
+ bad_null(*true);
+ *true = cast_to(*true, rtype);
+ ctype = rtype;
+ goto out;
+ }
+ if (is_null2 && (lclass & TYPE_PTR)) {
+ if (is_null2 == 2)
+ bad_null(expr->cond_false);
+ expr->cond_false = cast_to(expr->cond_false, ltype);
+ ctype = ltype;
+ goto out;
+ }
+ if (!(lclass & rclass & TYPE_PTR)) {
+ typediff = "different types";
+ goto Err;
+ }
+ /* OK, it's pointer on pointer */
+ if (ltype->ctype.as != rtype->ctype.as) {
+ typediff = "different address spaces";
+ goto Err;
+ }
+
+ /* need to be lazier here */
+ lbase = examine_pointer_target(ltype);
+ rbase = examine_pointer_target(rtype);
+ qual = target_qualifiers(ltype) | target_qualifiers(rtype);
+
+ if (lbase == &void_ctype) {
+ /* XXX: pointers to function should warn here */
+ ctype = ltype;
+ goto Qual;
+
+ }
+ if (rbase == &void_ctype) {
+ /* XXX: pointers to function should warn here */
+ ctype = rtype;
+ goto Qual;
+ }
+ /* XXX: that should be pointer to composite */
+ ctype = ltype;
+ typediff = type_difference(&ltype->ctype, &rtype->ctype,
+ qual, qual);
+ if (!typediff)
+ goto Qual;
+ goto Err;
+ }
+
+ /* void on void, struct on same struct, union on same union */
+ if (ltype == rtype) {
+ ctype = ltype;
+ goto out;
+ }
+ typediff = "different base types";
+
+Err:
+ expression_error(expr, "incompatible types in conditional expression (%s)", typediff);
+ /*
+ * if the condition is constant, the type is in fact known
+ * so use it, as gcc & clang do.
+ */
+ switch (expr_truth_value(expr->conditional)) {
+ case 1: expr->ctype = ltype;
+ break;
+ case 0: expr->ctype = rtype;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+
+out:
+ expr->ctype = ctype;
+ return ctype;
+
+Qual:
+ if (qual & ~ctype->ctype.modifiers) {
+ struct symbol *sym = alloc_symbol(ctype->pos, SYM_PTR);
+ *sym = *ctype;
+ sym->ctype.modifiers |= qual;
+ ctype = sym;
+ }
+ *true = cast_to(*true, ctype);
+ expr->cond_false = cast_to(expr->cond_false, ctype);
+ goto out;
+}
+
+/* FP assignments can not do modulo or bit operations */
+static int compatible_float_op(int op)
+{
+ return op == SPECIAL_ADD_ASSIGN ||
+ op == SPECIAL_SUB_ASSIGN ||
+ op == SPECIAL_MUL_ASSIGN ||
+ op == SPECIAL_DIV_ASSIGN;
+}
+
+static int evaluate_assign_op(struct expression *expr)
+{
+ struct symbol *target = expr->left->ctype;
+ struct symbol *source = expr->right->ctype;
+ struct symbol *t, *s;
+ int tclass = classify_type(target, &t);
+ int sclass = classify_type(source, &s);
+ int op = expr->op;
+
+ if (tclass & sclass & TYPE_NUM) {
+ if (tclass & TYPE_FLOAT && !compatible_float_op(op)) {
+ expression_error(expr, "invalid assignment");
+ return 0;
+ }
+ if (tclass & TYPE_RESTRICT) {
+ if (!restricted_binop(op, t)) {
+ warning(expr->pos, "bad assignment (%s) to %s",
+ show_special(op), show_typename(t));
+ expr->right = cast_to(expr->right, target);
+ return 0;
+ }
+ /* allowed assignments unfoul */
+ if (sclass & TYPE_FOULED && unfoul(s) == t)
+ goto Cast;
+ if (!restricted_value(expr->right, t))
+ return 1;
+ } else if (!(sclass & TYPE_RESTRICT))
+ goto usual;
+ /* source and target would better be identical restricted */
+ if (t == s)
+ return 1;
+ warning(expr->pos, "invalid assignment: %s", show_special(op));
+ info(expr->pos, " left side has type %s", show_typename(t));
+ info(expr->pos, " right side has type %s", show_typename(s));
+ expr->right = cast_to(expr->right, target);
+ return 0;
+ }
+ if (tclass == TYPE_PTR && is_int(sclass)) {
+ if (op == SPECIAL_ADD_ASSIGN || op == SPECIAL_SUB_ASSIGN) {
+ unrestrict(expr->right, sclass, &s);
+ evaluate_ptr_add(expr, s);
+ return 1;
+ }
+ expression_error(expr, "invalid pointer assignment");
+ return 0;
+ }
+
+ expression_error(expr, "invalid assignment");
+ return 0;
+
+usual:
+ target = usual_conversions(op, expr->left, expr->right,
+ tclass, sclass, target, source);
+Cast:
+ expr->right = cast_to(expr->right, target);
+ return 1;
+}
+
+static int whitelist_pointers(struct symbol *t1, struct symbol *t2)
+{
+ if (t1 == t2)
+ return 0; /* yes, 0 - we don't want a cast_to here */
+ if (t1 == &void_ctype)
+ return 1;
+ if (t2 == &void_ctype)
+ return 1;
+ if (classify_type(t1, &t1) != TYPE_NUM)
+ return 0;
+ if (classify_type(t2, &t2) != TYPE_NUM)
+ return 0;
+ if (t1 == t2)
+ return 1;
+ if (t1->ctype.modifiers & t2->ctype.modifiers & MOD_CHAR)
+ return 1;
+ if ((t1->ctype.modifiers ^ t2->ctype.modifiers) & MOD_SIZE)
+ return 0;
+ return !Wtypesign;
+}
+
+static int check_assignment_types(struct symbol *target, struct expression **rp,
+ const char **typediff)
+{
+ struct symbol *source = degenerate(*rp);
+ struct symbol *t, *s;
+ int tclass = classify_type(target, &t);
+ int sclass = classify_type(source, &s);
+
+ if (tclass & sclass & TYPE_NUM) {
+ if (tclass & TYPE_RESTRICT) {
+ /* allowed assignments unfoul */
+ if (sclass & TYPE_FOULED && unfoul(s) == t)
+ goto Cast;
+ if (!restricted_value(*rp, target))
+ return 1;
+ if (s == t)
+ return 1;
+ } else if (!(sclass & TYPE_RESTRICT))
+ goto Cast;
+ if (t == &bool_ctype) {
+ if (is_fouled_type(s))
+ warning((*rp)->pos, "%s degrades to integer",
+ show_typename(s->ctype.base_type));
+ goto Cast;
+ }
+ *typediff = "different base types";
+ return 0;
+ }
+
+ if (tclass == TYPE_PTR) {
+ unsigned long mod1, mod2;
+ struct symbol *b1, *b2;
+ // NULL pointer is always OK
+ int is_null = is_null_pointer_constant(*rp);
+ if (is_null) {
+ if (is_null == 2)
+ bad_null(*rp);
+ goto Cast;
+ }
+ if (!(sclass & TYPE_PTR)) {
+ *typediff = "different base types";
+ return 0;
+ }
+ b1 = examine_pointer_target(t);
+ b2 = examine_pointer_target(s);
+ mod1 = target_qualifiers(t);
+ mod2 = target_qualifiers(s);
+ if (whitelist_pointers(b1, b2)) {
+ /*
+ * assignments to/from void * are OK, provided that
+ * we do not remove qualifiers from pointed to [C]
+ * or mix address spaces [sparse].
+ */
+ if (t->ctype.as != s->ctype.as) {
+ *typediff = "different address spaces";
+ return 0;
+ }
+ /*
+ * If this is a function pointer assignment, it is
+ * actually fine to assign a pointer to const data to
+ * it, as a function pointer points to const data
+ * implicitly, i.e., dereferencing it does not produce
+ * an lvalue.
+ */
+ if (b1->type == SYM_FN)
+ mod1 |= MOD_CONST;
+ if (mod2 & ~mod1) {
+ *typediff = "different modifiers";
+ return 0;
+ }
+ goto Cast;
+ }
+ /* It's OK if the target is more volatile or const than the source */
+ *typediff = type_difference(&t->ctype, &s->ctype, 0, mod1);
+ if (*typediff)
+ return 0;
+ return 1;
+ }
+
+ if ((tclass & TYPE_COMPOUND) && s == t)
+ return 1;
+
+ if (tclass & TYPE_NUM) {
+ /* XXX: need to turn into comparison with NULL */
+ if (t == &bool_ctype && (sclass & TYPE_PTR))
+ goto Cast;
+ *typediff = "different base types";
+ return 0;
+ }
+ *typediff = "invalid types";
+ return 0;
+
+Cast:
+ *rp = cast_to(*rp, target);
+ return 1;
+}
+
+static int compatible_assignment_types(struct expression *expr, struct symbol *target,
+ struct expression **rp, const char *where)
+{
+ const char *typediff;
+ struct symbol *source = degenerate(*rp);
+
+ if (!check_assignment_types(target, rp, &typediff)) {
+ warning(expr->pos, "incorrect type in %s (%s)", where, typediff);
+ info(expr->pos, " expected %s", show_typename(target));
+ info(expr->pos, " got %s", show_typename(source));
+ *rp = cast_to(*rp, target);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int compatible_transparent_union(struct symbol *target,
+ struct expression **rp)
+{
+ struct symbol *t, *member;
+ classify_type(target, &t);
+ if (t->type != SYM_UNION || !t->transparent_union)
+ return 0;
+
+ FOR_EACH_PTR(t->symbol_list, member) {
+ const char *typediff;
+ if (check_assignment_types(member, rp, &typediff))
+ return 1;
+ } END_FOR_EACH_PTR(member);
+
+ return 0;
+}
+
+static int compatible_argument_type(struct expression *expr, struct symbol *target,
+ struct expression **rp, const char *where)
+{
+ if (compatible_transparent_union(target, rp))
+ return 1;
+
+ return compatible_assignment_types(expr, target, rp, where);
+}
+
+static void mark_assigned(struct expression *expr)
+{
+ struct symbol *sym;
+
+ if (!expr)
+ return;
+ switch (expr->type) {
+ case EXPR_SYMBOL:
+ sym = expr->symbol;
+ if (!sym)
+ return;
+ if (sym->type != SYM_NODE)
+ return;
+ sym->ctype.modifiers |= MOD_ASSIGNED;
+ return;
+
+ case EXPR_BINOP:
+ mark_assigned(expr->left);
+ mark_assigned(expr->right);
+ return;
+ case EXPR_CAST:
+ case EXPR_FORCE_CAST:
+ mark_assigned(expr->cast_expression);
+ return;
+ case EXPR_SLICE:
+ mark_assigned(expr->base);
+ return;
+ default:
+ /* Hmm? */
+ return;
+ }
+}
+
+static void evaluate_assign_to(struct expression *left, struct symbol *type)
+{
+ if (type->ctype.modifiers & MOD_CONST)
+ expression_error(left, "assignment to const expression");
+
+ /* We know left is an lvalue, so it's a "preop-*" */
+ mark_assigned(left->unop);
+}
+
+static struct symbol *evaluate_assignment(struct expression *expr)
+{
+ struct expression *left = expr->left;
+ struct expression *where = expr;
+ struct symbol *ltype;
+
+ if (!lvalue_expression(left)) {
+ expression_error(expr, "not an lvalue");
+ return NULL;
+ }
+
+ ltype = left->ctype;
+
+ if (expr->op != '=') {
+ if (!evaluate_assign_op(expr))
+ return NULL;
+ } else {
+ if (!compatible_assignment_types(where, ltype, &expr->right, "assignment"))
+ return NULL;
+ }
+
+ evaluate_assign_to(left, ltype);
+
+ expr->ctype = ltype;
+ return ltype;
+}
+
+static void examine_fn_arguments(struct symbol *fn)
+{
+ struct symbol *s;
+
+ FOR_EACH_PTR(fn->arguments, s) {
+ struct symbol *arg = evaluate_symbol(s);
+ /* Array/function arguments silently degenerate into pointers */
+ if (arg) {
+ struct symbol *ptr;
+ switch(arg->type) {
+ case SYM_ARRAY:
+ case SYM_FN:
+ ptr = alloc_symbol(s->pos, SYM_PTR);
+ if (arg->type == SYM_ARRAY)
+ ptr->ctype = arg->ctype;
+ else
+ ptr->ctype.base_type = arg;
+ ptr->ctype.as |= s->ctype.as;
+ ptr->ctype.modifiers |= s->ctype.modifiers & MOD_PTRINHERIT;
+
+ s->ctype.base_type = ptr;
+ s->ctype.as = 0;
+ s->ctype.modifiers &= ~MOD_PTRINHERIT;
+ s->bit_size = 0;
+ s->examined = 0;
+ examine_symbol_type(s);
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ }
+ } END_FOR_EACH_PTR(s);
+}
+
+static struct symbol *convert_to_as_mod(struct symbol *sym, int as, int mod)
+{
+ /* Take the modifiers of the pointer, and apply them to the member */
+ mod |= sym->ctype.modifiers;
+ if (sym->ctype.as != as || sym->ctype.modifiers != mod) {
+ struct symbol *newsym = alloc_symbol(sym->pos, SYM_NODE);
+ *newsym = *sym;
+ newsym->ctype.as = as;
+ newsym->ctype.modifiers = mod;
+ sym = newsym;
+ }
+ return sym;
+}
+
+static struct symbol *create_pointer(struct expression *expr, struct symbol *sym, int degenerate)
+{
+ struct symbol *node = alloc_symbol(expr->pos, SYM_NODE);
+ struct symbol *ptr = alloc_symbol(expr->pos, SYM_PTR);
+
+ node->ctype.base_type = ptr;
+ ptr->bit_size = bits_in_pointer;
+ ptr->ctype.alignment = pointer_alignment;
+
+ node->bit_size = bits_in_pointer;
+ node->ctype.alignment = pointer_alignment;
+
+ access_symbol(sym);
+ if (sym->ctype.modifiers & MOD_REGISTER) {
+ warning(expr->pos, "taking address of 'register' variable '%s'", show_ident(sym->ident));
+ sym->ctype.modifiers &= ~MOD_REGISTER;
+ }
+ if (sym->type == SYM_NODE) {
+ ptr->ctype.as |= sym->ctype.as;
+ ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT;
+ sym = sym->ctype.base_type;
+ }
+ if (degenerate && sym->type == SYM_ARRAY) {
+ ptr->ctype.as |= sym->ctype.as;
+ ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT;
+ sym = sym->ctype.base_type;
+ }
+ ptr->ctype.base_type = sym;
+
+ return node;
+}
+
+/* Arrays degenerate into pointers on pointer arithmetic */
+static struct symbol *degenerate(struct expression *expr)
+{
+ struct symbol *ctype, *base;
+
+ if (!expr)
+ return NULL;
+ ctype = expr->ctype;
+ if (!ctype)
+ return NULL;
+ base = examine_symbol_type(ctype);
+ if (ctype->type == SYM_NODE)
+ base = ctype->ctype.base_type;
+ /*
+ * Arrays degenerate into pointers to the entries, while
+ * functions degenerate into pointers to themselves.
+ * If array was part of non-lvalue compound, we create a copy
+ * of that compound first and then act as if we were dealing with
+ * the corresponding field in there.
+ */
+ switch (base->type) {
+ case SYM_ARRAY:
+ if (expr->type == EXPR_SLICE) {
+ struct symbol *a = alloc_symbol(expr->pos, SYM_NODE);
+ struct expression *e0, *e1, *e2, *e3, *e4;
+
+ a->ctype.base_type = expr->base->ctype;
+ a->bit_size = expr->base->ctype->bit_size;
+ a->array_size = expr->base->ctype->array_size;
+
+ e0 = alloc_expression(expr->pos, EXPR_SYMBOL);
+ e0->symbol = a;
+ e0->ctype = &lazy_ptr_ctype;
+
+ e1 = alloc_expression(expr->pos, EXPR_PREOP);
+ e1->unop = e0;
+ e1->op = '*';
+ e1->ctype = expr->base->ctype; /* XXX */
+
+ e2 = alloc_expression(expr->pos, EXPR_ASSIGNMENT);
+ e2->left = e1;
+ e2->right = expr->base;
+ e2->op = '=';
+ e2->ctype = expr->base->ctype;
+
+ if (expr->r_bitpos) {
+ e3 = alloc_expression(expr->pos, EXPR_BINOP);
+ e3->op = '+';
+ e3->left = e0;
+ e3->right = alloc_const_expression(expr->pos,
+ bits_to_bytes(expr->r_bitpos));
+ e3->ctype = &lazy_ptr_ctype;
+ } else {
+ e3 = e0;
+ }
+
+ e4 = alloc_expression(expr->pos, EXPR_COMMA);
+ e4->left = e2;
+ e4->right = e3;
+ e4->ctype = &lazy_ptr_ctype;
+
+ expr->unop = e4;
+ expr->type = EXPR_PREOP;
+ expr->op = '*';
+ }
+ case SYM_FN:
+ if (expr->op != '*' || expr->type != EXPR_PREOP) {
+ expression_error(expr, "strange non-value function or array");
+ return &bad_ctype;
+ }
+ *expr = *expr->unop;
+ ctype = create_pointer(expr, ctype, 1);
+ expr->ctype = ctype;
+ default:
+ /* nothing */;
+ }
+ return ctype;
+}
+
+static struct symbol *evaluate_addressof(struct expression *expr)
+{
+ struct expression *op = expr->unop;
+ struct symbol *ctype;
+
+ if (op->op != '*' || op->type != EXPR_PREOP) {
+ expression_error(expr, "not addressable");
+ return NULL;
+ }
+ ctype = op->ctype;
+ *expr = *op->unop;
+
+ if (expr->type == EXPR_SYMBOL) {
+ struct symbol *sym = expr->symbol;
+ sym->ctype.modifiers |= MOD_ADDRESSABLE;
+ }
+
+ /*
+ * symbol expression evaluation is lazy about the type
+ * of the sub-expression, so we may have to generate
+ * the type here if so..
+ */
+ if (expr->ctype == &lazy_ptr_ctype) {
+ ctype = create_pointer(expr, ctype, 0);
+ expr->ctype = ctype;
+ }
+ return expr->ctype;
+}
+
+
+static struct symbol *evaluate_dereference(struct expression *expr)
+{
+ struct expression *op = expr->unop;
+ struct symbol *ctype = op->ctype, *node, *target;
+
+ /* Simplify: *&(expr) => (expr) */
+ if (op->type == EXPR_PREOP && op->op == '&') {
+ *expr = *op->unop;
+ expr->flags = CEF_NONE;
+ return expr->ctype;
+ }
+
+ examine_symbol_type(ctype);
+
+ /* Dereferencing a node drops all the node information. */
+ if (ctype->type == SYM_NODE)
+ ctype = ctype->ctype.base_type;
+
+ node = alloc_symbol(expr->pos, SYM_NODE);
+ target = ctype->ctype.base_type;
+
+ switch (ctype->type) {
+ default:
+ expression_error(expr, "cannot dereference this type");
+ return NULL;
+ case SYM_PTR:
+ node->ctype.modifiers = target->ctype.modifiers & MOD_SPECIFIER;
+ merge_type(node, ctype);
+ break;
+
+ case SYM_ARRAY:
+ if (!lvalue_expression(op)) {
+ expression_error(op, "non-lvalue array??");
+ return NULL;
+ }
+
+ /* Do the implied "addressof" on the array */
+ *op = *op->unop;
+
+ /*
+ * When an array is dereferenced, we need to pick
+ * up the attributes of the original node too..
+ */
+ merge_type(node, op->ctype);
+ merge_type(node, ctype);
+ break;
+ }
+
+ node->bit_size = target->bit_size;
+ node->array_size = target->array_size;
+
+ expr->ctype = node;
+ return node;
+}
+
+/*
+ * Unary post-ops: x++ and x--
+ */
+static struct symbol *evaluate_postop(struct expression *expr)
+{
+ struct expression *op = expr->unop;
+ struct symbol *ctype = op->ctype;
+ int class = classify_type(ctype, &ctype);
+ int multiply = 0;
+
+ if (!class || class & TYPE_COMPOUND) {
+ expression_error(expr, "need scalar for ++/--");
+ return NULL;
+ }
+ if (!lvalue_expression(expr->unop)) {
+ expression_error(expr, "need lvalue expression for ++/--");
+ return NULL;
+ }
+
+ if ((class & TYPE_RESTRICT) && restricted_unop(expr->op, &ctype))
+ unrestrict(expr, class, &ctype);
+
+ if (class & TYPE_NUM) {
+ multiply = 1;
+ } else if (class == TYPE_PTR) {
+ struct symbol *target = examine_pointer_target(ctype);
+ if (!is_function(target))
+ multiply = bits_to_bytes(target->bit_size);
+ }
+
+ if (multiply) {
+ evaluate_assign_to(op, op->ctype);
+ expr->op_value = multiply;
+ expr->ctype = ctype;
+ return ctype;
+ }
+
+ expression_error(expr, "bad argument type for ++/--");
+ return NULL;
+}
+
+static struct symbol *evaluate_sign(struct expression *expr)
+{
+ struct symbol *ctype = expr->unop->ctype;
+ int class = classify_type(ctype, &ctype);
+ unsigned char flags = expr->unop->flags & ~CEF_CONST_MASK;
+
+ /* should be an arithmetic type */
+ if (!(class & TYPE_NUM))
+ return bad_expr_type(expr);
+ if (class & TYPE_RESTRICT)
+ goto Restr;
+Normal:
+ if (!(class & TYPE_FLOAT)) {
+ ctype = integer_promotion(ctype);
+ expr->unop = cast_to(expr->unop, ctype);
+ } else if (expr->op != '~') {
+ /* no conversions needed */
+ } else {
+ return bad_expr_type(expr);
+ }
+ if (expr->op == '+')
+ *expr = *expr->unop;
+ expr->flags = flags;
+ expr->ctype = ctype;
+ return ctype;
+Restr:
+ if (restricted_unop(expr->op, &ctype))
+ unrestrict(expr, class, &ctype);
+ goto Normal;
+}
+
+static struct symbol *evaluate_preop(struct expression *expr)
+{
+ struct symbol *ctype = expr->unop->ctype;
+
+ switch (expr->op) {
+ case '(':
+ *expr = *expr->unop;
+ return ctype;
+
+ case '+':
+ case '-':
+ case '~':
+ return evaluate_sign(expr);
+
+ case '*':
+ return evaluate_dereference(expr);
+
+ case '&':
+ return evaluate_addressof(expr);
+
+ case SPECIAL_INCREMENT:
+ case SPECIAL_DECREMENT:
+ /*
+ * From a type evaluation standpoint the preops are
+ * the same as the postops
+ */
+ return evaluate_postop(expr);
+
+ case '!':
+ expr->flags = expr->unop->flags & ~CEF_CONST_MASK;
+ /*
+ * A logical negation never yields an address constant
+ * [6.6(9)].
+ */
+ expr->flags &= ~CEF_ADDR;
+
+ if (is_safe_type(ctype))
+ warning(expr->pos, "testing a 'safe expression'");
+ if (is_float_type(ctype)) {
+ struct expression *arg = expr->unop;
+ expr->type = EXPR_COMPARE;
+ expr->op = SPECIAL_EQUAL;
+ expr->left = arg;
+ expr->right = alloc_expression(expr->pos, EXPR_FVALUE);
+ expr->right->ctype = ctype;
+ expr->right->fvalue = 0;
+ } else if (is_fouled_type(ctype)) {
+ warning(expr->pos, "%s degrades to integer",
+ show_typename(ctype->ctype.base_type));
+ }
+ /* the result is int [6.5.3.3(5)]*/
+ ctype = &int_ctype;
+ break;
+
+ default:
+ break;
+ }
+ expr->ctype = ctype;
+ return ctype;
+}
+
+static struct symbol *find_identifier(struct ident *ident, struct symbol_list *_list, int *offset)
+{
+ struct ptr_list *head = (struct ptr_list *)_list;
+ struct ptr_list *list = head;
+
+ if (!head)
+ return NULL;
+ do {
+ int i;
+ for (i = 0; i < list->nr; i++) {
+ struct symbol *sym = (struct symbol *) list->list[i];
+ if (sym->ident) {
+ if (sym->ident != ident)
+ continue;
+ *offset = sym->offset;
+ return sym;
+ } else {
+ struct symbol *ctype = sym->ctype.base_type;
+ struct symbol *sub;
+ if (!ctype)
+ continue;
+ if (ctype->type != SYM_UNION && ctype->type != SYM_STRUCT)
+ continue;
+ sub = find_identifier(ident, ctype->symbol_list, offset);
+ if (!sub)
+ continue;
+ *offset += sym->offset;
+ return sub;
+ }
+ }
+ } while ((list = list->next) != head);
+ return NULL;
+}
+
+static struct expression *evaluate_offset(struct expression *expr, unsigned long offset)
+{
+ struct expression *add;
+
+ /*
+ * Create a new add-expression
+ *
+ * NOTE! Even if we just add zero, we need a new node
+ * for the member pointer, since it has a different
+ * type than the original pointer. We could make that
+ * be just a cast, but the fact is, a node is a node,
+ * so we might as well just do the "add zero" here.
+ */
+ add = alloc_expression(expr->pos, EXPR_BINOP);
+ add->op = '+';
+ add->left = expr;
+ add->right = alloc_expression(expr->pos, EXPR_VALUE);
+ add->right->ctype = &int_ctype;
+ add->right->value = offset;
+
+ /*
+ * The ctype of the pointer will be lazily evaluated if
+ * we ever take the address of this member dereference..
+ */
+ add->ctype = &lazy_ptr_ctype;
+ /*
+ * The resulting address of a member access through an address
+ * constant is an address constant again [6.6(9)].
+ */
+ add->flags = expr->flags;
+
+ return add;
+}
+
+/* structure/union dereference */
+static struct symbol *evaluate_member_dereference(struct expression *expr)
+{
+ int offset;
+ struct symbol *ctype, *member;
+ struct expression *deref = expr->deref, *add;
+ struct ident *ident = expr->member;
+ unsigned int mod;
+ int address_space;
+
+ if (!evaluate_expression(deref))
+ return NULL;
+ if (!ident) {
+ expression_error(expr, "bad member name");
+ return NULL;
+ }
+
+ ctype = deref->ctype;
+ examine_symbol_type(ctype);
+ address_space = ctype->ctype.as;
+ mod = ctype->ctype.modifiers;
+ if (ctype->type == SYM_NODE) {
+ ctype = ctype->ctype.base_type;
+ address_space |= ctype->ctype.as;
+ mod |= ctype->ctype.modifiers;
+ }
+ if (!ctype || (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION)) {
+ expression_error(expr, "expected structure or union");
+ return NULL;
+ }
+ offset = 0;
+ member = find_identifier(ident, ctype->symbol_list, &offset);
+ if (!member) {
+ const char *type = ctype->type == SYM_STRUCT ? "struct" : "union";
+ const char *name = "<unnamed>";
+ int namelen = 9;
+ if (ctype->ident) {
+ name = ctype->ident->name;
+ namelen = ctype->ident->len;
+ }
+ if (ctype->symbol_list)
+ expression_error(expr, "no member '%s' in %s %.*s",
+ show_ident(ident), type, namelen, name);
+ else
+ expression_error(expr, "using member '%s' in "
+ "incomplete %s %.*s", show_ident(ident),
+ type, namelen, name);
+ return NULL;
+ }
+
+ /*
+ * The member needs to take on the address space and modifiers of
+ * the "parent" type.
+ */
+ member = convert_to_as_mod(member, address_space, mod);
+ ctype = get_base_type(member);
+
+ if (!lvalue_expression(deref)) {
+ if (deref->type != EXPR_SLICE) {
+ expr->base = deref;
+ expr->r_bitpos = 0;
+ } else {
+ expr->base = deref->base;
+ expr->r_bitpos = deref->r_bitpos;
+ }
+ expr->r_bitpos += bytes_to_bits(offset);
+ expr->type = EXPR_SLICE;
+ expr->r_nrbits = member->bit_size;
+ expr->r_bitpos += member->bit_offset;
+ expr->ctype = member;
+ return member;
+ }
+
+ deref = deref->unop;
+ expr->deref = deref;
+
+ add = evaluate_offset(deref, offset);
+ expr->type = EXPR_PREOP;
+ expr->op = '*';
+ expr->unop = add;
+
+ expr->ctype = member;
+ return member;
+}
+
+static int is_promoted(struct expression *expr)
+{
+ while (1) {
+ switch (expr->type) {
+ case EXPR_BINOP:
+ case EXPR_SELECT:
+ case EXPR_CONDITIONAL:
+ return 1;
+ case EXPR_COMMA:
+ expr = expr->right;
+ continue;
+ case EXPR_PREOP:
+ switch (expr->op) {
+ case '(':
+ expr = expr->unop;
+ continue;
+ case '+':
+ case '-':
+ case '~':
+ return 1;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+ }
+}
+
+
+static struct symbol *evaluate_cast(struct expression *);
+
+static struct symbol *evaluate_type_information(struct expression *expr)
+{
+ struct symbol *sym = expr->cast_type;
+ if (!sym) {
+ sym = evaluate_expression(expr->cast_expression);
+ if (!sym)
+ return NULL;
+ /*
+ * Expressions of restricted types will possibly get
+ * promoted - check that here
+ */
+ if (is_restricted_type(sym)) {
+ if (sym->bit_size < bits_in_int && is_promoted(expr))
+ sym = &int_ctype;
+ } else if (is_fouled_type(sym)) {
+ sym = &int_ctype;
+ }
+ }
+ examine_symbol_type(sym);
+ if (is_bitfield_type(sym)) {
+ expression_error(expr, "trying to examine bitfield type");
+ return NULL;
+ }
+ return sym;
+}
+
+static struct symbol *evaluate_sizeof(struct expression *expr)
+{
+ struct symbol *type;
+ int size;
+
+ type = evaluate_type_information(expr);
+ if (!type)
+ return NULL;
+
+ size = type->bit_size;
+
+ if (size < 0 && is_void_type(type)) {
+ if (Wpointer_arith)
+ warning(expr->pos, "expression using sizeof(void)");
+ size = bits_in_char;
+ }
+
+ if (size == 1 && is_bool_type(type)) {
+ if (Wsizeof_bool)
+ warning(expr->pos, "expression using sizeof bool");
+ size = bits_in_char;
+ }
+
+ if (is_function(type->ctype.base_type)) {
+ if (Wpointer_arith)
+ warning(expr->pos, "expression using sizeof on a function");
+ size = bits_in_char;
+ }
+
+ if ((size < 0) || (size & (bits_in_char - 1)))
+ expression_error(expr, "cannot size expression");
+
+ expr->type = EXPR_VALUE;
+ expr->value = bits_to_bytes(size);
+ expr->taint = 0;
+ expr->ctype = size_t_ctype;
+ return size_t_ctype;
+}
+
+static struct symbol *evaluate_ptrsizeof(struct expression *expr)
+{
+ struct symbol *type;
+ int size;
+
+ type = evaluate_type_information(expr);
+ if (!type)
+ return NULL;
+
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ if (!type)
+ return NULL;
+ switch (type->type) {
+ case SYM_ARRAY:
+ break;
+ case SYM_PTR:
+ type = get_base_type(type);
+ if (type)
+ break;
+ default:
+ expression_error(expr, "expected pointer expression");
+ return NULL;
+ }
+ size = type->bit_size;
+ if (size & (bits_in_char-1))
+ size = 0;
+ expr->type = EXPR_VALUE;
+ expr->value = bits_to_bytes(size);
+ expr->taint = 0;
+ expr->ctype = size_t_ctype;
+ return size_t_ctype;
+}
+
+static struct symbol *evaluate_alignof(struct expression *expr)
+{
+ struct symbol *type;
+
+ type = evaluate_type_information(expr);
+ if (!type)
+ return NULL;
+
+ expr->type = EXPR_VALUE;
+ expr->value = type->ctype.alignment;
+ expr->taint = 0;
+ expr->ctype = size_t_ctype;
+ return size_t_ctype;
+}
+
+static int evaluate_arguments(struct symbol *fn, struct expression_list *head)
+{
+ struct expression *expr;
+ struct symbol_list *argument_types = fn->arguments;
+ struct symbol *argtype;
+ int i = 1;
+
+ PREPARE_PTR_LIST(argument_types, argtype);
+ FOR_EACH_PTR (head, expr) {
+ struct expression **p = THIS_ADDRESS(expr);
+ struct symbol *ctype, *target;
+ ctype = evaluate_expression(expr);
+
+ if (!ctype)
+ return 0;
+
+ target = argtype;
+ if (!target) {
+ struct symbol *type;
+ int class = classify_type(ctype, &type);
+ if (is_int(class)) {
+ *p = cast_to(expr, integer_promotion(type));
+ } else if (class & TYPE_FLOAT) {
+ unsigned long mod = type->ctype.modifiers;
+ if (!(mod & (MOD_LONG_ALL)))
+ *p = cast_to(expr, &double_ctype);
+ } else if (class & TYPE_PTR) {
+ if (expr->ctype == &null_ctype)
+ *p = cast_to(expr, &ptr_ctype);
+ else
+ degenerate(expr);
+ }
+ } else if (!target->forced_arg){
+ static char where[30];
+ examine_symbol_type(target);
+ sprintf(where, "argument %d", i);
+ compatible_argument_type(expr, target, p, where);
+ }
+
+ i++;
+ NEXT_PTR_LIST(argtype);
+ } END_FOR_EACH_PTR(expr);
+ FINISH_PTR_LIST(argtype);
+ return 1;
+}
+
+static void convert_index(struct expression *e)
+{
+ struct expression *child = e->idx_expression;
+ unsigned from = e->idx_from;
+ unsigned to = e->idx_to + 1;
+ e->type = EXPR_POS;
+ e->init_offset = from * bits_to_bytes(e->ctype->bit_size);
+ e->init_nr = to - from;
+ e->init_expr = child;
+}
+
+static void convert_ident(struct expression *e)
+{
+ struct expression *child = e->ident_expression;
+ int offset = e->offset;
+
+ e->type = EXPR_POS;
+ e->init_offset = offset;
+ e->init_nr = 1;
+ e->init_expr = child;
+}
+
+static void convert_designators(struct expression *e)
+{
+ while (e) {
+ if (e->type == EXPR_INDEX)
+ convert_index(e);
+ else if (e->type == EXPR_IDENTIFIER)
+ convert_ident(e);
+ else
+ break;
+ e = e->init_expr;
+ }
+}
+
+static void excess(struct expression *e, const char *s)
+{
+ warning(e->pos, "excessive elements in %s initializer", s);
+}
+
+/*
+ * implicit designator for the first element
+ */
+static struct expression *first_subobject(struct symbol *ctype, int class,
+ struct expression **v)
+{
+ struct expression *e = *v, *new;
+
+ if (ctype->type == SYM_NODE)
+ ctype = ctype->ctype.base_type;
+
+ if (class & TYPE_PTR) { /* array */
+ if (!ctype->bit_size)
+ return NULL;
+ new = alloc_expression(e->pos, EXPR_INDEX);
+ new->idx_expression = e;
+ new->ctype = ctype->ctype.base_type;
+ } else {
+ struct symbol *field, *p;
+ PREPARE_PTR_LIST(ctype->symbol_list, p);
+ while (p && !p->ident && is_bitfield_type(p))
+ NEXT_PTR_LIST(p);
+ field = p;
+ FINISH_PTR_LIST(p);
+ if (!field)
+ return NULL;
+ new = alloc_expression(e->pos, EXPR_IDENTIFIER);
+ new->ident_expression = e;
+ new->field = new->ctype = field;
+ new->offset = field->offset;
+ }
+ *v = new;
+ return new;
+}
+
+/*
+ * sanity-check explicit designators; return the innermost one or NULL
+ * in case of error. Assign types.
+ */
+static struct expression *check_designators(struct expression *e,
+ struct symbol *ctype)
+{
+ struct expression *last = NULL;
+ const char *err;
+ while (1) {
+ if (ctype->type == SYM_NODE)
+ ctype = ctype->ctype.base_type;
+ if (e->type == EXPR_INDEX) {
+ struct symbol *type;
+ if (ctype->type != SYM_ARRAY) {
+ err = "array index in non-array";
+ break;
+ }
+ type = ctype->ctype.base_type;
+ if (ctype->bit_size >= 0 && type->bit_size >= 0) {
+ unsigned offset = array_element_offset(type->bit_size, e->idx_to);
+ if (offset >= ctype->bit_size) {
+ err = "index out of bounds in";
+ break;
+ }
+ }
+ e->ctype = ctype = type;
+ ctype = type;
+ last = e;
+ if (!e->idx_expression) {
+ err = "invalid";
+ break;
+ }
+ e = e->idx_expression;
+ } else if (e->type == EXPR_IDENTIFIER) {
+ int offset = 0;
+ if (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION) {
+ err = "field name not in struct or union";
+ break;
+ }
+ ctype = find_identifier(e->expr_ident, ctype->symbol_list, &offset);
+ if (!ctype) {
+ err = "unknown field name in";
+ break;
+ }
+ e->offset = offset;
+ e->field = e->ctype = ctype;
+ last = e;
+ if (!e->ident_expression) {
+ err = "invalid";
+ break;
+ }
+ e = e->ident_expression;
+ } else if (e->type == EXPR_POS) {
+ err = "internal front-end error: EXPR_POS in";
+ break;
+ } else
+ return last;
+ }
+ expression_error(e, "%s initializer", err);
+ return NULL;
+}
+
+/*
+ * choose the next subobject to initialize.
+ *
+ * Get designators for next element, switch old ones to EXPR_POS.
+ * Return the resulting expression or NULL if we'd run out of subobjects.
+ * The innermost designator is returned in *v. Designators in old
+ * are assumed to be already sanity-checked.
+ */
+static struct expression *next_designators(struct expression *old,
+ struct symbol *ctype,
+ struct expression *e, struct expression **v)
+{
+ struct expression *new = NULL;
+
+ if (!old)
+ return NULL;
+ if (old->type == EXPR_INDEX) {
+ struct expression *copy;
+ unsigned n;
+
+ copy = next_designators(old->idx_expression,
+ old->ctype, e, v);
+ if (!copy) {
+ n = old->idx_to + 1;
+ if (array_element_offset(old->ctype->bit_size, n) == ctype->bit_size) {
+ convert_index(old);
+ return NULL;
+ }
+ copy = e;
+ *v = new = alloc_expression(e->pos, EXPR_INDEX);
+ } else {
+ n = old->idx_to;
+ new = alloc_expression(e->pos, EXPR_INDEX);
+ }
+
+ new->idx_from = new->idx_to = n;
+ new->idx_expression = copy;
+ new->ctype = old->ctype;
+ convert_index(old);
+ } else if (old->type == EXPR_IDENTIFIER) {
+ struct expression *copy;
+ struct symbol *field;
+ int offset = 0;
+
+ copy = next_designators(old->ident_expression,
+ old->ctype, e, v);
+ if (!copy) {
+ field = old->field->next_subobject;
+ if (!field) {
+ convert_ident(old);
+ return NULL;
+ }
+ copy = e;
+ *v = new = alloc_expression(e->pos, EXPR_IDENTIFIER);
+ /*
+ * We can't necessarily trust "field->offset",
+ * because the field might be in an anonymous
+ * union, and the field offset is then the offset
+ * within that union.
+ *
+ * The "old->offset - old->field->offset"
+ * would be the offset of such an anonymous
+ * union.
+ */
+ offset = old->offset - old->field->offset;
+ } else {
+ field = old->field;
+ new = alloc_expression(e->pos, EXPR_IDENTIFIER);
+ }
+
+ new->field = field;
+ new->expr_ident = field->ident;
+ new->ident_expression = copy;
+ new->ctype = field;
+ new->offset = field->offset + offset;
+ convert_ident(old);
+ }
+ return new;
+}
+
+static int handle_initializer(struct expression **ep, int nested,
+ int class, struct symbol *ctype, unsigned long mods);
+
+/*
+ * deal with traversing subobjects [6.7.8(17,18,20)]
+ */
+static void handle_list_initializer(struct expression *expr,
+ int class, struct symbol *ctype, unsigned long mods)
+{
+ struct expression *e, *last = NULL, *top = NULL, *next;
+ int jumped = 0;
+
+ FOR_EACH_PTR(expr->expr_list, e) {
+ struct expression **v;
+ struct symbol *type;
+ int lclass;
+
+ if (e->type != EXPR_INDEX && e->type != EXPR_IDENTIFIER) {
+ struct symbol *struct_sym;
+ if (!top) {
+ top = e;
+ last = first_subobject(ctype, class, &top);
+ } else {
+ last = next_designators(last, ctype, e, &top);
+ }
+ if (!last) {
+ excess(e, class & TYPE_PTR ? "array" :
+ "struct or union");
+ DELETE_CURRENT_PTR(e);
+ continue;
+ }
+ struct_sym = ctype->type == SYM_NODE ? ctype->ctype.base_type : ctype;
+ if (Wdesignated_init && struct_sym->designated_init)
+ warning(e->pos, "%s%.*s%spositional init of field in %s %s, declared with attribute designated_init",
+ ctype->ident ? "in initializer for " : "",
+ ctype->ident ? ctype->ident->len : 0,
+ ctype->ident ? ctype->ident->name : "",
+ ctype->ident ? ": " : "",
+ get_type_name(struct_sym->type),
+ show_ident(struct_sym->ident));
+ if (jumped) {
+ warning(e->pos, "advancing past deep designator");
+ jumped = 0;
+ }
+ REPLACE_CURRENT_PTR(e, last);
+ } else {
+ next = check_designators(e, ctype);
+ if (!next) {
+ DELETE_CURRENT_PTR(e);
+ continue;
+ }
+ top = next;
+ /* deeper than one designator? */
+ jumped = top != e;
+ convert_designators(last);
+ last = e;
+ }
+
+found:
+ lclass = classify_type(top->ctype, &type);
+ if (top->type == EXPR_INDEX)
+ v = &top->idx_expression;
+ else
+ v = &top->ident_expression;
+
+ mods |= ctype->ctype.modifiers & MOD_STORAGE;
+ if (handle_initializer(v, 1, lclass, top->ctype, mods))
+ continue;
+
+ if (!(lclass & TYPE_COMPOUND)) {
+ warning(e->pos, "bogus scalar initializer");
+ DELETE_CURRENT_PTR(e);
+ continue;
+ }
+
+ next = first_subobject(type, lclass, v);
+ if (next) {
+ warning(e->pos, "missing braces around initializer");
+ top = next;
+ goto found;
+ }
+
+ DELETE_CURRENT_PTR(e);
+ excess(e, lclass & TYPE_PTR ? "array" : "struct or union");
+
+ } END_FOR_EACH_PTR(e);
+
+ convert_designators(last);
+ expr->ctype = ctype;
+}
+
+static int is_string_literal(struct expression **v)
+{
+ struct expression *e = *v;
+ while (e && e->type == EXPR_PREOP && e->op == '(')
+ e = e->unop;
+ if (!e || e->type != EXPR_STRING)
+ return 0;
+ if (e != *v && Wparen_string)
+ warning(e->pos,
+ "array initialized from parenthesized string constant");
+ *v = e;
+ return 1;
+}
+
+/*
+ * We want a normal expression, possibly in one layer of braces. Warn
+ * if the latter happens inside a list (it's legal, but likely to be
+ * an effect of screwup). In case of anything not legal, we are definitely
+ * having an effect of screwup, so just fail and let the caller warn.
+ */
+static struct expression *handle_scalar(struct expression *e, int nested)
+{
+ struct expression *v = NULL, *p;
+ int count = 0;
+
+ /* normal case */
+ if (e->type != EXPR_INITIALIZER)
+ return e;
+
+ FOR_EACH_PTR(e->expr_list, p) {
+ if (!v)
+ v = p;
+ count++;
+ } END_FOR_EACH_PTR(p);
+ if (count != 1)
+ return NULL;
+ switch(v->type) {
+ case EXPR_INITIALIZER:
+ case EXPR_INDEX:
+ case EXPR_IDENTIFIER:
+ return NULL;
+ default:
+ break;
+ }
+ if (nested)
+ warning(e->pos, "braces around scalar initializer");
+ return v;
+}
+
+/*
+ * deal with the cases that don't care about subobjects:
+ * scalar <- assignment expression, possibly in braces [6.7.8(11)]
+ * character array <- string literal, possibly in braces [6.7.8(14)]
+ * struct or union <- assignment expression of compatible type [6.7.8(13)]
+ * compound type <- initializer list in braces [6.7.8(16)]
+ * The last one punts to handle_list_initializer() which, in turn will call
+ * us for individual elements of the list.
+ *
+ * We do not handle 6.7.8(15) (wide char array <- wide string literal) for
+ * the lack of support of wide char stuff in general.
+ *
+ * One note: we need to take care not to evaluate a string literal until
+ * we know that we *will* handle it right here. Otherwise we would screw
+ * the cases like struct { struct {char s[10]; ...} ...} initialized with
+ * { "string", ...} - we need to preserve that string literal recognizable
+ * until we dig into the inner struct.
+ */
+static int handle_initializer(struct expression **ep, int nested,
+ int class, struct symbol *ctype, unsigned long mods)
+{
+ int is_string = is_string_type(ctype);
+ struct expression *e = *ep, *p;
+ struct symbol *type;
+
+ if (!e)
+ return 0;
+
+ /* scalar */
+ if (!(class & TYPE_COMPOUND)) {
+ e = handle_scalar(e, nested);
+ if (!e)
+ return 0;
+ *ep = e;
+ if (!evaluate_expression(e))
+ return 1;
+ compatible_assignment_types(e, ctype, ep, "initializer");
+ /*
+ * Initializers for static storage duration objects
+ * shall be constant expressions or a string literal [6.7.8(4)].
+ */
+ mods |= ctype->ctype.modifiers;
+ mods &= (MOD_TOPLEVEL | MOD_STATIC);
+ if (mods && !(e->flags & (CEF_ACE | CEF_ADDR)))
+ if (Wconstexpr_not_const)
+ warning(e->pos, "non-constant initializer for static object");
+
+ return 1;
+ }
+
+ /*
+ * sublist; either a string, or we dig in; the latter will deal with
+ * pathologies, so we don't need anything fancy here.
+ */
+ if (e->type == EXPR_INITIALIZER) {
+ if (is_string) {
+ struct expression *v = NULL;
+ int count = 0;
+
+ FOR_EACH_PTR(e->expr_list, p) {
+ if (!v)
+ v = p;
+ count++;
+ } END_FOR_EACH_PTR(p);
+ if (count == 1 && is_string_literal(&v)) {
+ *ep = e = v;
+ goto String;
+ }
+ }
+ handle_list_initializer(e, class, ctype, mods);
+ return 1;
+ }
+
+ /* string */
+ if (is_string_literal(&e)) {
+ /* either we are doing array of char, or we'll have to dig in */
+ if (is_string) {
+ *ep = e;
+ goto String;
+ }
+ return 0;
+ }
+ /* struct or union can be initialized by compatible */
+ if (class != TYPE_COMPOUND)
+ return 0;
+ type = evaluate_expression(e);
+ if (!type)
+ return 0;
+ if (ctype->type == SYM_NODE)
+ ctype = ctype->ctype.base_type;
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ if (ctype == type)
+ return 1;
+ return 0;
+
+String:
+ p = alloc_expression(e->pos, EXPR_STRING);
+ *p = *e;
+ type = evaluate_expression(p);
+ if (ctype->bit_size != -1) {
+ if (ctype->bit_size + bits_in_char < type->bit_size)
+ warning(e->pos,
+ "too long initializer-string for array of char");
+ else if (Winit_cstring && ctype->bit_size + bits_in_char == type->bit_size) {
+ warning(e->pos,
+ "too long initializer-string for array of char(no space for nul char)");
+ }
+ }
+ *ep = p;
+ return 1;
+}
+
+static void evaluate_initializer(struct symbol *ctype, struct expression **ep)
+{
+ struct symbol *type;
+ int class = classify_type(ctype, &type);
+ if (!handle_initializer(ep, 0, class, ctype, 0))
+ expression_error(*ep, "invalid initializer");
+}
+
+static struct symbol *cast_to_bool(struct expression *expr)
+{
+ struct expression *old = expr->cast_expression;
+ struct expression *zero;
+ struct symbol *otype;
+ int oclass = classify_type(degenerate(old), &otype);
+ struct symbol *ctype;
+
+ if (oclass & TYPE_COMPOUND)
+ return NULL;
+
+ zero = alloc_const_expression(expr->pos, 0);
+ expr->op = SPECIAL_NOTEQUAL;
+ ctype = usual_conversions(expr->op, old, zero,
+ oclass, TYPE_NUM, otype, zero->ctype);
+ expr->type = EXPR_COMPARE;
+ expr->left = cast_to(old, ctype);
+ expr->right = cast_to(zero, ctype);
+
+ return expr->ctype;
+}
+
+static int cast_flags(struct expression *expr, struct expression *old)
+{
+ struct symbol *t;
+ int class;
+ int flags = CEF_NONE;
+
+ class = classify_type(expr->ctype, &t);
+ if (class & TYPE_NUM) {
+ flags = old->flags & ~CEF_CONST_MASK;
+ /*
+ * Casts to numeric types never result in address
+ * constants [6.6(9)].
+ */
+ flags &= ~CEF_ADDR;
+
+ /*
+ * As an extension, treat address constants cast to
+ * integer type as an arithmetic constant.
+ */
+ if (old->flags & CEF_ADDR)
+ flags = CEF_ACE;
+
+ /*
+ * Cast to float type -> not an integer constant
+ * expression [6.6(6)].
+ */
+ if (class & TYPE_FLOAT)
+ flags &= ~CEF_CLR_ICE;
+ /*
+ * Casts of float literals to integer type results in
+ * a constant integer expression [6.6(6)].
+ */
+ else if (old->flags & CEF_FLOAT)
+ flags = CEF_SET_ICE;
+ } else if (class & TYPE_PTR) {
+ /*
+ * Casts of integer literals to pointer type yield
+ * address constants [6.6(9)].
+ *
+ * As an extension, treat address constants cast to a
+ * different pointer type as address constants again.
+ *
+ * As another extension, treat integer constant
+ * expressions (in contrast to literals) cast to
+ * pointer type as address constants.
+ */
+ if (old->flags & (CEF_ICE | CEF_ADDR))
+ flags = CEF_ADDR;
+ }
+
+ return flags;
+}
+
+static struct symbol *evaluate_cast(struct expression *expr)
+{
+ struct expression *target = expr->cast_expression;
+ struct symbol *ctype;
+ struct symbol *t1, *t2;
+ int class1, class2;
+ int as1 = 0, as2 = 0;
+
+ if (!target)
+ return NULL;
+
+ /*
+ * Special case: a cast can be followed by an
+ * initializer, in which case we need to pass
+ * the type value down to that initializer rather
+ * than trying to evaluate it as an expression
+ *
+ * A more complex case is when the initializer is
+ * dereferenced as part of a post-fix expression.
+ * We need to produce an expression that can be dereferenced.
+ */
+ if (target->type == EXPR_INITIALIZER) {
+ struct symbol *sym = expr->cast_type;
+ struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
+
+ sym->initializer = target;
+ evaluate_symbol(sym);
+
+ addr->ctype = &lazy_ptr_ctype; /* Lazy eval */
+ addr->symbol = sym;
+ if (sym->ctype.modifiers & MOD_TOPLEVEL)
+ addr->flags |= CEF_ADDR;
+
+ expr->type = EXPR_PREOP;
+ expr->op = '*';
+ expr->unop = addr;
+ expr->ctype = sym;
+
+ return sym;
+ }
+
+ ctype = examine_symbol_type(expr->cast_type);
+ expr->ctype = ctype;
+ expr->cast_type = ctype;
+
+ evaluate_expression(target);
+ degenerate(target);
+
+ class1 = classify_type(ctype, &t1);
+
+ expr->flags = cast_flags(expr, target);
+
+ /*
+ * You can always throw a value away by casting to
+ * "void" - that's an implicit "force". Note that
+ * the same is _not_ true of "void *".
+ */
+ if (t1 == &void_ctype)
+ goto out;
+
+ if (class1 & (TYPE_COMPOUND | TYPE_FN))
+ warning(expr->pos, "cast to non-scalar");
+
+ t2 = target->ctype;
+ if (!t2) {
+ expression_error(expr, "cast from unknown type");
+ goto out;
+ }
+ class2 = classify_type(t2, &t2);
+
+ if (class2 & TYPE_COMPOUND)
+ warning(expr->pos, "cast from non-scalar");
+
+ if (expr->type == EXPR_FORCE_CAST)
+ goto out;
+
+ /* allowed cast unfouls */
+ if (class2 & TYPE_FOULED)
+ t2 = unfoul(t2);
+
+ if (t1 != t2) {
+ if ((class1 & TYPE_RESTRICT) && restricted_value(target, t1))
+ warning(expr->pos, "cast to %s",
+ show_typename(t1));
+ if (class2 & TYPE_RESTRICT) {
+ if (t1 == &bool_ctype) {
+ if (class2 & TYPE_FOULED)
+ warning(expr->pos, "%s degrades to integer",
+ show_typename(t2));
+ } else {
+ warning(expr->pos, "cast from %s",
+ show_typename(t2));
+ }
+ }
+ }
+
+ if (t1 == &ulong_ctype)
+ as1 = -1;
+ else if (class1 == TYPE_PTR) {
+ examine_pointer_target(t1);
+ as1 = t1->ctype.as;
+ }
+
+ if (t2 == &ulong_ctype)
+ as2 = -1;
+ else if (class2 == TYPE_PTR) {
+ examine_pointer_target(t2);
+ as2 = t2->ctype.as;
+ }
+
+ if (!as1 && as2 > 0)
+ warning(expr->pos, "cast removes address space of expression");
+ if (as1 > 0 && as2 > 0 && as1 != as2)
+ warning(expr->pos, "cast between address spaces (<asn:%d>-><asn:%d>)", as2, as1);
+ if (as1 > 0 && !as2 &&
+ !is_null_pointer_constant(target) && Wcast_to_as)
+ warning(expr->pos,
+ "cast adds address space to expression (<asn:%d>)", as1);
+
+ if (!(t1->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR &&
+ !as1 && (target->flags & CEF_ICE)) {
+ if (t1->ctype.base_type == &void_ctype) {
+ if (is_zero_constant(target)) {
+ /* NULL */
+ expr->type = EXPR_VALUE;
+ expr->ctype = &null_ctype;
+ expr->value = 0;
+ return expr->ctype;
+ }
+ }
+ }
+
+ if (t1 == &bool_ctype)
+ cast_to_bool(expr);
+
+out:
+ return ctype;
+}
+
+/*
+ * Evaluate a call expression with a symbol. This
+ * should expand inline functions, and evaluate
+ * builtins.
+ */
+static int evaluate_symbol_call(struct expression *expr)
+{
+ struct expression *fn = expr->fn;
+ struct symbol *ctype = fn->ctype;
+
+ if (fn->type != EXPR_PREOP)
+ return 0;
+
+ if (ctype->op && ctype->op->evaluate)
+ return ctype->op->evaluate(expr);
+
+ if (ctype->ctype.modifiers & MOD_INLINE) {
+ int ret;
+ struct symbol *curr = current_fn;
+
+ if (ctype->definition)
+ ctype = ctype->definition;
+
+ current_fn = ctype->ctype.base_type;
+
+ ret = inline_function(expr, ctype);
+
+ /* restore the old function */
+ current_fn = curr;
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct symbol *evaluate_call(struct expression *expr)
+{
+ int args, fnargs;
+ struct symbol *ctype, *sym;
+ struct expression *fn = expr->fn;
+ struct expression_list *arglist = expr->args;
+
+ if (!evaluate_expression(fn))
+ return NULL;
+ sym = ctype = fn->ctype;
+ if (ctype->type == SYM_NODE)
+ ctype = ctype->ctype.base_type;
+ if (ctype->type == SYM_PTR)
+ ctype = get_base_type(ctype);
+
+ if (ctype->type != SYM_FN) {
+ struct expression *arg;
+ expression_error(expr, "not a function %s",
+ show_ident(sym->ident));
+ /* do typechecking in arguments */
+ FOR_EACH_PTR (arglist, arg) {
+ evaluate_expression(arg);
+ } END_FOR_EACH_PTR(arg);
+ return NULL;
+ }
+
+ examine_fn_arguments(ctype);
+ if (sym->type == SYM_NODE && fn->type == EXPR_PREOP &&
+ sym->op && sym->op->args) {
+ if (!sym->op->args(expr))
+ return NULL;
+ } else {
+ if (!evaluate_arguments(ctype, arglist))
+ return NULL;
+ args = expression_list_size(expr->args);
+ fnargs = symbol_list_size(ctype->arguments);
+ if (args < fnargs) {
+ expression_error(expr,
+ "not enough arguments for function %s",
+ show_ident(sym->ident));
+ return NULL;
+ }
+ if (args > fnargs && !ctype->variadic)
+ expression_error(expr,
+ "too many arguments for function %s",
+ show_ident(sym->ident));
+ }
+ expr->ctype = ctype->ctype.base_type;
+ if (sym->type == SYM_NODE) {
+ if (evaluate_symbol_call(expr))
+ return expr->ctype;
+ }
+ return expr->ctype;
+}
+
+static struct symbol *evaluate_offsetof(struct expression *expr)
+{
+ struct expression *e = expr->down;
+ struct symbol *ctype = expr->in;
+ int class;
+
+ if (expr->op == '.') {
+ struct symbol *field;
+ int offset = 0;
+ if (!ctype) {
+ expression_error(expr, "expected structure or union");
+ return NULL;
+ }
+ examine_symbol_type(ctype);
+ class = classify_type(ctype, &ctype);
+ if (class != TYPE_COMPOUND) {
+ expression_error(expr, "expected structure or union");
+ return NULL;
+ }
+
+ field = find_identifier(expr->ident, ctype->symbol_list, &offset);
+ if (!field) {
+ expression_error(expr, "unknown member");
+ return NULL;
+ }
+ ctype = field;
+ expr->type = EXPR_VALUE;
+ expr->flags = CEF_SET_ICE;
+ expr->value = offset;
+ expr->taint = 0;
+ expr->ctype = size_t_ctype;
+ } else {
+ if (!ctype) {
+ expression_error(expr, "expected structure or union");
+ return NULL;
+ }
+ examine_symbol_type(ctype);
+ class = classify_type(ctype, &ctype);
+ if (class != (TYPE_COMPOUND | TYPE_PTR)) {
+ expression_error(expr, "expected array");
+ return NULL;
+ }
+ ctype = ctype->ctype.base_type;
+ if (!expr->index) {
+ expr->type = EXPR_VALUE;
+ expr->flags = CEF_SET_ICE;
+ expr->value = 0;
+ expr->taint = 0;
+ expr->ctype = size_t_ctype;
+ } else {
+ struct expression *idx = expr->index, *m;
+ struct symbol *i_type = evaluate_expression(idx);
+ unsigned old_idx_flags;
+ int i_class = classify_type(i_type, &i_type);
+
+ if (!is_int(i_class)) {
+ expression_error(expr, "non-integer index");
+ return NULL;
+ }
+ unrestrict(idx, i_class, &i_type);
+ old_idx_flags = idx->flags;
+ idx = cast_to(idx, size_t_ctype);
+ idx->flags = old_idx_flags;
+ m = alloc_const_expression(expr->pos,
+ bits_to_bytes(ctype->bit_size));
+ m->ctype = size_t_ctype;
+ m->flags = CEF_SET_INT;
+ expr->type = EXPR_BINOP;
+ expr->left = idx;
+ expr->right = m;
+ expr->op = '*';
+ expr->ctype = size_t_ctype;
+ expr->flags = m->flags & idx->flags & ~CEF_CONST_MASK;
+ }
+ }
+ if (e) {
+ struct expression *copy = __alloc_expression(0);
+ *copy = *expr;
+ if (e->type == EXPR_OFFSETOF)
+ e->in = ctype;
+ if (!evaluate_expression(e))
+ return NULL;
+ expr->type = EXPR_BINOP;
+ expr->flags = e->flags & copy->flags & ~CEF_CONST_MASK;
+ expr->op = '+';
+ expr->ctype = size_t_ctype;
+ expr->left = copy;
+ expr->right = e;
+ }
+ return size_t_ctype;
+}
+
+struct symbol *evaluate_expression(struct expression *expr)
+{
+ if (!expr)
+ return NULL;
+ if (expr->ctype)
+ return expr->ctype;
+
+ switch (expr->type) {
+ case EXPR_VALUE:
+ case EXPR_FVALUE:
+ expression_error(expr, "value expression without a type");
+ return NULL;
+ case EXPR_STRING:
+ return evaluate_string(expr);
+ case EXPR_SYMBOL:
+ return evaluate_symbol_expression(expr);
+ case EXPR_BINOP:
+ if (!evaluate_expression(expr->left))
+ return NULL;
+ if (!evaluate_expression(expr->right))
+ return NULL;
+ return evaluate_binop(expr);
+ case EXPR_LOGICAL:
+ return evaluate_logical(expr);
+ case EXPR_COMMA:
+ evaluate_expression(expr->left);
+ if (!evaluate_expression(expr->right))
+ return NULL;
+ return evaluate_comma(expr);
+ case EXPR_COMPARE:
+ if (!evaluate_expression(expr->left))
+ return NULL;
+ if (!evaluate_expression(expr->right))
+ return NULL;
+ return evaluate_compare(expr);
+ case EXPR_ASSIGNMENT:
+ if (!evaluate_expression(expr->left))
+ return NULL;
+ if (!evaluate_expression(expr->right))
+ return NULL;
+ return evaluate_assignment(expr);
+ case EXPR_PREOP:
+ if (!evaluate_expression(expr->unop))
+ return NULL;
+ return evaluate_preop(expr);
+ case EXPR_POSTOP:
+ if (!evaluate_expression(expr->unop))
+ return NULL;
+ return evaluate_postop(expr);
+ case EXPR_CAST:
+ case EXPR_FORCE_CAST:
+ case EXPR_IMPLIED_CAST:
+ return evaluate_cast(expr);
+ case EXPR_SIZEOF:
+ return evaluate_sizeof(expr);
+ case EXPR_PTRSIZEOF:
+ return evaluate_ptrsizeof(expr);
+ case EXPR_ALIGNOF:
+ return evaluate_alignof(expr);
+ case EXPR_DEREF:
+ return evaluate_member_dereference(expr);
+ case EXPR_CALL:
+ return evaluate_call(expr);
+ case EXPR_SELECT:
+ case EXPR_CONDITIONAL:
+ return evaluate_conditional_expression(expr);
+ case EXPR_STATEMENT:
+ expr->ctype = evaluate_statement(expr->statement);
+ return expr->ctype;
+
+ case EXPR_LABEL:
+ expr->ctype = &ptr_ctype;
+ return &ptr_ctype;
+
+ case EXPR_TYPE:
+ /* Evaluate the type of the symbol .. */
+ evaluate_symbol(expr->symbol);
+ /* .. but the type of the _expression_ is a "type" */
+ expr->ctype = &type_ctype;
+ return &type_ctype;
+
+ case EXPR_OFFSETOF:
+ return evaluate_offsetof(expr);
+
+ /* These can not exist as stand-alone expressions */
+ case EXPR_INITIALIZER:
+ case EXPR_IDENTIFIER:
+ case EXPR_INDEX:
+ case EXPR_POS:
+ expression_error(expr, "internal front-end error: initializer in expression");
+ return NULL;
+ case EXPR_SLICE:
+ expression_error(expr, "internal front-end error: SLICE re-evaluated");
+ return NULL;
+ }
+ return NULL;
+}
+
+static void check_duplicates(struct symbol *sym)
+{
+ int declared = 0;
+ struct symbol *next = sym;
+ int initialized = sym->initializer != NULL;
+
+ while ((next = next->same_symbol) != NULL) {
+ const char *typediff;
+ evaluate_symbol(next);
+ if (initialized && next->initializer) {
+ sparse_error(sym->pos, "symbol '%s' has multiple initializers (originally initialized at %s:%d)",
+ show_ident(sym->ident),
+ stream_name(next->pos.stream), next->pos.line);
+ /* Only warn once */
+ initialized = 0;
+ }
+ declared++;
+ typediff = type_difference(&sym->ctype, &next->ctype, 0, 0);
+ if (typediff) {
+ sparse_error(sym->pos, "symbol '%s' redeclared with different type (originally declared at %s:%d) - %s",
+ show_ident(sym->ident),
+ stream_name(next->pos.stream), next->pos.line, typediff);
+ return;
+ }
+ }
+ if (!declared) {
+ unsigned long mod = sym->ctype.modifiers;
+ if (mod & (MOD_STATIC | MOD_REGISTER))
+ return;
+ if (!(mod & MOD_TOPLEVEL))
+ return;
+ if (!Wdecl)
+ return;
+ if (sym->ident == &main_ident)
+ return;
+ warning(sym->pos, "symbol '%s' was not declared. Should it be static?", show_ident(sym->ident));
+ }
+}
+
+static struct symbol *evaluate_symbol(struct symbol *sym)
+{
+ struct symbol *base_type;
+
+ if (!sym)
+ return sym;
+ if (sym->evaluated)
+ return sym;
+ sym->evaluated = 1;
+
+ sym = examine_symbol_type(sym);
+ base_type = get_base_type(sym);
+ if (!base_type)
+ return NULL;
+
+ /* Evaluate the initializers */
+ if (sym->initializer)
+ evaluate_initializer(sym, &sym->initializer);
+
+ /* And finally, evaluate the body of the symbol too */
+ if (base_type->type == SYM_FN) {
+ struct symbol *curr = current_fn;
+
+ if (sym->definition && sym->definition != sym)
+ return evaluate_symbol(sym->definition);
+
+ current_fn = base_type;
+
+ examine_fn_arguments(base_type);
+ if (!base_type->stmt && base_type->inline_stmt)
+ uninline(sym);
+ if (base_type->stmt)
+ evaluate_statement(base_type->stmt);
+
+ current_fn = curr;
+ }
+
+ return base_type;
+}
+
+void evaluate_symbol_list(struct symbol_list *list)
+{
+ struct symbol *sym;
+
+ FOR_EACH_PTR(list, sym) {
+ has_error &= ~ERROR_CURR_PHASE;
+ evaluate_symbol(sym);
+ check_duplicates(sym);
+ } END_FOR_EACH_PTR(sym);
+}
+
+static struct symbol *evaluate_return_expression(struct statement *stmt)
+{
+ struct expression *expr = stmt->expression;
+ struct symbol *fntype;
+
+ evaluate_expression(expr);
+ fntype = current_fn->ctype.base_type;
+ if (!fntype || fntype == &void_ctype) {
+ if (expr && expr->ctype != &void_ctype)
+ expression_error(expr, "return expression in %s function", fntype?"void":"typeless");
+ if (expr && Wreturn_void)
+ warning(stmt->pos, "returning void-valued expression");
+ return NULL;
+ }
+
+ if (!expr) {
+ sparse_error(stmt->pos, "return with no return value");
+ return NULL;
+ }
+ if (!expr->ctype)
+ return NULL;
+ compatible_assignment_types(expr, fntype, &stmt->expression, "return expression");
+ return NULL;
+}
+
+static void evaluate_if_statement(struct statement *stmt)
+{
+ if (!stmt->if_conditional)
+ return;
+
+ evaluate_conditional(stmt->if_conditional, 0);
+ evaluate_statement(stmt->if_true);
+ evaluate_statement(stmt->if_false);
+}
+
+static void evaluate_iterator(struct statement *stmt)
+{
+ evaluate_symbol_list(stmt->iterator_syms);
+ evaluate_conditional(stmt->iterator_pre_condition, 1);
+ evaluate_conditional(stmt->iterator_post_condition,1);
+ evaluate_statement(stmt->iterator_pre_statement);
+ evaluate_statement(stmt->iterator_statement);
+ evaluate_statement(stmt->iterator_post_statement);
+}
+
+static void verify_output_constraint(struct expression *expr, const char *constraint)
+{
+ switch (*constraint) {
+ case '=': /* Assignment */
+ case '+': /* Update */
+ break;
+ default:
+ expression_error(expr, "output constraint is not an assignment constraint (\"%s\")", constraint);
+ }
+}
+
+static void verify_input_constraint(struct expression *expr, const char *constraint)
+{
+ switch (*constraint) {
+ case '=': /* Assignment */
+ case '+': /* Update */
+ expression_error(expr, "input constraint with assignment (\"%s\")", constraint);
+ }
+}
+
+static void evaluate_asm_statement(struct statement *stmt)
+{
+ struct expression *expr;
+ struct symbol *sym;
+ int state;
+
+ expr = stmt->asm_string;
+ if (!expr || expr->type != EXPR_STRING) {
+ sparse_error(stmt->pos, "need constant string for inline asm");
+ return;
+ }
+
+ state = 0;
+ FOR_EACH_PTR(stmt->asm_outputs, expr) {
+ switch (state) {
+ case 0: /* Identifier */
+ state = 1;
+ continue;
+
+ case 1: /* Constraint */
+ state = 2;
+ if (!expr || expr->type != EXPR_STRING) {
+ sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string");
+ *THIS_ADDRESS(expr) = NULL;
+ continue;
+ }
+ verify_output_constraint(expr, expr->string->data);
+ continue;
+
+ case 2: /* Expression */
+ state = 0;
+ if (!evaluate_expression(expr))
+ return;
+ if (!lvalue_expression(expr))
+ warning(expr->pos, "asm output is not an lvalue");
+ evaluate_assign_to(expr, expr->ctype);
+ continue;
+ }
+ } END_FOR_EACH_PTR(expr);
+
+ state = 0;
+ FOR_EACH_PTR(stmt->asm_inputs, expr) {
+ switch (state) {
+ case 0: /* Identifier */
+ state = 1;
+ continue;
+
+ case 1: /* Constraint */
+ state = 2;
+ if (!expr || expr->type != EXPR_STRING) {
+ sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string");
+ *THIS_ADDRESS(expr) = NULL;
+ continue;
+ }
+ verify_input_constraint(expr, expr->string->data);
+ continue;
+
+ case 2: /* Expression */
+ state = 0;
+ if (!evaluate_expression(expr))
+ return;
+ continue;
+ }
+ } END_FOR_EACH_PTR(expr);
+
+ FOR_EACH_PTR(stmt->asm_clobbers, expr) {
+ if (!expr) {
+ sparse_error(stmt->pos, "bad asm clobbers");
+ return;
+ }
+ if (expr->type == EXPR_STRING)
+ continue;
+ expression_error(expr, "asm clobber is not a string");
+ } END_FOR_EACH_PTR(expr);
+
+ FOR_EACH_PTR(stmt->asm_labels, sym) {
+ if (!sym || sym->type != SYM_LABEL) {
+ sparse_error(stmt->pos, "bad asm label");
+ return;
+ }
+ } END_FOR_EACH_PTR(sym);
+}
+
+static void evaluate_case_statement(struct statement *stmt)
+{
+ evaluate_expression(stmt->case_expression);
+ evaluate_expression(stmt->case_to);
+ evaluate_statement(stmt->case_statement);
+}
+
+static void check_case_type(struct expression *switch_expr,
+ struct expression *case_expr,
+ struct expression **enumcase)
+{
+ struct symbol *switch_type, *case_type;
+ int sclass, cclass;
+
+ if (!case_expr)
+ return;
+
+ switch_type = switch_expr->ctype;
+ case_type = evaluate_expression(case_expr);
+
+ if (!switch_type || !case_type)
+ goto Bad;
+ if (enumcase) {
+ if (*enumcase)
+ warn_for_different_enum_types(case_expr->pos, case_type, (*enumcase)->ctype);
+ else if (is_enum_type(case_type))
+ *enumcase = case_expr;
+ }
+
+ sclass = classify_type(switch_type, &switch_type);
+ cclass = classify_type(case_type, &case_type);
+
+ /* both should be arithmetic */
+ if (!(sclass & cclass & TYPE_NUM))
+ goto Bad;
+
+ /* neither should be floating */
+ if ((sclass | cclass) & TYPE_FLOAT)
+ goto Bad;
+
+ /* if neither is restricted, we are OK */
+ if (!((sclass | cclass) & TYPE_RESTRICT))
+ return;
+
+ if (!restricted_binop_type(SPECIAL_EQUAL, case_expr, switch_expr,
+ cclass, sclass, case_type, switch_type)) {
+ unrestrict(case_expr, cclass, &case_type);
+ unrestrict(switch_expr, sclass, &switch_type);
+ }
+ return;
+
+Bad:
+ expression_error(case_expr, "incompatible types for 'case' statement");
+}
+
+static void evaluate_switch_statement(struct statement *stmt)
+{
+ struct symbol *sym;
+ struct expression *enumcase = NULL;
+ struct expression **enumcase_holder = &enumcase;
+ struct expression *sel = stmt->switch_expression;
+
+ evaluate_expression(sel);
+ evaluate_statement(stmt->switch_statement);
+ if (!sel)
+ return;
+ if (sel->ctype && is_enum_type(sel->ctype))
+ enumcase_holder = NULL; /* Only check cases against switch */
+
+ FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
+ struct statement *case_stmt = sym->stmt;
+ check_case_type(sel, case_stmt->case_expression, enumcase_holder);
+ check_case_type(sel, case_stmt->case_to, enumcase_holder);
+ } END_FOR_EACH_PTR(sym);
+}
+
+static void evaluate_goto_statement(struct statement *stmt)
+{
+ struct symbol *label = stmt->goto_label;
+
+ if (label && !label->stmt && !lookup_keyword(label->ident, NS_KEYWORD))
+ sparse_error(stmt->pos, "label '%s' was not declared", show_ident(label->ident));
+
+ evaluate_expression(stmt->goto_expression);
+}
+
+struct symbol *evaluate_statement(struct statement *stmt)
+{
+ if (!stmt)
+ return NULL;
+
+ switch (stmt->type) {
+ case STMT_DECLARATION: {
+ struct symbol *s;
+ FOR_EACH_PTR(stmt->declaration, s) {
+ evaluate_symbol(s);
+ } END_FOR_EACH_PTR(s);
+ return NULL;
+ }
+
+ case STMT_RETURN:
+ return evaluate_return_expression(stmt);
+
+ case STMT_EXPRESSION:
+ if (!evaluate_expression(stmt->expression))
+ return NULL;
+ if (stmt->expression->ctype == &null_ctype)
+ stmt->expression = cast_to(stmt->expression, &ptr_ctype);
+ return degenerate(stmt->expression);
+
+ case STMT_COMPOUND: {
+ struct statement *s;
+ struct symbol *type = NULL;
+
+ /* Evaluate the return symbol in the compound statement */
+ evaluate_symbol(stmt->ret);
+
+ /*
+ * Then, evaluate each statement, making the type of the
+ * compound statement be the type of the last statement
+ */
+ type = evaluate_statement(stmt->args);
+ FOR_EACH_PTR(stmt->stmts, s) {
+ type = evaluate_statement(s);
+ } END_FOR_EACH_PTR(s);
+ if (!type)
+ type = &void_ctype;
+ return type;
+ }
+ case STMT_IF:
+ evaluate_if_statement(stmt);
+ return NULL;
+ case STMT_ITERATOR:
+ evaluate_iterator(stmt);
+ return NULL;
+ case STMT_SWITCH:
+ evaluate_switch_statement(stmt);
+ return NULL;
+ case STMT_CASE:
+ evaluate_case_statement(stmt);
+ return NULL;
+ case STMT_LABEL:
+ return evaluate_statement(stmt->label_statement);
+ case STMT_GOTO:
+ evaluate_goto_statement(stmt);
+ return NULL;
+ case STMT_NONE:
+ break;
+ case STMT_ASM:
+ evaluate_asm_statement(stmt);
+ return NULL;
+ case STMT_CONTEXT:
+ evaluate_expression(stmt->expression);
+ return NULL;
+ case STMT_RANGE:
+ evaluate_expression(stmt->range_expression);
+ evaluate_expression(stmt->range_low);
+ evaluate_expression(stmt->range_high);
+ return NULL;
+ }
+ return NULL;
+}