root/usr/src/tools/smatch/src/evaluate.c
/*
 * 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 (non-scalar type)");
                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;
}

enum null_constant_type {
        NON_NULL,
        NULL_PTR,
        NULL_ZERO,
};

static inline int is_null_pointer_constant(struct expression *e)
{
        if (e->ctype == &null_ctype)
                return NULL_PTR;
        if (!(e->flags & CEF_ICE))
                return NON_NULL;
        return is_zero_constant(e) ? NULL_ZERO : NON_NULL;
}

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 == NULL_ZERO)
                        bad_null(left);
                if (is_null2 == NULL_ZERO)
                        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);
        info(expr->pos, "   %s", show_typename(ltype));
        info(expr->pos, "   %s", show_typename(rtype));
        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 == NULL_ZERO)
                                bad_null(*cond);
                        *cond = cast_to(*cond, rtype);
                        ctype = rtype;
                        goto out;
                }
                if (is_null2 && (lclass & TYPE_PTR)) {
                        if (is_null2 == NULL_ZERO)
                                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);
        info(expr->pos, "   %s", show_typename(ltype));
        info(expr->pos, "   %s", show_typename(rtype));
        /*
         * 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 == NULL_ZERO)
                                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 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(expr, 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;
}

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_to_bytes(bits_in_bool) * 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 || ttype == uintptr_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 || stype == uintptr_ctype))
                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 | MOD_EXT_VISIBLE))
                        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;
}