/*
 * sparse/evaluate.c
 *
 * Copyright (C) 2003 Transmeta Corp.
 *               2003-2004 Linus Torvalds
 *
 *  Licensed under the Open Software License version 1.1
 *
 * Evaluate constant expressions.
 */
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>

#include "lib.h"
#include "allocate.h"
#include "parse.h"
#include "token.h"
#include "symbol.h"
#include "target.h"
#include "expression.h"

#ifndef DO_CTX
struct symbol *current_fn;
#endif

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

static struct symbol *evaluate_symbol_expression(SCTX_ struct expression *expr)
{
	struct expression *addr;
	struct symbol *sym = expr->symbol;
	struct symbol *base_type;

	if (!sym) {
		expression_error(sctx_ expr, "undefined identifier '%s'", show_ident(sctx_ expr->symbol_name));
		return NULL;
	}

	examine_symbol_type(sctx_ sym);

	base_type = get_base_type(sctx_ sym);
	if (!base_type) {
		expression_error(sctx_ expr, "identifier '%s' has no type", show_ident(sctx_ expr->symbol_name));
		return NULL;
	}

	addr = alloc_expression(sctx_ expr->tok, EXPR_SYMBOL);
	addr->symbol = sym;
	addr->symbol_name = expr->symbol_name;
	addr->ctype = &sctxp lazy_ptr_ctype;	/* Lazy evaluation: we need to do a proper job if somebody does &sym */
	expr->type = EXPR_PREOP;
	expr->op = '*';
	expr->unop = addr;

	/* The type of a symbol is the symbol itself! */
	expr->ctype = sym;
	return sym;
}

static struct symbol *evaluate_string(SCTX_ struct expression *expr)
{
	struct symbol *sym = alloc_symbol(sctx_ expr->tok, SYM_NODE);
	struct symbol *array = alloc_symbol(sctx_ expr->tok, SYM_ARRAY);
	struct expression *addr = alloc_expression(sctx_ expr->tok, EXPR_SYMBOL);
	struct expression *initstr = alloc_expression(sctx_ expr->tok, EXPR_STRING);
	unsigned int length = expr->string->length;

	sym->array_size = alloc_const_expression(sctx_ expr->tok, length);
	sym->bit_size = bytes_to_bits(sctx_ 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(sctx_ length);
	array->ctype.alignment = 1;
	array->ctype.modifiers = MOD_STATIC;
	array->ctype.base_type = &sctxp char_ctype;
	
	addr->symbol = sym;
	addr->ctype = &sctxp lazy_ptr_ctype;

	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(SCTX_ struct symbol *type)
{
	struct symbol *orig_type = 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;
		orig_type = type;
	}
	mod = type->ctype.modifiers;
	if (width < sctxp bits_in_int)
		return &sctxp 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 &sctxp uint_ctype;
		return &sctxp int_ctype;
	}
	return orig_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(SCTX_ struct symbol *left, struct symbol *right)
{
	unsigned long lmod, rmod;

	left = integer_promotion(sctx_ left);
	right = integer_promotion(sctx_ 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(SCTX_ struct symbol *orig, struct symbol *new)
{
	return orig->bit_size == new->bit_size && orig->bit_offset == new->bit_offset;
}

static struct symbol *base_type(SCTX_ struct symbol *node, unsigned long *modp, unsigned long *asp)
{
	unsigned long mod, as;

	mod = 0; as = 0;
	while (node) {
		mod |= node->ctype.modifiers;
		as |= node->ctype.as;
		if (node->type == SYM_NODE) {
			node = node->ctype.base_type;
			continue;
		}
		break;
	}
	*modp = mod & ~MOD_IGNORE;
	*asp = as;
	return node;
}

static int is_same_type(SCTX_ struct expression *expr, struct symbol *new)
{
	struct symbol *old = expr->ctype;
	unsigned long oldmod, newmod, oldas, newas;

	old = base_type(sctx_ old, &oldmod, &oldas);
	new = base_type(sctx_ 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(sctx_ expr->pos->pos, "implicit cast %s nocast type", tofrom);
	}
	return 0;
}

static void
warn_for_different_enum_types (SCTX_ struct position pos,
			       struct symbol *typea,
			       struct symbol *typeb)
{
	if (!sctxp 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(sctx_ pos, "mixing different enum types");
		info(sctx_ pos, "    %s versus", show_typename(sctx_ typea));
		info(sctx_ pos, "    %s", show_typename(sctx_ typeb));
	}
}

/*
 * 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(SCTX_ struct expression *old, struct symbol *type)
{
	struct expression *expr;

	warn_for_different_enum_types (sctx_ old->pos->pos, old->ctype, type);

	if (old->ctype != &sctxp null_ctype && is_same_type(sctx_ 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(sctx_ old->unop, type);
			return old;
		}
		break;

	case EXPR_IMPLIED_CAST:
		warn_for_different_enum_types(sctx_ old->pos->pos, old->ctype, type);

		if (old->ctype->bit_size >= type->bit_size) {
			struct expression *orig = old->cast_expression;
			if (same_cast_type(sctx_ 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(sctx_ old->tok, EXPR_IMPLIED_CAST);
	expr->flags = old->flags;
	expr->ctype = type;
	expr->cast_type = type;
	expr->cast_expression = old;
	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(SCTX_ 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(sctx_ type->initializer);
		if (!type)
			type = &sctxp 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 == &sctxp int_type)
			return TYPE_NUM;
		if (type->ctype.base_type == &sctxp 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(SCTX_ struct symbol *type)
{
	if (type->type == SYM_NODE)
		type = type->ctype.base_type;
	return type->type == SYM_ARRAY && is_byte_type(sctx_ type->ctype.base_type);
}

static struct symbol *bad_expr_type(SCTX_ struct expression *expr)
{
	sparse_error(sctx_ expr->pos->pos, "incompatible types for operation (%s)", show_special(sctx_ expr->op));
	switch (expr->type) {
	case EXPR_BINOP:
	case EXPR_COMPARE:
		info(sctx_ expr->pos->pos, "   left side has type %s", show_typename(sctx_ expr->left->ctype));
		info(sctx_ expr->pos->pos, "   right side has type %s", show_typename(sctx_ expr->right->ctype));
		break;
	case EXPR_PREOP:
	case EXPR_POSTOP:
		info(sctx_ expr->pos->pos, "   argument has type %s", show_typename(sctx_ expr->unop->ctype));
		break;
	default:
		break;
	}

	expr->flags = 0;
	return expr->ctype = &sctxp bad_ctype;
}

static int restricted_value(SCTX_ 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(SCTX_ 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(SCTX_ int op, struct symbol **type)
{
	if (op == '~') {
		if ((*type)->bit_size < sctxp bits_in_int)
			*type = befoul(sctx_ *type);
		return 0;
	} if (op == '+')
		return 0;
	return 1;
}

/* type should be SYM_FOULED */
static inline struct symbol *unfoul(SCTX_ struct symbol *type)
{
	return type->ctype.base_type;
}

static struct symbol *restricted_binop_type(SCTX_ 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(sctx_ ltype) == rtype)
					ctype = ltype;
			} else if (rclass & TYPE_FOULED) {
				if (unfoul(sctx_ rtype) == ltype)
					ctype = rtype;
			}
		} else {
			if (!restricted_value(sctx_ right, ltype))
				ctype = ltype;
		}
	} else if (!restricted_value(sctx_ left, rtype))
		ctype = rtype;

	if (ctype) {
		switch (restricted_binop(sctx_ op, ctype)) {
		case 1:
			if ((lclass ^ rclass) & TYPE_FOULED)
				ctype = unfoul(sctx_ ctype);
			break;
		case 3:
			if (!(lclass & rclass & TYPE_FOULED))
				break;
		case 0:
			ctype = NULL;
		default:
			break;
		}
	}

	return ctype;
}

static inline void unrestrict(SCTX_ struct expression *expr,
			      int class, struct symbol **ctype)
{
	if (class & TYPE_RESTRICT) {
		if (class & TYPE_FOULED)
			*ctype = unfoul(sctx_ *ctype);
		warning(sctx_ expr->pos->pos, "%s degrades to integer",
			show_typename(sctx_ *ctype));
		*ctype = (*ctype)->ctype.base_type; /* get to arithmetic type */
	}
}

