--- /dev/null	Fri Dec 21 15:00:12 2018
+++ new/usr/src/tools/smatch/src/evaluate.c	Fri Dec 21 15:00:12 2018
@@ -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;
+}
