/*
 * 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 "evaluate.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;

struct ident bad_address_space = { .len = 6, .name = "bad AS", };

static struct symbol *degenerate(struct expression *expr);
static struct symbol *evaluate_symbol(struct symbol *sym);

static inline int valid_expr_type(struct expression *expr)
{
	return expr && valid_type(expr->ctype);
}

static inline int valid_subexpr_type(struct expression *expr)
{
	return valid_expr_type(expr->left)
	    && valid_expr_type(expr->right);
}

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, struct ident **asp)
{
	unsigned long mod = 0;
	struct ident *as = NULL;

	while (node) {
		mod |= node->ctype.modifiers;
		combine_address_space(node->pos, &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;
	struct ident *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)
{
	switch (expr->type) {
	case EXPR_BINOP:
	case EXPR_COMPARE:
		if (!valid_subexpr_type(expr))
			break;
		sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
		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:
		if (!valid_expr_type(expr->unop))
			break;
		sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
		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_QUALIFIER | MOD_PURE)

const char *type_difference(struct ctype *c1, struct ctype *c2,
	unsigned long mod1, unsigned long mod2)
{
	struct ident *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;
				combine_address_space(t1->pos, &as1, t1->ctype.as);
			}
			move1 = 0;
		}

		if (move2) {
			if (t2 && t2->type != SYM_PTR) {
				mod2 |= t2->ctype.modifiers;
				combine_address_space(t2->pos, &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");
				info(expr->pos, "    '%s' has a non-power-of-2 size: %lu", show_typename(lbase), value);
			}
		}

		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 (!valid_type(ctype))
		return NULL;
	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));
		return 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 **cond;
	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);

	cond = &expr->conditional;
	ltype = ctype;
	if (expr->cond_true) {
		if (!evaluate_expression(expr->cond_true))
			return NULL;
		ltype = degenerate(expr->cond_true);
		cond = &expr->cond_true;
	}

	expr->flags = (expr->conditional->flags & (*cond)->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 = (*cond)->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('?', *cond, expr->cond_false,
					  lclass, rclass, ltype, rtype);
		*cond = cast_to(*cond, ctype);
		expr->cond_false = cast_to(expr->cond_false, ctype);
		goto out;
	}

	if ((lclass | rclass) & TYPE_PTR) {
		int is_null1 = is_null_pointer_constant(*cond);
		int is_null2 = is_null_pointer_constant(expr->cond_false);

		if (is_null1 && is_null2) {
			*cond = cast_to(*cond, &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(*cond);
			*cond = cast_to(*cond, 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;
	}
	*cond = cast_to(*cond, 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 (op == SPECIAL_SHR_ASSIGN || op == SPECIAL_SHL_ASSIGN) {
			// shifts do integer promotions, but that's it.
			unrestrict(expr->right, sclass, &s);
			target = integer_promotion(s);
			goto Cast;
		} 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;
				combine_address_space(s->pos, &ptr->ctype.as, s->ctype.as);
				ptr->ctype.modifiers |= s->ctype.modifiers & MOD_PTRINHERIT;

				s->ctype.base_type = ptr;
				s->ctype.as = NULL;
				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, struct ident *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) {
		combine_address_space(sym->pos, &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) {
		combine_address_space(sym->pos, &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;

	target = ctype->ctype.base_type;
	examine_symbol_type(target);

	switch (ctype->type) {
	default:
		expression_error(expr, "cannot dereference this type");
		return NULL;
	case SYM_FN:
		*expr = *op;
		return expr->ctype;
	case SYM_PTR:
		node = alloc_symbol(expr->pos, SYM_NODE);
		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..
		 */
		node = alloc_symbol(expr->pos, SYM_NODE);
		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 '!':
		ctype = degenerate(expr->unop);
		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;
	struct ident *address_space;
	unsigned int mod;

	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;
		combine_address_space(deref->pos, &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 (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 (is_array_type(type) && size < 0) {	// VLA, 1-dimension only
		struct expression *base, *size;
		struct symbol *base_type;

		if (type->type == SYM_NODE)
			type = type->ctype.base_type;	// strip the SYM_NODE
		base_type = get_base_type(type);
		if (!base_type)
			goto error;
		if (base_type->bit_size <= 0) {
			base = alloc_expression(expr->pos, EXPR_SIZEOF);
			base->cast_type = base_type;
			if (!evaluate_sizeof(base))
				goto error;
		} else {
			base = alloc_expression(expr->pos, EXPR_VALUE);
			base->value = bits_to_bytes(base_type->bit_size);
			base->ctype = size_t_ctype;
		}
		size = alloc_expression(expr->pos, EXPR_CAST);
		size->cast_type = size_t_ctype;
		size->cast_expression = type->array_size;
		if (!evaluate_expression(size))
			goto error;
		expr->left = size;
		expr->right = base;
		expr->type = EXPR_BINOP;
		expr->op = '*';
		return expr->ctype = size_t_ctype;
	}

error:
	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 *source = expr->cast_expression;
	struct symbol *ctype;
	struct symbol *ttype, *stype;
	int tclass, sclass;
	struct ident *tas = NULL, *sas = NULL;

	if (!source)
		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 (source->type == EXPR_INITIALIZER) {
		struct symbol *sym = expr->cast_type;
		struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);

		sym->initializer = source;
		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(source);
	degenerate(source);

	tclass = classify_type(ctype, &ttype);

	expr->flags = cast_flags(expr, source);

	/*
	 * 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 (ttype == &void_ctype)
		goto out;

	stype = source->ctype;
	if (!stype) {
		expression_error(expr, "cast from unknown type");
		goto out;
	}
	sclass = classify_type(stype, &stype);

	if (expr->type == EXPR_FORCE_CAST)
		goto out;

	if (tclass & (TYPE_COMPOUND | TYPE_FN))
		warning(expr->pos, "cast to non-scalar");

	if (sclass & TYPE_COMPOUND)
		warning(expr->pos, "cast from non-scalar");

	/* allowed cast unfouls */
	if (sclass & TYPE_FOULED)
		stype = unfoul(stype);

	if (ttype != stype) {
		if ((tclass & TYPE_RESTRICT) && restricted_value(source, ttype))
			warning(expr->pos, "cast to %s",
				show_typename(ttype));
		if (sclass & TYPE_RESTRICT) {
			if (ttype == &bool_ctype) {
				if (sclass & TYPE_FOULED)
					warning(expr->pos, "%s degrades to integer",
						show_typename(stype));
			} else {
				warning(expr->pos, "cast from %s",
					show_typename(stype));
			}
		}
	}

	if (ttype == &ulong_ctype && !Wcast_from_as)
		tas = &bad_address_space;
	else if (tclass == TYPE_PTR) {
		examine_pointer_target(ttype);
		tas = ttype->ctype.as;
	}

	if (stype == &ulong_ctype && !Wcast_from_as)
		sas = &bad_address_space;
	else if (sclass == TYPE_PTR) {
		examine_pointer_target(stype);
		sas = stype->ctype.as;
	}

	if (!tas && valid_as(sas))
		warning(expr->pos, "cast removes address space '%s' of expression", show_as(sas));
	if (valid_as(tas) && valid_as(sas) && tas != sas)
		warning(expr->pos, "cast between address spaces (%s -> %s)", show_as(sas), show_as(tas));
	if (valid_as(tas) && !sas &&
	    !is_null_pointer_constant(source) && Wcast_to_as)
		warning(expr->pos,
			"cast adds address space '%s' to expression", show_as(tas));

	if (!(ttype->ctype.modifiers & MOD_PTRINHERIT) && tclass == TYPE_PTR &&
	    !tas && (source->flags & CEF_ICE)) {
		if (ttype->ctype.base_type == &void_ctype) {
			if (is_zero_constant(source)) {
				/* NULL */
				expr->type = EXPR_VALUE;
				expr->ctype = &null_ctype;
				expr->value = 0;
				return expr->ctype;
			}
		}
	}

	if (ttype == &bool_ctype)
		cast_to_bool(expr);

	// checks pointers to restricted
	while (Wbitwise_pointer && tclass == TYPE_PTR && sclass == TYPE_PTR) {
		tclass = classify_type(ttype->ctype.base_type, &ttype);
		sclass = classify_type(stype->ctype.base_type, &stype);
		if (ttype == stype)
			break;
		if (!ttype || !stype)
			break;
		if (ttype == &void_ctype || stype == &void_ctype)
			break;
		if (tclass & TYPE_RESTRICT) {
			warning(expr->pos, "cast to %s", show_typename(ctype));
			break;
		}
		if (sclass & TYPE_RESTRICT) {
			warning(expr->pos, "cast from %s", show_typename(source->ctype));
			break;
		}
	}
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:
		evaluate_expression(expr->left);
		evaluate_expression(expr->right);
		if (!valid_subexpr_type(expr))
			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:
		evaluate_expression(expr->left);
		evaluate_expression(expr->right);
		if (!valid_subexpr_type(expr))
			return NULL;
		return evaluate_compare(expr);
	case EXPR_ASSIGNMENT:
		evaluate_expression(expr->left);
		evaluate_expression(expr->right);
		if (!valid_subexpr_type(expr))
			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;
	case EXPR_ASM_OPERAND:
		expression_error(expr, "internal front-end error: ASM_OPERAND evaluated");
		return NULL;
	}
	return NULL;
}

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 expression *op;
	struct symbol *sym;

	expr = stmt->asm_string;
	if (!expr || expr->type != EXPR_STRING) {
		sparse_error(stmt->pos, "need constant string for inline asm");
		return;
	}

	FOR_EACH_PTR(stmt->asm_outputs, op) {
		/* Identifier */

		/* Constraint */
		expr = op->constraint;
		if (!expr || expr->type != EXPR_STRING) {
			sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string");
			op->constraint = NULL;
		} else
			verify_output_constraint(expr, expr->string->data);

		/* Expression */
		expr = op->expr;
		if (!evaluate_expression(expr))
			return;
		if (!lvalue_expression(expr))
			warning(expr->pos, "asm output is not an lvalue");
		evaluate_assign_to(expr, expr->ctype);
	} END_FOR_EACH_PTR(op);

	FOR_EACH_PTR(stmt->asm_inputs, op) {
		/* Identifier */

		/* Constraint */
		expr = op->constraint;
		if (!expr || expr->type != EXPR_STRING) {
			sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string");
			op->constraint = NULL;
		} else
			verify_input_constraint(expr, expr->string->data);

		/* Expression */
		if (!evaluate_expression(op->expr))
			return;
	} END_FOR_EACH_PTR(op);

	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 && label->ident && !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;
}