static struct symbol *usual_conversions(SCTX_ 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(sctx_ right->pos->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(sctx_ 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(sctx_ op, left, right,
				      lclass, rclass, ltype, rtype);
	if (ctype)
		return ctype;

	unrestrict(sctx_ left, lclass, &ltype);
	unrestrict(sctx_ 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(SCTX_ struct expression *expr, struct symbol *itype)
{
	struct expression *index = expr->right;
	struct symbol *ctype, *base;
	int multiply;

	classify_type(sctx_ degenerate(sctx_ expr->left), &ctype);
	base = examine_pointer_target(sctx_ ctype);

	if (!base) {
		expression_error(sctx_ expr, "missing type information");
		return NULL;
	}
	if (is_function(base)) {
		expression_error(sctx_ expr, "arithmetics on pointers to functions");
		return NULL;
	}

	/* Get the size of whatever the pointer points to */
	multiply = is_void_type(sctx_ base) ? 1 : bits_to_bytes(sctx_ base->bit_size);

	if (ctype == &sctxp null_ctype)
		ctype = &sctxp ptr_ctype;
	expr->ctype = ctype;

	if (multiply == 1 && itype->bit_size >= sctxp bits_in_pointer)
		return ctype;

	if (index->type == EXPR_VALUE) {
		struct expression *val = alloc_expression(sctx_ expr->tok, 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 << (sctxp bits_in_pointer - 1);
		v &= mask | (mask - 1);
		val->value = v;
		val->ctype = sctxp ssize_t_ctype;
		expr->right = val;
		return ctype;
	}

	if (itype->bit_size < sctxp bits_in_pointer)
		index = cast_to(sctx_ index, sctxp ssize_t_ctype);

	if (multiply > 1) {
		struct expression *val = alloc_expression(sctx_ expr->tok, EXPR_VALUE);
		struct expression *mul = alloc_expression(sctx_ expr->tok, EXPR_BINOP);

		val->ctype = sctxp ssize_t_ctype;
		val->value = multiply;

		mul->op = '*';
		mul->ctype = sctxp ssize_t_ctype;
		mul->left = index;
		mul->right = val;
		index = mul;
	}

	expr->right = index;
	return ctype;
}

static void examine_fn_arguments(SCTX_ struct symbol *fn);

#define MOD_IGN (MOD_VOLATILE | MOD_CONST)

const char *type_difference(SCTX_ struct ctype *c1, struct ctype *c2,
	unsigned long mod1, unsigned long mod2)
{
	unsigned long as1 = c1->as, as2 = c2->as;
	struct symbol *t1 = c1->base_type;
	struct symbol *t2 = c2->base_type;
	int move1 = 1, move2 = 1;
	mod1 |= c1->modifiers;
	mod2 |= c2->modifiers;
	for (;;) {
		unsigned long diff;
		int type;
		struct symbol *base1 = t1->ctype.base_type;
		struct symbol *base2 = t2->ctype.base_type;

		/*
		 * FIXME! Collect alignment and context too here!
		 */
		if (move1) {
			if (t1 && t1->type != SYM_PTR) {
				mod1 |= t1->ctype.modifiers;
				as1 |= t1->ctype.as;
			}
			move1 = 0;
		}

		if (move2) {
			if (t2 && t2->type != SYM_PTR) {
				mod2 |= t2->ctype.modifiers;
				as2 |= t2->ctype.as;
			}
			move2 = 0;
		}

		if (t1 == t2)
			break;
		if (!t1 || !t2)
			return "different types";

		if (t1->type == SYM_NODE || t1->type == SYM_ENUM) {
			t1 = base1;
			move1 = 1;
			if (!t1)
				return "bad types";
			continue;
		}

		if (t2->type == SYM_NODE || t2->type == SYM_ENUM) {
			t2 = base2;
			move2 = 1;
			if (!t2)
				return "bad types";
			continue;
		}

		move1 = move2 = 1;
		type = t1->type;
		if (type != t2->type)
			return "different base types";

		switch (type) {
		default:
			sparse_error(sctx_ t1->pos->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(sctx_ t1);
			base2 = examine_pointer_target(sctx_ 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 (base1->variadic != base2->variadic)
				return "incompatible variadic arguments";
			examine_fn_arguments(sctx_ t1);
			examine_fn_arguments(sctx_ 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(sctx_ &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(SCTX_ struct expression *expr)
{
	if (sctxp Wnon_pointer_null)
		warning(sctx_ expr->pos->pos, "Using plain integer as NULL pointer");
}

static unsigned long target_qualifiers(SCTX_ 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(SCTX_ 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(sctx_ degenerate(sctx_ l), &ltype);
	classify_type(sctx_ degenerate(sctx_ r), &rtype);

	lbase = examine_pointer_target(sctx_ ltype);
	examine_pointer_target(sctx_ rtype);
	typediff = type_difference(sctx_ &ltype->ctype, &rtype->ctype,
				   target_qualifiers(sctx_ rtype),
				   target_qualifiers(sctx_ ltype));
	if (typediff)
		expression_error(sctx_ expr, "subtraction of different types can't work (%s)", typediff);

	if (is_function(lbase)) {
		expression_error(sctx_ expr, "subtraction of functions? Share your drugs");
		return NULL;
	}

	expr->ctype = sctxp ssize_t_ctype;
	if (lbase->bit_size > sctxp bits_in_char) {
		struct expression *sub = alloc_expression(sctx_ expr->tok, EXPR_BINOP);
		struct expression *div = expr;
		struct expression *val = alloc_expression(sctx_ expr->tok, EXPR_VALUE);
		unsigned long value = bits_to_bytes(sctx_ lbase->bit_size);

		val->ctype = sctxp size_t_ctype;
		val->value = value;

		if (value & (value-1)) {
			if (sctxp Wptr_subtraction_blows)
				warning(sctx_ expr->pos->pos, "potentially expensive pointer subtraction");
		}

		sub->op = '-';
		sub->ctype = sctxp ssize_t_ctype;
		sub->left = l;
		sub->right = r;

		div->op = '/';
		div->left = sub;
		div->right = val;
	}
		
	return sctxp ssize_t_ctype;
}

#define is_safe_type(type) ((type)->ctype.modifiers & MOD_SAFE)

static struct symbol *evaluate_conditional(SCTX_ struct expression *expr, int iterator)
{
	struct symbol *ctype;

	if (!expr)
		return NULL;

	if (!iterator && expr->type == EXPR_ASSIGNMENT && expr->op == '=')
		warning(sctx_ expr->pos->pos, "assignment expression in conditional");

	ctype = evaluate_expression(sctx_ expr);
	if (ctype) {
		if (is_safe_type(ctype))
			warning(sctx_ expr->pos->pos, "testing a 'safe expression'");
	}

	return ctype;
}

static struct symbol *evaluate_logical(SCTX_ struct expression *expr)
{
	if (!evaluate_conditional(sctx_ expr->left, 0))
		return NULL;
	if (!evaluate_conditional(sctx_ expr->right, 0))
		return NULL;

	expr->ctype = &sctxp bool_ctype;
	if (expr->flags) {
		if (!(expr->left->flags & expr->right->flags & Int_const_expr))
			expr->flags = 0;
	}
	return &sctxp bool_ctype;
}

static struct symbol *evaluate_binop(SCTX_ struct expression *expr)
{
	struct symbol *ltype, *rtype, *ctype;
	int lclass = classify_type(sctx_ expr->left->ctype, &ltype);
	int rclass = classify_type(sctx_ expr->right->ctype, &rtype);
	int op = expr->op;

	if (expr->flags) {
		if (!(expr->left->flags & expr->right->flags & Int_const_expr))
			expr->flags = 0;
	}

	/* number op number */
	if (lclass & rclass & TYPE_NUM) {
		if ((lclass | rclass) & TYPE_FLOAT) {
			switch (op) {
			case '+': case '-': case '*': case '/':
				break;
			default:
				return bad_expr_type(sctx_ expr);
			}
		}

		if (op == SPECIAL_LEFTSHIFT || op == SPECIAL_RIGHTSHIFT) {
			// shifts do integer promotions, but that's it.
			unrestrict(sctx_ expr->left, lclass, &ltype);
			unrestrict(sctx_ expr->right, rclass, &rtype);
			ctype = ltype = integer_promotion(sctx_ ltype);
			rtype = integer_promotion(sctx_ 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(sctx_ expr->pos->pos, "dubious: %sx %c %sy",
				        left_not ? "!" : "",
					op,
					right_not ? "!" : "");

			ltype = usual_conversions(sctx_ op, expr->left, expr->right,
						  lclass, rclass, ltype, rtype);
			ctype = rtype = ltype;
		}

		expr->left = cast_to(sctx_ expr->left, ltype);
		expr->right = cast_to(sctx_ expr->right, rtype);
		expr->ctype = ctype;
		return ctype;
	}

	/* pointer (+|-) integer */
	if (lclass & TYPE_PTR && is_int(rclass) && (op == '+' || op == '-')) {
		unrestrict(sctx_ expr->right, rclass, &rtype);
		return evaluate_ptr_add(sctx_ expr, rtype);
	}

	/* integer + pointer */
	if (rclass & TYPE_PTR && is_int(lclass) && op == '+') {
		struct expression *index = expr->left;
		unrestrict(sctx_ index, lclass, &ltype);
		expr->left = expr->right;
		expr->right = index;
		return evaluate_ptr_add(sctx_ expr, ltype);
	}

	/* pointer - pointer */
	if (lclass & rclass & TYPE_PTR && expr->op == '-')
		return evaluate_ptr_sub(sctx_ expr);

	return bad_expr_type(sctx_ expr);
}

static struct symbol *evaluate_comma(SCTX_ struct expression *expr)
{
	expr->ctype = degenerate(sctx_ expr->right);
	if (expr->ctype == &sctxp null_ctype)
		expr->ctype = &sctxp ptr_ctype;
	expr->flags &= expr->left->flags & expr->right->flags;
	return expr->ctype;
}

static int modify_for_unsigned(SCTX_ 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(SCTX_ struct expression *e)
{
	if (e->ctype == &sctxp null_ctype)
		return 1;
	if (!(e->flags & Int_const_expr))
		return 0;
	return is_zero_constant(sctx_ e) ? 2 : 0;
}

static struct symbol *evaluate_compare(SCTX_ struct expression *expr)
{
	struct expression *left = expr->left, *right = expr->right;
	struct symbol *ltype, *rtype, *lbase, *rbase;
	int lclass = classify_type(sctx_ degenerate(sctx_ left), &ltype);
	int rclass = classify_type(sctx_ degenerate(sctx_ right), &rtype);
	struct symbol *ctype;
	const char *typediff;

	if (expr->flags) {
		if (!(expr->left->flags & expr->right->flags & Int_const_expr))
			expr->flags = 0;
	}

	/* Type types? */
	if (is_type_type(ltype) && is_type_type(rtype))
		goto OK;

	if (is_safe_type(left->ctype) || is_safe_type(right->ctype))
		warning(sctx_ expr->pos->pos, "testing a 'safe expression'");

	/* number on number */
	if (lclass & rclass & TYPE_NUM) {
		ctype = usual_conversions(sctx_ expr->op, expr->left, expr->right,
					  lclass, rclass, ltype, rtype);
		expr->left = cast_to(sctx_ expr->left, ctype);
		expr->right = cast_to(sctx_ expr->right, ctype);
		if (ctype->ctype.modifiers & MOD_UNSIGNED)
			expr->op = modify_for_unsigned(sctx_ expr->op);
		goto OK;
	}

	/* at least one must be a pointer */
	if (!((lclass | rclass) & TYPE_PTR))
		return bad_expr_type(sctx_ 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(sctx_ left);
		int is_null2 = is_null_pointer_constant(sctx_ right);
		if (is_null1 == 2)
			bad_null(sctx_ left);
		if (is_null2 == 2)
			bad_null(sctx_ 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(sctx_ left, rtype);
			goto OK;
		}
		if (is_null2 && (lclass & TYPE_PTR)) {
			right = cast_to(sctx_ right, ltype);
			goto OK;
		}
	}
	/* both should be pointers */
	if (!(lclass & rclass & TYPE_PTR))
		return bad_expr_type(sctx_ expr);
	expr->op = modify_for_unsigned(sctx_ expr->op);

	lbase = examine_pointer_target(sctx_ ltype);
	rbase = examine_pointer_target(sctx_ 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 == &sctxp void_ctype) {
				right = cast_to(sctx_ right, ltype);
				goto OK;
			}
			if (rbase == &sctxp void_ctype) {
				left = cast_to(sctx_ left, rtype);
				goto OK;
			}
		}
	}

	typediff = type_difference(sctx_ &ltype->ctype, &rtype->ctype,
				   target_qualifiers(sctx_ rtype),
				   target_qualifiers(sctx_ ltype));
	if (!typediff)
		goto OK;

	expression_error(sctx_ expr, "incompatible types in comparison expression (%s)", typediff);
	return NULL;

OK:
	expr->ctype = &sctxp bool_ctype;
	return &sctxp bool_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(SCTX_ struct expression *expr)
{
	struct expression **true_sim;
	struct symbol *ctype, *ltype, *rtype, *lbase, *rbase;
	int lclass, rclass;
	const char * typediff;
	int qual;

	if (!evaluate_conditional(sctx_ expr->conditional, 0))
		return NULL;
	if (!evaluate_expression(sctx_ expr->cond_false))
		return NULL;

	ctype = degenerate(sctx_ expr->conditional);
	rtype = degenerate(sctx_ expr->cond_false);

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

	if (expr->flags) {
		int flags = expr->conditional->flags & Int_const_expr;
		flags &= (*true_sim)->flags & expr->cond_false->flags;
		if (!flags)
			expr->flags = 0;
	}

	lclass = classify_type(sctx_ ltype, &ltype);
	rclass = classify_type(sctx_ rtype, &rtype);
	if (lclass & rclass & TYPE_NUM) {
		ctype = usual_conversions(sctx_ '?', *true_sim, expr->cond_false,
					  lclass, rclass, ltype, rtype);
		*true_sim = cast_to(sctx_ *true_sim, ctype);
		expr->cond_false = cast_to(sctx_ expr->cond_false, ctype);
		goto out;
	}

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

		if (is_null1 && is_null2) {
			*true_sim = cast_to(sctx_ *true_sim, &sctxp ptr_ctype);
			expr->cond_false = cast_to(sctx_ expr->cond_false, &sctxp ptr_ctype);
			ctype = &sctxp ptr_ctype;
			goto out;
		}
		if (is_null1 && (rclass & TYPE_PTR)) {
			if (is_null1 == 2)
				bad_null(sctx_ *true_sim);
			*true_sim = cast_to(sctx_ *true_sim, rtype);
			ctype = rtype;
			goto out;
		}
		if (is_null2 && (lclass & TYPE_PTR)) {
			if (is_null2 == 2)
				bad_null(sctx_ expr->cond_false);
			expr->cond_false = cast_to(sctx_ 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(sctx_ ltype);
		rbase = examine_pointer_target(sctx_ rtype);
		qual = target_qualifiers(sctx_ ltype) | target_qualifiers(sctx_ rtype);

		if (lbase == &sctxp void_ctype) {
			/* XXX: pointers to function should warn here */
			ctype = ltype;
			goto Qual;

		}
		if (rbase == &sctxp 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(sctx_ &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(sctx_ expr, "incompatible types in conditional expression (%s)", typediff);
	return NULL;

out:
	expr->ctype = ctype;
	return ctype;

Qual:
	if (qual & ~ctype->ctype.modifiers) {
		struct symbol *sym = alloc_symbol(sctx_ ctype->tok, SYM_PTR);
		*sym = *ctype;
		sym->ctype.modifiers |= qual;
		ctype = sym;
	}
	*true_sim = cast_to(sctx_ *true_sim, ctype);
	expr->cond_false = cast_to(sctx_ expr->cond_false, ctype);
	goto out;
}

/* FP assignments can not do modulo or bit operations */
static int compatible_float_op(SCTX_ int op)
{
	return	op == SPECIAL_ADD_ASSIGN ||
		op == SPECIAL_SUB_ASSIGN ||
		op == SPECIAL_MUL_ASSIGN ||
		op == SPECIAL_DIV_ASSIGN;
}

static int evaluate_assign_op(SCTX_ struct expression *expr)
{
	struct symbol *target = expr->left->ctype;
	struct symbol *source = expr->right->ctype;
	struct symbol *t, *s;
	int tclass = classify_type(sctx_ target, &t);
	int sclass = classify_type(sctx_ source, &s);
	int op = expr->op;

	if (tclass & sclass & TYPE_NUM) {
		if (tclass & TYPE_FLOAT && !compatible_float_op(sctx_ op)) {
			expression_error(sctx_ expr, "invalid assignment");
			return 0;
		}
		if (tclass & TYPE_RESTRICT) {
			if (!restricted_binop(sctx_ op, t)) {
				warning(sctx_ expr->pos->pos, "bad assignment (%s) to %s",
					show_special(sctx_ op), show_typename(sctx_ t));
				expr->right = cast_to(sctx_ expr->right, target);
				return 0;
			}
			/* allowed assignments unfoul */
			if (sclass & TYPE_FOULED && unfoul(sctx_ s) == t)
				goto Cast;
			if (!restricted_value(sctx_ expr->right, t))
				return 1;
		} else if (!(sclass & TYPE_RESTRICT))
			goto Cast;
		/* source and target would better be identical restricted */
		if (t == s)
			return 1;
		warning(sctx_ expr->pos->pos, "invalid assignment: %s", show_special(sctx_ op));
		info(sctx_ expr->pos->pos, "   left side has type %s", show_typename(sctx_ t));
		info(sctx_ expr->pos->pos, "   right side has type %s", show_typename(sctx_ s));
		expr->right = cast_to(sctx_ expr->right, target);
		return 0;
	}
	if (tclass == TYPE_PTR && is_int(sclass)) {
		if (op == SPECIAL_ADD_ASSIGN || op == SPECIAL_SUB_ASSIGN) {
			unrestrict(sctx_ expr->right, sclass, &s);
			evaluate_ptr_add(sctx_ expr, s);
			return 1;
		}
		expression_error(sctx_ expr, "invalid pointer assignment");
		return 0;
	}

	expression_error(sctx_ expr, "invalid assignment");
	return 0;

Cast:
	expr->right = cast_to(sctx_ expr->right, target);
	return 1;
}

static int whitelist_pointers(SCTX_ struct symbol *t1, struct symbol *t2)
{
	if (t1 == t2)
		return 0;	/* yes, 0 - we don't want a cast_to here */
	if (t1 == &sctxp void_ctype)
		return 1;
	if (t2 == &sctxp void_ctype)
		return 1;
	if (classify_type(sctx_ t1, &t1) != TYPE_NUM)
		return 0;
	if (classify_type(sctx_ 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 !sctxp Wtypesign;
}

static int compatible_assignment_types(SCTX_ struct expression *expr, struct symbol *target,
	struct expression **rp, const char *where)
{
	const char *typediff;
	struct symbol *source = degenerate(sctx_ *rp);
	struct symbol *t, *s;
	int tclass = classify_type(sctx_ target, &t);
	int sclass = classify_type(sctx_ source, &s);

	if (tclass & sclass & TYPE_NUM) {
		if (tclass & TYPE_RESTRICT) {
			/* allowed assignments unfoul */
			if (sclass & TYPE_FOULED && unfoul(sctx_ s) == t)
				goto Cast;
			if (!restricted_value(sctx_ *rp, target))
				return 1;
			if (s == t)
				return 1;
		} else if (!(sclass & TYPE_RESTRICT))
			goto Cast;
		typediff = "different base types";
		goto Err;
	}

	if (tclass == TYPE_PTR) {
		unsigned long mod1, mod2;
		struct symbol *b1, *b2;
		// NULL pointer is always OK
		int is_null = is_null_pointer_constant(sctx_ *rp);
		if (is_null) {
			if (is_null == 2)
				bad_null(sctx_ *rp);
			goto Cast;
		}
		if (!(sclass & TYPE_PTR)) {
			typediff = "different base types";
			goto Err;
		}
		b1 = examine_pointer_target(sctx_ t);
		b2 = examine_pointer_target(sctx_ s);
		mod1 = target_qualifiers(sctx_ t);
		mod2 = target_qualifiers(sctx_ s);
		if (whitelist_pointers(sctx_ 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";
				goto Err;
			}
			if (mod2 & ~mod1) {
				typediff = "different modifiers";
				goto Err;
			}
			goto Cast;
		}
		/* It's OK if the target is more volatile or const than the source */
		typediff = type_difference(sctx_ &t->ctype, &s->ctype, 0, mod1);
		if (typediff)
			goto Err;
		return 1;
	}

	if ((tclass & TYPE_COMPOUND) && s == t)
		return 1;

	if (tclass & TYPE_NUM) {
		/* XXX: need to turn into comparison with NULL */
		if (t == &sctxp bool_ctype && (sclass & TYPE_PTR))
			goto Cast;
		typediff = "different base types";
		goto Err;
	}
	typediff = "invalid types";

Err:
	warning(sctx_ expr->pos->pos, "incorrect type in %s (%s)", where, typediff);
	info(sctx_ expr->pos->pos, "   expected %s", show_typename(sctx_ target));
	info(sctx_ expr->pos->pos, "   got %s", show_typename(sctx_ source));
	*rp = cast_to(sctx_ *rp, target);
	return 0;
Cast:
	*rp = cast_to(sctx_ *rp, target);
	return 1;
}

static void mark_assigned(SCTX_ 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(sctx_ expr->left);
		mark_assigned(sctx_ expr->right);
		return;
	case EXPR_CAST:
	case EXPR_FORCE_CAST:
		mark_assigned(sctx_ expr->cast_expression);
		return;
	case EXPR_SLICE:
		mark_assigned(sctx_ expr->base);
		return;
	default:
		/* Hmm? */
		return;
	}
}

static void evaluate_assign_to(SCTX_ struct expression *left, struct symbol *type)
{
	if (type->ctype.modifiers & MOD_CONST)
		expression_error(sctx_ left, "assignment to const expression");

	/* We know left is an lvalue, so it's a "preop-*" */
	mark_assigned(sctx_ left->unop);
}

static struct symbol *evaluate_assignment(SCTX_ struct expression *expr)
{
	struct expression *left = expr->left;
	struct expression *where = expr;
	struct symbol *ltype;

	if (!lvalue_expression(left)) {
		expression_error(sctx_ expr, "not an lvalue");
		return NULL;
	}

	ltype = left->ctype;

	if (expr->op != '=') {
		if (!evaluate_assign_op(sctx_ expr))
			return NULL;
	} else {
		if (!compatible_assignment_types(sctx_ where, ltype, &expr->right, "assignment"))
			return NULL;
	}

	evaluate_assign_to(sctx_ left, ltype);

	expr->ctype = ltype;
	return ltype;
}

static void examine_fn_arguments(SCTX_ struct symbol *fn)
{
	struct symbol *s;

	FOR_EACH_PTR(fn->arguments, s) {
		struct symbol *arg = evaluate_symbol(sctx_ 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(sctx_ s->tok, SYM_PTR);
				if (arg->type == SYM_ARRAY)
					ptr->ctype = arg->ctype;
				else
					ptr->ctype.base_type = arg;
				ptr->ctype.as |= s->ctype.as;
				ptr->ctype.modifiers |= s->ctype.modifiers & MOD_PTRINHERIT;

				s->ctype.base_type = ptr;
				s->ctype.as = 0;
				s->ctype.modifiers &= ~MOD_PTRINHERIT;
				s->bit_size = 0;
				s->examined = 0;
				examine_symbol_type(sctx_ s);
				break;
			default:
				/* nothing */
				break;
			}
		}
	} END_FOR_EACH_PTR(s);
}

static struct symbol *convert_to_as_mod(SCTX_ struct symbol *sym, int as, int mod)
{
	/* Take the modifiers of the pointer, and apply them to the member */
	mod |= sym->ctype.modifiers;
	if (sym->ctype.as != as || sym->ctype.modifiers != mod) {
		struct symbol *newsym = alloc_symbol(sctx_ sym->tok, SYM_NODE);
		*newsym = *sym;
		newsym->ctype.as = as;
		newsym->ctype.modifiers = mod;
		sym = newsym;
	}
	return sym;
}

static struct symbol *create_pointer(SCTX_ struct expression *expr, struct symbol *sym, int degenerate)
{
	struct symbol *node = alloc_symbol(sctx_ expr->tok, SYM_NODE);
	struct symbol *ptr = alloc_symbol(sctx_ expr->tok, SYM_PTR);

	node->ctype.base_type = ptr;
	ptr->bit_size = sctxp bits_in_pointer;
	ptr->ctype.alignment = sctxp pointer_alignment;

	node->bit_size = sctxp bits_in_pointer;
	node->ctype.alignment = sctxp pointer_alignment;

	access_symbol(sctx_ sym);
	if (sym->ctype.modifiers & MOD_REGISTER) {
		warning(sctx_ expr->pos->pos, "taking address of 'register' variable '%s'", show_ident(sctx_ sym->ident));
		sym->ctype.modifiers &= ~MOD_REGISTER;
	}
	if (sym->type == SYM_NODE) {
		ptr->ctype.as |= sym->ctype.as;
		ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT;
		sym = sym->ctype.base_type;
	}
	if (degenerate && sym->type == SYM_ARRAY) {
		ptr->ctype.as |= sym->ctype.as;
		ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT;
		sym = sym->ctype.base_type;
	}
	ptr->ctype.base_type = sym;

	return node;
}

/* Arrays degenerate into pointers on pointer arithmetic */
static struct symbol *degenerate(SCTX_ struct expression *expr)
{
	struct symbol *ctype, *base;

	if (!expr)
		return NULL;
	ctype = expr->ctype;
	if (!ctype)
		return NULL;
	base = examine_symbol_type(sctx_ 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(sctx_ expr->tok, 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(sctx_ expr->tok, EXPR_SYMBOL);
			e0->symbol = a;
			e0->ctype = &sctxp lazy_ptr_ctype;

			e1 = alloc_expression(sctx_ expr->tok, EXPR_PREOP);
			e1->unop = e0;
			e1->op = '*';
			e1->ctype = expr->base->ctype;	/* XXX */

			e2 = alloc_expression(sctx_ expr->tok, EXPR_ASSIGNMENT);
			e2->left = e1;
			e2->right = expr->base;
			e2->op = '=';
			e2->ctype = expr->base->ctype;

			if (expr->r_bitpos) {
				e3 = alloc_expression(sctx_ expr->tok, EXPR_BINOP);
				e3->op = '+';
				e3->left = e0;
				e3->right = alloc_const_expression(sctx_ expr->tok,
							bits_to_bytes(sctx_ expr->r_bitpos));
				e3->ctype = &sctxp lazy_ptr_ctype;
			} else {
				e3 = e0;
			}

			e4 = alloc_expression(sctx_ expr->tok, EXPR_COMMA);
			e4->left = e2;
			e4->right = e3;
			e4->ctype = &sctxp lazy_ptr_ctype;

			expr->unop = e4;
			expr->type = EXPR_PREOP;
			expr->op = '*';
		}
	case SYM_FN:
		if (expr->op != '*' || expr->type != EXPR_PREOP) {
			expression_error(sctx_ expr, "strange non-value function or array");
			return &sctxp bad_ctype;
		}
		*expr = *expr->unop;
		ctype = create_pointer(sctx_ expr, ctype, 1);
		expr->ctype = ctype;
	default:
		/* nothing */;
	}
	return ctype;
}

static struct symbol *evaluate_addressof(SCTX_ struct expression *expr)
{
	struct expression *op = expr->unop;
	struct symbol *ctype;

	if (op->op != '*' || op->type != EXPR_PREOP) {
		expression_error(sctx_ expr, "not addressable");
		return NULL;
	}
	ctype = op->ctype;
	*expr = *op->unop;
	expr->flags = 0;

	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 == &sctxp lazy_ptr_ctype) {
		ctype = create_pointer(sctx_ expr, ctype, 0);
		expr->ctype = ctype;
	}
	return expr->ctype;
}


static struct symbol *evaluate_dereference(SCTX_ 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 = 0;
		return expr->ctype;
	}

	/* Dereferencing a node drops all the node information. */
	if (ctype->type == SYM_NODE)
		ctype = ctype->ctype.base_type;

	node = alloc_symbol(sctx_ expr->tok, SYM_NODE);
	target = ctype->ctype.base_type;

	switch (ctype->type) {
	default:
		expression_error(sctx_ expr, "cannot dereference this type");
		return NULL;
	case SYM_PTR:
		node->ctype.modifiers = target->ctype.modifiers & MOD_SPECIFIER;
		merge_type(sctx_ node, ctype);
		break;

	case SYM_ARRAY:
		if (!lvalue_expression(op)) {
			expression_error(sctx_ op, "non-lvalue array??");
			return NULL;
		}

		/* Do the implied "addressof" on the array */
		*op = *op->unop;

		/*
		 * When an array is dereferenced, we need to pick
		 * up the attributes of the original node too..
		 */
		merge_type(sctx_ node, op->ctype);
		merge_type(sctx_ 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(SCTX_ struct expression *expr)
{
	struct expression *op = expr->unop;
	struct symbol *ctype = op->ctype;
	int class = classify_type(sctx_ ctype, &ctype);
	int multiply = 0;

	if (!class || class & TYPE_COMPOUND) {
		expression_error(sctx_ expr, "need scalar for ++/--");
		return NULL;
	}
	if (!lvalue_expression(expr->unop)) {
		expression_error(sctx_ expr, "need lvalue expression for ++/--");
		return NULL;
	}

	if ((class & TYPE_RESTRICT) && restricted_unop(sctx_ expr->op, &ctype))
		unrestrict(sctx_ expr, class, &ctype);

	if (class & TYPE_NUM) {
		multiply = 1;
	} else if (class == TYPE_PTR) {
		struct symbol *target = examine_pointer_target(sctx_ ctype);
		if (!is_function(target))
			multiply = bits_to_bytes(sctx_ target->bit_size);
	}

	if (multiply) {
		evaluate_assign_to(sctx_ op, op->ctype);
		expr->op_value = multiply;
		expr->ctype = ctype;
		return ctype;
	}

	expression_error(sctx_ expr, "bad argument type for ++/--");
	return NULL;
}

static struct symbol *evaluate_sign(SCTX_ struct expression *expr)
{
	struct symbol *ctype = expr->unop->ctype;
	int class = classify_type(sctx_ ctype, &ctype);
	if (expr->flags && !(expr->unop->flags & Int_const_expr))
		expr->flags = 0;
	/* should be an arithmetic type */
	if (!(class & TYPE_NUM))
		return bad_expr_type(sctx_ expr);
	if (class & TYPE_RESTRICT)
		goto Restr;
Normal:
	if (!(class & TYPE_FLOAT)) {
		ctype = integer_promotion(sctx_ ctype);
		expr->unop = cast_to(sctx_ expr->unop, ctype);
	} else if (expr->op != '~') {
		/* no conversions needed */
	} else {
		return bad_expr_type(sctx_ expr);
	}
	if (expr->op == '+')
		*expr = *expr->unop;
	expr->ctype = ctype;
	return ctype;
Restr:
	if (restricted_unop(sctx_ expr->op, &ctype))
		unrestrict(sctx_ expr, class, &ctype);
	goto Normal;
}

static struct symbol *evaluate_preop(SCTX_ struct expression *expr)
{
	struct symbol *ctype = expr->unop->ctype;

	switch (expr->op) {
	case '(':
		*expr = *expr->unop;
		return ctype;

	case '+':
	case '-':
	case '~':
		return evaluate_sign(sctx_ expr);

	case '*':
		return evaluate_dereference(sctx_ expr);

	case '&':
		return evaluate_addressof(sctx_ expr);

	case SPECIAL_INCREMENT:
	case SPECIAL_DECREMENT:
		/*
		 * From a type evaluation standpoint the preops are
		 * the same as the postops
		 */
		return evaluate_postop(sctx_ expr);

	case '!':
		if (expr->flags && !(expr->unop->flags & Int_const_expr))
			expr->flags = 0;
		if (is_safe_type(ctype))
			warning(sctx_ expr->pos->pos, "testing a 'safe expression'");
		if (is_float_type(sctx_ ctype)) {
			struct expression *arg = expr->unop;
			expr->type = EXPR_BINOP;
			expr->op = SPECIAL_EQUAL;
			expr->left = arg;
			expr->right = alloc_expression(sctx_ expr->tok, EXPR_FVALUE);
			expr->right->ctype = ctype;
			expr->right->fvalue = 0;
		} else if (is_fouled_type(ctype)) {
			warning(sctx_ expr->pos->pos, "%s degrades to integer",
				show_typename(sctx_ ctype->ctype.base_type));
		}
		ctype = &sctxp bool_ctype;
		break;

	default:
		break;
	}
	expr->ctype = ctype;
	return &sctxp bool_ctype;
}

static struct symbol *find_identifier(SCTX_ 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(sctx_ 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(SCTX_ 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(sctx_ expr->tok, EXPR_BINOP);
	add->op = '+';
	add->left = expr;
	add->right = alloc_expression(sctx_ expr->tok, EXPR_VALUE);
	add->right->ctype = &sctxp 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 = &sctxp lazy_ptr_ctype;
	return add;
}

/* structure/union dereference */
static struct symbol *evaluate_member_dereference(SCTX_ struct expression *expr)
{
	int offset;
	struct symbol *ctype, *member;
	struct expression *deref = expr->deref, *add;
	struct ident *ident = expr->member;
	unsigned int mod;
	int address_space;

	if (!evaluate_expression(sctx_ deref))
		return NULL;
	if (!ident) {
		expression_error(sctx_ expr, "bad member name");
		return NULL;
	}

	ctype = deref->ctype;
	examine_symbol_type(sctx_ ctype);
	address_space = ctype->ctype.as;
	mod = ctype->ctype.modifiers;
	if (ctype->type == SYM_NODE) {
		ctype = ctype->ctype.base_type;
		address_space |= ctype->ctype.as;
		mod |= ctype->ctype.modifiers;
	}
	if (!ctype || (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION)) {
		expression_error(sctx_ expr, "expected structure or union");
		return NULL;
	}
	offset = 0;
	member = find_identifier(sctx_ 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(sctx_ expr, "no member '%s' in %s %.*s",
				show_ident(sctx_ ident), type, namelen, name);
		else
			expression_error(sctx_ expr, "using member '%s' in "
				"incomplete %s %.*s", show_ident(sctx_ 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(sctx_ member, address_space, mod);
	ctype = get_base_type(sctx_ 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(sctx_ 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(sctx_ deref, offset);
	expr->type = EXPR_PREOP;
	expr->op = '*';
	expr->unop = add;

	expr->ctype = member;
	return member;
}

static int is_promoted(SCTX_ 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(SCTX_ struct expression *);

static struct symbol *evaluate_type_information(SCTX_ struct expression *expr)
{
	struct symbol *sym = expr->cast_type;
	if (!sym) {
		sym = evaluate_expression(sctx_ 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 < sctxp bits_in_int && is_promoted(sctx_ expr))
				sym = &sctxp int_ctype;
		} else if (is_fouled_type(sym)) {
			sym = &sctxp int_ctype;
		}
	}
	examine_symbol_type(sctx_ sym);
	if (is_bitfield_type(sym)) {
		expression_error(sctx_ expr, "trying to examine bitfield type");
		return NULL;
	}
	return sym;
}

static struct symbol *evaluate_sizeof(SCTX_ struct expression *expr)
{
	struct symbol *type;
	int size;

	type = evaluate_type_information(sctx_ expr);
	if (!type)
		return NULL;

	size = type->bit_size;

	if (size < 0 && is_void_type(sctx_ type)) {
		warning(sctx_ expr->pos->pos, "expression using sizeof(void)");
		size = sctxp bits_in_char;
	}

	if (size == 1 && is_bool_type(sctx_ type)) {
		warning(sctx_ expr->pos->pos, "expression using sizeof bool");
		size = sctxp bits_in_char;
	}

	if (is_function(type->ctype.base_type)) {
		warning(sctx_ expr->pos->pos, "expression using sizeof on a function");
		size = sctxp bits_in_char;
	}

	if ((size < 0) || (size & (sctxp bits_in_char - 1)))
		expression_error(sctx_ expr, "cannot size expression");

	expr->type = EXPR_VALUE;
	expr->value = bits_to_bytes(sctx_ size);
	expr->taint = 0;
	expr->ctype = sctxp size_t_ctype;
	return sctxp size_t_ctype;
}

static struct symbol *evaluate_ptrsizeof(SCTX_ struct expression *expr)
{
	struct symbol *type;
	int size;

	type = evaluate_type_information(sctx_ 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(sctx_ type);
		if (type)
			break;
	default:
		expression_error(sctx_ expr, "expected pointer expression");
		return NULL;
	}
	size = type->bit_size;
	if (size & (sctxp bits_in_char-1))
		size = 0;
	expr->type = EXPR_VALUE;
	expr->value = bits_to_bytes(sctx_ size);
	expr->taint = 0;
	expr->ctype = sctxp size_t_ctype;
	return sctxp size_t_ctype;
}

static struct symbol *evaluate_alignof(SCTX_ struct expression *expr)
{
	struct symbol *type;

	type = evaluate_type_information(sctx_ expr);
	if (!type)
		return NULL;

	expr->type = EXPR_VALUE;
	expr->value = type->ctype.alignment;
	expr->taint = 0;
	expr->ctype = sctxp size_t_ctype;
	return sctxp size_t_ctype;
}

static int evaluate_arguments(SCTX_ struct symbol *f, 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(sctx_ expr);

		if (!ctype)
			return 0;

		target = argtype;
		if (!target) {
			struct symbol *type;
			int class = classify_type(sctx_ ctype, &type);
			if (is_int(class)) {
				*p = cast_to(sctx_ expr, integer_promotion(sctx_ type));
			} else if (class & TYPE_FLOAT) {
				unsigned long mod = type->ctype.modifiers;
				if (!(mod & (MOD_LONG_ALL)))
					*p = cast_to(sctx_ expr, &sctxp double_ctype);
			} else if (class & TYPE_PTR) {
				if (expr->ctype == &sctxp null_ctype)
					*p = cast_to(sctx_ expr, &sctxp ptr_ctype);
				else
					degenerate(sctx_ expr);
			}
		} else if (!target->forced_arg){
			static char where[30];
			examine_symbol_type(sctx_ target);
			sprintf(where, "argument %d", i);
			compatible_assignment_types(sctx_ expr, target, p, where);
		}

		i++;
		NEXT_PTR_LIST(argtype);
	} END_FOR_EACH_PTR(expr);
	FINISH_PTR_LIST(argtype);
	return 1;
}

static struct symbol *find_struct_ident(SCTX_ struct symbol *ctype, struct ident *ident)
{
	struct symbol *sym;

	FOR_EACH_PTR(ctype->symbol_list, sym) {
		if (sym->ident == ident)
			return sym;
	} END_FOR_EACH_PTR(sym);
	return NULL;
}

static void convert_index(SCTX_ 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(sctx_ e->ctype->bit_size);
	e->init_nr = to - from;
	e->init_expr = child;
}

static void convert_ident(SCTX_ struct expression *e)
{
	struct expression *child = e->ident_expression;
	struct symbol *sym = e->field;
	e->type = EXPR_POS;
	e->init_offset = sym->offset;
	e->init_nr = 1;
	e->init_expr = child;
}

static void convert_designators(SCTX_ struct expression *e)
{
	while (e) {
		if (e->type == EXPR_INDEX)
			convert_index(sctx_ e);
		else if (e->type == EXPR_IDENTIFIER)
			convert_ident(sctx_ e);
		else
			break;
		e = e->init_expr;
	}
}

static void excess(SCTX_ struct expression *e, const char *s)
{
	warning(sctx_ e->pos->pos, "excessive elements in %s initializer", s);
}

/*
 * implicit designator for the first element
 */
static struct expression *first_subobject(SCTX_ 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(sctx_ e->tok, 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(sctx_ e->tok, EXPR_IDENTIFIER);
		new->ident_expression = e;
		new->field = new->ctype = field;
	}
	*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(SCTX_ 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 = e->idx_to * type->bit_size;
				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) {
			if (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION) {
				err = "field name not in struct or union";
				break;
			}
			ctype = find_struct_ident(sctx_ ctype, e->expr_ident);
			if (!ctype) {
				err = "unknown field name in";
				break;
			}
			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(sctx_ 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(SCTX_ 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(sctx_ old->idx_expression,
					old->ctype, e, v);
		if (!copy) {
			n = old->idx_to + 1;
			if (n * old->ctype->bit_size == ctype->bit_size) {
				convert_index(sctx_ old);
				return NULL;
			}
			copy = e;
			*v = new = alloc_expression(sctx_ e->tok, EXPR_INDEX);
		} else {
			n = old->idx_to;
			new = alloc_expression(sctx_ e->tok, EXPR_INDEX);
		}

		new->idx_from = new->idx_to = n;
		new->idx_expression = copy;
		new->ctype = old->ctype;
		convert_index(sctx_ old);
	} else if (old->type == EXPR_IDENTIFIER) {
		struct expression *copy;
		struct symbol *field;

		copy = next_designators(sctx_ old->ident_expression,
					old->ctype, e, v);
		if (!copy) {
			field = old->field->next_subobject;
			if (!field) {
				convert_ident(sctx_ old);
				return NULL;
			}
			copy = e;
			*v = new = alloc_expression(sctx_ e->tok, EXPR_IDENTIFIER);
		} else {
			field = old->field;
			new = alloc_expression(sctx_ e->tok, EXPR_IDENTIFIER);
		}

		new->field = field;
		new->expr_ident = field->ident;
		new->ident_expression = copy;
		new->ctype = field;
		convert_ident(sctx_ old);
	}
	return new;
}

static int handle_simple_initializer(SCTX_ struct expression **ep, int nested,
				     int class, struct symbol *ctype);

/*
 * deal with traversing subobjects [6.7.8(17,18,20)]
 */
static void handle_list_initializer(SCTX_ struct expression *expr,
				    int class, struct symbol *ctype)
{
	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(sctx_ ctype, class, &top);
			} else {
				last = next_designators(sctx_ last, ctype, e, &top);
			}
			if (!last) {
				excess(sctx_ 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 (sctxp Wdesignated_init && struct_sym->designated_init)
				warning(sctx_ e->pos->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(sctx_ struct_sym->type),
					show_ident(sctx_ struct_sym->ident));
			if (jumped) {
				warning(sctx_ e->pos->pos, "advancing past deep designator");
				jumped = 0;
			}
			REPLACE_CURRENT_PTR(e, last);
		} else {
			next = check_designators(sctx_ e, ctype);
			if (!next) {
				DELETE_CURRENT_PTR(e);
				continue;
			}
			top = next;
			/* deeper than one designator? */
			jumped = top != e;
			convert_designators(sctx_ last);
			last = e;
		}

found:
		lclass = classify_type(sctx_ top->ctype, &type);
		if (top->type == EXPR_INDEX)
			v = &top->idx_expression;
		else
			v = &top->ident_expression;

		if (handle_simple_initializer(sctx_ v, 1, lclass, top->ctype))
			continue;

		if (!(lclass & TYPE_COMPOUND)) {
			warning(sctx_ e->pos->pos, "bogus scalar initializer");
			DELETE_CURRENT_PTR(e);
			continue;
		}

		next = first_subobject(sctx_ type, lclass, v);
		if (next) {
			warning(sctx_ e->pos->pos, "missing braces around initializer");
			top = next;
			goto found;
		}

		DELETE_CURRENT_PTR(e);
		excess(sctx_ e, lclass & TYPE_PTR ? "array" : "struct or union");

	} END_FOR_EACH_PTR(e);

	convert_designators(sctx_ last);
	expr->ctype = ctype;
}

static int is_string_literal(SCTX_ 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 && sctxp Wparen_string)
		warning(sctx_ e->pos->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(SCTX_ 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(sctx_ e->pos->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_simple_initializer(SCTX_ struct expression **ep, int nested,
				     int class, struct symbol *ctype)
{
	int is_string = is_string_type(sctx_ ctype);
	struct expression *e = *ep, *p;
	struct symbol *type;

	if (!e)
		return 0;

	/* scalar */
	if (!(class & TYPE_COMPOUND)) {
		e = handle_scalar(sctx_ e, nested);
		if (!e)
			return 0;
		*ep = e;
		if (!evaluate_expression(sctx_ e))
			return 1;
		compatible_assignment_types(sctx_ e, ctype, ep, "initializer");
		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(sctx_ &v)) {
				*ep = e = v;
				goto String;
			}
		}
		handle_list_initializer(sctx_ e, class, ctype);
		return 1;
	}

	/* string */
	if (is_string_literal(sctx_ &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(sctx_ 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(sctx_ e->tok, EXPR_STRING);
	*p = *e;
	type = evaluate_expression(sctx_ p);
	if (ctype->bit_size != -1) {
		if (ctype->bit_size + sctxp bits_in_char < type->bit_size)
			warning(sctx_ e->pos->pos,
				"too long initializer-string for array of char");
		else if (sctxp Winit_cstring && ctype->bit_size + sctxp bits_in_char == type->bit_size) {
			warning(sctx_ e->pos->pos,
				"too long initializer-string for array of char(no space for nul char)");
		}
	}
	*ep = p;
	return 1;
}

static void evaluate_initializer(SCTX_ struct symbol *ctype, struct expression **ep)
{
	struct symbol *type;
	int class = classify_type(sctx_ ctype, &type);
	if (!handle_simple_initializer(sctx_ ep, 0, class, ctype))
		expression_error(sctx_ *ep, "invalid initializer");
}

static struct symbol *evaluate_cast(SCTX_ struct expression *expr)
{
	struct expression *target = expr->cast_expression;
	struct symbol *ctype;
	struct symbol *t1, *t2;
	int class1, class2;
	int as1 = 0, as2 = 0;

	if (!target)
		return NULL;

	/*
	 * Special case: a cast can be followed by an
	 * initializer, in which case we need to pass
	 * the type value down to that initializer rather
	 * than trying to evaluate it as an expression
	 *
	 * A more complex case is when the initializer is
	 * dereferenced as part of a post-fix expression.
	 * We need to produce an expression that can be dereferenced.
	 */
	if (target->type == EXPR_INITIALIZER) {
		struct symbol *sym = expr->cast_type;
		struct expression *addr = alloc_expression(sctx_ expr->tok, EXPR_SYMBOL);

		sym->initializer = target;
		evaluate_symbol(sctx_ sym);

		addr->ctype = &sctxp lazy_ptr_ctype;	/* Lazy eval */
		addr->symbol = sym;

		expr->type = EXPR_PREOP;
		expr->op = '*';
		expr->unop = addr;
		expr->ctype = sym;

		return sym;
	}

	ctype = examine_symbol_type(sctx_ expr->cast_type);
	expr->ctype = ctype;
	expr->cast_type = ctype;

	evaluate_expression(sctx_ target);
	degenerate(sctx_ target);

	class1 = classify_type(sctx_ ctype, &t1);

	/* cast to non-integer type -> not an integer constant expression */
	if (!is_int(class1))
		expr->flags = 0;
	/* if argument turns out to be not an integer constant expression *and*
	   it was not a floating literal to start with -> too bad */
	else if (expr->flags == Int_const_expr &&
		!(target->flags & Int_const_expr))
		expr->flags = 0;
	/*
	 * You can always throw a value away by casting to
	 * "void" - that's an implicit "force". Note that
	 * the same is _not_ true of "void *".
	 */
	if (t1 == &sctxp void_ctype)
		goto out;

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

	t2 = target->ctype;
	if (!t2) {
		expression_error(sctx_ expr, "cast from unknown type");
		goto out;
	}
	class2 = classify_type(sctx_ t2, &t2);

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

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

	/* allowed cast unfouls */
	if (class2 & TYPE_FOULED)
		t2 = unfoul(sctx_ t2);

	if (t1 != t2) {
		if (class1 & TYPE_RESTRICT)
			warning(sctx_ expr->pos->pos, "cast to %s",
				show_typename(sctx_ t1));
		if (class2 & TYPE_RESTRICT)
			warning(sctx_ expr->pos->pos, "cast from %s",
				show_typename(sctx_ t2));
	}

	if (t1 == &sctxp ulong_ctype)
		as1 = -1;
	else if (class1 == TYPE_PTR) {
		examine_pointer_target(sctx_ t1);
		as1 = t1->ctype.as;
	}

	if (t2 == &sctxp ulong_ctype)
		as2 = -1;
	else if (class2 == TYPE_PTR) {
		examine_pointer_target(sctx_ t2);
		as2 = t2->ctype.as;
	}

	if (!as1 && as2 > 0)
		warning(sctx_ expr->pos->pos, "cast removes address space of expression");
	if (as1 > 0 && as2 > 0 && as1 != as2)
		warning(sctx_ expr->pos->pos, "cast between address spaces (<asn:%d>-><asn:%d>)", as2, as1);
	if (as1 > 0 && !as2 &&
	    !is_null_pointer_constant(sctx_ target) && sctxp Wcast_to_as)
		warning(sctx_ expr->pos->pos,
			"cast adds address space to expression (<asn:%d>)", as1);

	if (!(t1->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR &&
	    !as1 && (target->flags & Int_const_expr)) {
		if (t1->ctype.base_type == &sctxp void_ctype) {
			if (is_zero_constant(sctx_ target)) {
				/* NULL */
				expr->type = EXPR_VALUE;
				expr->ctype = &sctxp null_ctype;
				expr->value = 0;
				return ctype;
			}
		}
	}
out:
	return ctype;
}

/*
 * Evaluate a call expression with a symbol. This
 * should expand inline functions, and evaluate
 * builtins.
 */
static int evaluate_symbol_call(SCTX_ 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(sctx_ expr);

	if (ctype->ctype.modifiers & MOD_INLINE) {
		int ret;
		struct symbol *curr = sctxp current_fn;

		if (ctype->definition)
			ctype = ctype->definition;

		sctxp current_fn = ctype->ctype.base_type;

		ret = inline_function(sctx_ expr, ctype);

		/* restore the old function */
		sctxp current_fn = curr;
		return ret;
	}

	return 0;
}

static struct symbol *evaluate_call(SCTX_ struct expression *expr)
{
	int args, fnargs;
	struct symbol *ctype, *sym;
	struct expression *fn = expr->fn;
	struct expression_list *arglist = expr->args;

	if (!evaluate_expression(sctx_ 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(sctx_ ctype);

	if (ctype->type != SYM_FN) {
		struct expression *arg;
		expression_error(sctx_ expr, "not a function %s",
			     show_ident(sctx_ sym->ident));
		/* do typechecking in arguments */
		FOR_EACH_PTR (arglist, arg) {
			evaluate_expression(sctx_ arg);
		} END_FOR_EACH_PTR(arg);
		return NULL;
	}

	examine_fn_arguments(sctx_ ctype);
        if (sym->type == SYM_NODE && fn->type == EXPR_PREOP &&
	    sym->op && sym->op->args) {
		if (!sym->op->args(sctx_ expr))
			return NULL;
	} else {
		if (!evaluate_arguments(sctx_ sym, ctype, arglist))
			return NULL;
		args = expression_list_size(sctx_ expr->args);
		fnargs = symbol_list_size(sctx_ ctype->arguments);
		if (args < fnargs)
			expression_error(sctx_ expr,
				     "not enough arguments for function %s",
				     show_ident(sctx_ sym->ident));
		if (args > fnargs && !ctype->variadic)
			expression_error(sctx_ expr,
				     "too many arguments for function %s",
				     show_ident(sctx_ sym->ident));
	}
	if (sym->type == SYM_NODE) {
		if (evaluate_symbol_call(sctx_ expr))
			return expr->ctype;
	}
	expr->ctype = ctype->ctype.base_type;
	return expr->ctype;
}

static struct symbol *evaluate_offsetof(SCTX_ 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(sctx_ expr, "expected structure or union");
			return NULL;
		}
		examine_symbol_type(sctx_ ctype);
		class = classify_type(sctx_ ctype, &ctype);
		if (class != TYPE_COMPOUND) {
			expression_error(sctx_ expr, "expected structure or union");
			return NULL;
		}

		field = find_identifier(sctx_ expr->ident, ctype->symbol_list, &offset);
		if (!field) {
			expression_error(sctx_ expr, "unknown member");
			return NULL;
		}
		ctype = field;
		expr->type = EXPR_VALUE;
		expr->flags = Int_const_expr;
		expr->value = offset;
		expr->taint = 0;
		expr->ctype = sctxp size_t_ctype;
	} else {
		if (!ctype) {
			expression_error(sctx_ expr, "expected structure or union");
			return NULL;
		}
		examine_symbol_type(sctx_ ctype);
		class = classify_type(sctx_ ctype, &ctype);
		if (class != (TYPE_COMPOUND | TYPE_PTR)) {
			expression_error(sctx_ expr, "expected array");
			return NULL;
		}
		ctype = ctype->ctype.base_type;
		if (!expr->index) {
			expr->type = EXPR_VALUE;
			expr->flags = Int_const_expr;
			expr->value = 0;
			expr->taint = 0;
			expr->ctype = sctxp size_t_ctype;
		} else {
			struct expression *idx = expr->index, *m;
			struct symbol *i_type = evaluate_expression(sctx_ idx);
			int i_class = classify_type(sctx_ i_type, &i_type);
			if (!is_int(i_class)) {
				expression_error(sctx_ expr, "non-integer index");
				return NULL;
			}
			unrestrict(sctx_ idx, i_class, &i_type);
			idx = cast_to(sctx_ idx, sctxp size_t_ctype);
			m = alloc_const_expression(sctx_ expr->tok,
						   bits_to_bytes(sctx_ ctype->bit_size));
			m->ctype = sctxp size_t_ctype;
			m->flags = Int_const_expr;
			expr->type = EXPR_BINOP;
			expr->left = idx;
			expr->right = m;
			expr->op = '*';
			expr->ctype = sctxp size_t_ctype;
			expr->flags = m->flags & idx->flags & Int_const_expr;
		}
	}
	if (e) {
		struct expression *copy = __alloc_expression(sctx_ 0);
		*copy = *expr;
		if (e->type == EXPR_OFFSETOF)
			e->in = ctype;
		if (!evaluate_expression(sctx_ e))
			return NULL;
		expr->type = EXPR_BINOP;
		expr->flags = e->flags & copy->flags & Int_const_expr;
		expr->op = '+';
		expr->ctype = sctxp size_t_ctype;
		expr->left = copy;
		expr->right = e;
	}
	return sctxp size_t_ctype;
}

struct symbol *evaluate_expression(SCTX_ struct expression *expr)
{
	if (!expr)
		return NULL;
	if (expr->ctype)
		return expr->ctype;

	switch (expr->type) {
	case EXPR_VALUE:
	case EXPR_FVALUE:
		expression_error(sctx_ expr, "value expression without a type");
		return NULL;
	case EXPR_STRING:
		return evaluate_string(sctx_ expr);
	case EXPR_SYMBOL:
		return evaluate_symbol_expression(sctx_ expr);
	case EXPR_BINOP:
		if (!evaluate_expression(sctx_ expr->left))
			return NULL;
		if (!evaluate_expression(sctx_ expr->right))
			return NULL;
		return evaluate_binop(sctx_ expr);
	case EXPR_LOGICAL:
		return evaluate_logical(sctx_ expr);
	case EXPR_COMMA:
		evaluate_expression(sctx_ expr->left);
		if (!evaluate_expression(sctx_ expr->right))
			return NULL;
		return evaluate_comma(sctx_ expr);
	case EXPR_COMPARE:
		if (!evaluate_expression(sctx_ expr->left))
			return NULL;
		if (!evaluate_expression(sctx_ expr->right))
			return NULL;
		return evaluate_compare(sctx_ expr);
	case EXPR_ASSIGNMENT:
		if (!evaluate_expression(sctx_ expr->left))
			return NULL;
		if (!evaluate_expression(sctx_ expr->right))
			return NULL;
		return evaluate_assignment(sctx_ expr);
	case EXPR_PREOP:
		if (!evaluate_expression(sctx_ expr->unop))
			return NULL;
		return evaluate_preop(sctx_ expr);
	case EXPR_POSTOP:
		if (!evaluate_expression(sctx_ expr->unop))
			return NULL;
		return evaluate_postop(sctx_ expr);
	case EXPR_CAST:
	case EXPR_FORCE_CAST:
	case EXPR_IMPLIED_CAST:
		return evaluate_cast(sctx_ expr);
	case EXPR_SIZEOF:
		return evaluate_sizeof(sctx_ expr);
	case EXPR_PTRSIZEOF:
		return evaluate_ptrsizeof(sctx_ expr);
	case EXPR_ALIGNOF:
		return evaluate_alignof(sctx_ expr);
	case EXPR_DEREF:
		return evaluate_member_dereference(sctx_ expr);
	case EXPR_CALL:
		return evaluate_call(sctx_ expr);
	case EXPR_SELECT:
	case EXPR_CONDITIONAL:
		return evaluate_conditional_expression(sctx_ expr);
	case EXPR_STATEMENT:
		expr->ctype = evaluate_statement(sctx_ expr->statement);
		return expr->ctype;

	case EXPR_LABEL:
		expr->ctype = &sctxp ptr_ctype;
		return &sctxp ptr_ctype;

	case EXPR_TYPE:
		/* Evaluate the type of the symbol .. */
		evaluate_symbol(sctx_ expr->symbol);
		/* .. but the type of the _expression_ is a "type" */
		expr->ctype = &sctxp type_ctype;
		return &sctxp type_ctype;

	case EXPR_OFFSETOF:
		return evaluate_offsetof(sctx_ expr);

	/* These can not exist as stand-alone expressions */
	case EXPR_INITIALIZER:
	case EXPR_IDENTIFIER:
	case EXPR_INDEX:
	case EXPR_POS:
		expression_error(sctx_ expr, "internal front-end error: initializer in expression");
		return NULL;
	case EXPR_SLICE:
		expression_error(sctx_ expr, "internal front-end error: SLICE re-evaluated");
		return NULL;
	}
	return NULL;
}

static void check_duplicates(SCTX_ struct symbol *sym)
{
	int declared = 0;
	struct symbol *next = sym;

	while ((next = next->same_symbol) != NULL) {
		const char *typediff;
		evaluate_symbol(sctx_ next);
		declared++;
		typediff = type_difference(sctx_ &sym->ctype, &next->ctype, 0, 0);
		if (typediff) {
			sparse_error(sctx_ sym->pos->pos, "symbol '%s' redeclared with different type (originally declared at %s:%d) - %s",
				show_ident(sctx_ sym->ident),
				stream_name(sctx_ next->pos->pos.stream), next->pos->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 (!sctxp Wdecl)
			return;
		if (sym->ident == (struct ident *)&sctxp main_ident)
			return;
		warning(sctx_ sym->pos->pos, "symbol '%s' was not declared. Should it be static?", show_ident(sctx_ sym->ident));
	}
}

static struct symbol *evaluate_symbol(SCTX_ struct symbol *sym)
{
	struct symbol *base_type;

	if (!sym)
		return sym;
	if (sym->evaluated)
		return sym;
	sym->evaluated = 1;

	sym = examine_symbol_type(sctx_ sym);
	base_type = get_base_type(sctx_ sym);
	if (!base_type)
		return NULL;

	/* Evaluate the initializers */
	if (sym->initializer)
		evaluate_initializer(sctx_ sym, &sym->initializer);

	/* And finally, evaluate the body of the symbol too */
	if (base_type->type == SYM_FN) {
		struct symbol *curr = sctxp current_fn;

		if (sym->definition && sym->definition != sym)
			return evaluate_symbol(sctx_ sym->definition);

		sctxp current_fn = base_type;

		examine_fn_arguments(sctx_ base_type);
		if (!base_type->stmt && base_type->inline_stmt)
			uninline(sctx_ sym);
		if (base_type->stmt)
			evaluate_statement(sctx_ base_type->stmt);

		sctxp current_fn = curr;
	}

	return base_type;
}

void evaluate_symbol_list(SCTX_ struct symbol_list *list)
{
	struct symbol *sym;

	FOR_EACH_PTR(list, sym) {
		evaluate_symbol(sctx_ sym);
		check_duplicates(sctx_ sym);
	} END_FOR_EACH_PTR(sym);
}

static struct symbol *evaluate_return_expression(SCTX_ struct statement *stmt)
{
	struct expression *expr = stmt->expression;
	struct symbol *fntype;

	evaluate_expression(sctx_ expr);
	fntype = sctxp current_fn->ctype.base_type;
	if (!fntype || fntype == &sctxp void_ctype) {
		if (expr && expr->ctype != &sctxp void_ctype)
			expression_error(sctx_ expr, "return expression in %s function", fntype?"void":"typeless");
		if (expr && sctxp Wreturn_void)
			warning(sctx_ stmt->pos->pos, "returning void-valued expression");
		return NULL;
	}

	if (!expr) {
		sparse_error(sctx_ stmt->pos->pos, "return with no return value");
		return NULL;
	}
	if (!expr->ctype)
		return NULL;
	compatible_assignment_types(sctx_ expr, fntype, &stmt->expression, "return expression");
	return NULL;
}

static void evaluate_if_statement(SCTX_ struct statement *stmt)
{
	if (!stmt->if_conditional)
		return;

	evaluate_conditional(sctx_ stmt->if_conditional, 0);
	evaluate_statement(sctx_ stmt->if_true);
	evaluate_statement(sctx_ stmt->if_false);
}

static void evaluate_iterator(SCTX_ struct statement *stmt)
{
	evaluate_symbol_list(sctx_ stmt->iterator_syms);
	evaluate_conditional(sctx_ stmt->iterator_pre_condition, 1);
	evaluate_conditional(sctx_ stmt->iterator_post_condition,1);
	evaluate_statement(sctx_ stmt->iterator_pre_statement);
	evaluate_statement(sctx_ stmt->iterator_statement);
	evaluate_statement(sctx_ stmt->iterator_post_statement);
}

static void verify_output_constraint(SCTX_ struct expression *expr, const char *constraint)
{
	switch (*constraint) {
	case '=':	/* Assignment */
	case '+':	/* Update */
		break;
	default:
		expression_error(sctx_ expr, "output constraint is not an assignment constraint (\"%s\")", constraint);
	}
}

static void verify_input_constraint(SCTX_ struct expression *expr, const char *constraint)
{
	switch (*constraint) {
	case '=':	/* Assignment */
	case '+':	/* Update */
		expression_error(sctx_ expr, "input constraint with assignment (\"%s\")", constraint);
	}
}

static void evaluate_asm_statement(SCTX_ struct statement *stmt)
{
	struct expression *expr;
	struct symbol *sym;
	int state;

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

	state = 0;
	FOR_EACH_PTR(stmt->asm_outputs, expr) {
		switch (state) {
		case 0: /* Identifier */
			state = 1;
			continue;

		case 1: /* Constraint */
			state = 2;
			if (!expr || expr->type != EXPR_STRING) {
				sparse_error(sctx_ expr ? expr->pos->pos : stmt->pos->pos, "asm output constraint is not a string");
				*THIS_ADDRESS(expr) = NULL;
				continue;
			}
			verify_output_constraint(sctx_ expr, expr->string->data);
			continue;

		case 2: /* Expression */
			state = 0;
			if (!evaluate_expression(sctx_ expr))
				return;
			if (!lvalue_expression(expr))
				warning(sctx_ expr->pos->pos, "asm output is not an lvalue");
			evaluate_assign_to(sctx_ expr, expr->ctype);
			continue;
		}
	} END_FOR_EACH_PTR(expr);

	state = 0;
	FOR_EACH_PTR(stmt->asm_inputs, expr) {
		switch (state) {
		case 0: /* Identifier */
			state = 1;
			continue;

		case 1:	/* Constraint */
			state = 2;
			if (!expr || expr->type != EXPR_STRING) {
				sparse_error(sctx_ expr ? expr->pos->pos : stmt->pos->pos, "asm input constraint is not a string");
				*THIS_ADDRESS(expr) = NULL;
				continue;
			}
			verify_input_constraint(sctx_ expr, expr->string->data);
			continue;

		case 2: /* Expression */
			state = 0;
			if (!evaluate_expression(sctx_ expr))
				return;
			continue;
		}
	} END_FOR_EACH_PTR(expr);

	FOR_EACH_PTR(stmt->asm_clobbers, expr) {
		if (!expr) {
			sparse_error(sctx_ stmt->pos->pos, "bad asm clobbers");
			return;
		}
		if (expr->type == EXPR_STRING)
			continue;
		expression_error(sctx_ 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(sctx_ stmt->pos->pos, "bad asm label");
			return;
		}
	} END_FOR_EACH_PTR(sym);
}

static void evaluate_case_statement(SCTX_ struct statement *stmt)
{
	evaluate_expression(sctx_ stmt->case_expression);
	evaluate_expression(sctx_ stmt->case_to);
	evaluate_statement(sctx_ stmt->case_statement);
}

static void check_case_type(SCTX_ 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(sctx_ case_expr);

	if (!switch_type || !case_type)
		goto Bad;
	if (enumcase) {
		if (*enumcase)
			warn_for_different_enum_types(sctx_ case_expr->pos->pos, case_type, (*enumcase)->ctype);
		else if (is_enum_type(case_type))
			*enumcase = case_expr;
	}

	sclass = classify_type(sctx_ switch_type, &switch_type);
	cclass = classify_type(sctx_ 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(sctx_ SPECIAL_EQUAL, case_expr, switch_expr,
				   cclass, sclass, case_type, switch_type)) {
		unrestrict(sctx_ case_expr, cclass, &case_type);
		unrestrict(sctx_ switch_expr, sclass, &switch_type);
	}
	return;

Bad:
	expression_error(sctx_ case_expr, "incompatible types for 'case' statement");
}

static void evaluate_switch_statement(SCTX_ struct statement *stmt)
{
	struct symbol *sym;
	struct expression *enumcase = NULL;
	struct expression **enumcase_holder = &enumcase;
	struct expression *sel = stmt->switch_expression;

	evaluate_expression(sctx_ sel);
	evaluate_statement(sctx_ 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(sctx_ sel, case_stmt->case_expression, enumcase_holder);
		check_case_type(sctx_ sel, case_stmt->case_to, enumcase_holder);
	} END_FOR_EACH_PTR(sym);
}

static void evaluate_goto_statement(SCTX_ struct statement *stmt)
{
	struct symbol *label = stmt->goto_label;

	if (label && !label->stmt && !lookup_keyword(sctx_ label->ident, NS_KEYWORD))
		sparse_error(sctx_ stmt->pos->pos, "label '%s' was not declared", show_ident(sctx_ label->ident));

	evaluate_expression(sctx_ stmt->goto_expression);
}

struct symbol *evaluate_statement(SCTX_ struct statement *stmt)
{
	if (!stmt)
		return NULL;

	switch (stmt->type) {
	case STMT_DECLARATION: {
		struct symbol *s;
		FOR_EACH_PTR(stmt->declaration, s) {
			evaluate_symbol(sctx_ s);
		} END_FOR_EACH_PTR(s);
		return NULL;
	}

	case STMT_RETURN:
		return evaluate_return_expression(sctx_ stmt);

	case STMT_EXPRESSION:
		if (!evaluate_expression(sctx_ stmt->expression))
			return NULL;
		if (stmt->expression->ctype == &sctxp null_ctype)
			stmt->expression = cast_to(sctx_ stmt->expression, &sctxp ptr_ctype);
		return degenerate(sctx_ stmt->expression);

	case STMT_COMPOUND: {
		struct statement *s;
		struct symbol *type = NULL;

		/* Evaluate the return symbol in the compound statement */
		evaluate_symbol(sctx_ stmt->ret);

		/*
		 * Then, evaluate each statement, making the type of the
		 * compound statement be the type of the last statement
		 */
		type = evaluate_statement(sctx_ stmt->args);
		FOR_EACH_PTR(stmt->stmts, s) {
			type = evaluate_statement(sctx_ s);
		} END_FOR_EACH_PTR(s);
		if (!type)
			type = &sctxp void_ctype;
		return type;
	}
	case STMT_IF:
		evaluate_if_statement(sctx_ stmt);
		return NULL;
	case STMT_ITERATOR:
		evaluate_iterator(sctx_ stmt);
		return NULL;
	case STMT_SWITCH:
		evaluate_switch_statement(sctx_ stmt);
		return NULL;
	case STMT_CASE:
		evaluate_case_statement(sctx_ stmt);
		return NULL;
	case STMT_LABEL:
		return evaluate_statement(sctx_ stmt->label_statement);
	case STMT_GOTO:
		evaluate_goto_statement(sctx_ stmt);
		return NULL;
	case STMT_NONE:
		break;
	case STMT_ASM:
		evaluate_asm_statement(sctx_ stmt);
		return NULL;
	case STMT_CONTEXT:
		evaluate_expression(sctx_ stmt->expression);
		return NULL;
	case STMT_RANGE:
		evaluate_expression(sctx_ stmt->range_expression);
		evaluate_expression(sctx_ stmt->range_low);
		evaluate_expression(sctx_ stmt->range_high);
		return NULL;
	}
	return NULL;
}
