Print this page
11972 resync smatch

@@ -32,10 +32,11 @@
 #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"

@@ -42,13 +43,26 @@
 #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;

@@ -194,18 +208,18 @@
 {
         return orig->bit_size == new->bit_size &&
                orig->bit_offset == new->bit_offset;
 }
 
-static struct symbol *base_type(struct symbol *node, unsigned long *modp, unsigned long *asp)
+static struct symbol *base_type(struct symbol *node, unsigned long *modp, struct ident **asp)
 {
-        unsigned long mod, as;
+        unsigned long mod = 0;
+        struct ident *as = NULL;
 
-        mod = 0; as = 0;
         while (node) {
                 mod |= node->ctype.modifiers;
-                as |= node->ctype.as;
+                combine_address_space(node->pos, &as, node->ctype.as);
                 if (node->type == SYM_NODE) {
                         node = node->ctype.base_type;
                         continue;
                 }
                 break;

@@ -216,11 +230,12 @@
 }
 
 static int is_same_type(struct expression *expr, struct symbol *new)
 {
         struct symbol *old = expr->ctype;
-        unsigned long oldmod, newmod, oldas, newas;
+        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? */

@@ -391,19 +406,24 @@
         return type->type == SYM_ARRAY && is_byte_type(type->ctype.base_type);
 }
 
 static struct symbol *bad_expr_type(struct expression *expr)
 {
-        sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
         switch (expr->type) {
         case EXPR_BINOP:
         case EXPR_COMPARE:
+                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;
         }

@@ -636,16 +656,16 @@
         return ctype;
 }
 
 static void examine_fn_arguments(struct symbol *fn);
 
-#define MOD_IGN (MOD_VOLATILE | MOD_CONST | MOD_PURE)
+#define MOD_IGN (MOD_QUALIFIER | MOD_PURE)
 
 const char *type_difference(struct ctype *c1, struct ctype *c2,
         unsigned long mod1, unsigned long mod2)
 {
-        unsigned long as1 = c1->as, as2 = c2->as;
+        struct 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;

@@ -659,19 +679,19 @@
                  * FIXME! Collect alignment and context too here!
                  */
                 if (move1) {
                         if (t1 && t1->type != SYM_PTR) {
                                 mod1 |= t1->ctype.modifiers;
-                                as1 |= t1->ctype.as;
+                                combine_address_space(t1->pos, &as1, t1->ctype.as);
                         }
                         move1 = 0;
                 }
 
                 if (move2) {
                         if (t2 && t2->type != SYM_PTR) {
                                 mod2 |= t2->ctype.modifiers;
-                                as2 |= t2->ctype.as;
+                                combine_address_space(t2->pos, &as2, t2->ctype.as);
                         }
                         move2 = 0;
                 }
 
                 if (t1 == t2)

@@ -845,13 +865,15 @@
 
                 val->ctype = size_t_ctype;
                 val->value = value;
 
                 if (value & (value-1)) {
-                        if (Wptr_subtraction_blows)
+                        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;

@@ -875,27 +897,27 @@
 
         if (!iterator && expr->type == EXPR_ASSIGNMENT && expr->op == '=')
                 warning(expr->pos, "assignment expression in conditional");
 
         ctype = evaluate_expression(expr);
-        if (ctype) {
+        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");
+                sparse_error(expr->pos, "incorrect type in conditional (non-scalar type)");
                         info(expr->pos, "   got %s", show_typename(ctype));
-                        ctype = NULL;
+                return NULL;
                 }
-        }
-        ctype = degenerate(expr);
 
+        ctype = degenerate(expr);
         return ctype;
 }
 
 static struct symbol *evaluate_logical(struct expression *expr)
 {

@@ -1003,17 +1025,23 @@
         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 1;
+                return NULL_PTR;
         if (!(e->flags & CEF_ICE))
-                return 0;
-        return is_zero_constant(e) ? 2 : 0;
+                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;

@@ -1055,13 +1083,13 @@
 
         /* equality comparisons can be with null pointer constants */
         if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) {
                 int is_null1 = is_null_pointer_constant(left);
                 int is_null2 = is_null_pointer_constant(right);
-                if (is_null1 == 2)
+                if (is_null1 == NULL_ZERO)
                         bad_null(left);
-                if (is_null2 == 2)
+                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;

@@ -1102,11 +1130,13 @@
                                    target_qualifiers(rtype),
                                    target_qualifiers(ltype));
         if (!typediff)
                 goto OK;
 
-        expression_error(expr, "incompatible types in comparison expression (%s)", typediff);
+        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;

@@ -1120,11 +1150,11 @@
  * test in the expression. But since promotion is "safe"
  * for testing, that's OK.
  */
 static struct symbol *evaluate_conditional_expression(struct expression *expr)
 {
-        struct expression **true;
+        struct expression **cond;
         struct symbol *ctype, *ltype, *rtype, *lbase, *rbase;
         int lclass, rclass;
         const char * typediff;
         int qual;
 

@@ -1134,20 +1164,20 @@
                 return NULL;
 
         ctype = degenerate(expr->conditional);
         rtype = degenerate(expr->cond_false);
 
-        true = &expr->conditional;
+        cond = &expr->conditional;
         ltype = ctype;
         if (expr->cond_true) {
                 if (!evaluate_expression(expr->cond_true))
                         return NULL;
                 ltype = degenerate(expr->cond_true);
-                true = &expr->cond_true;
+                cond = &expr->cond_true;
         }
 
-        expr->flags = (expr->conditional->flags & (*true)->flags &
+        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)].

@@ -1159,41 +1189,41 @@
          * However, as an extension, if the condition is any constant
          * expression, and the true and false expressions are both
          * address constants, mark the result as an address constant.
          */
         if (expr->conditional->flags & (CEF_ACE | CEF_ADDR))
-                expr->flags = (*true)->flags & expr->cond_false->flags & ~CEF_CONST_MASK;
+                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('?', *true, expr->cond_false,
+                ctype = usual_conversions('?', *cond, expr->cond_false,
                                           lclass, rclass, ltype, rtype);
-                *true = cast_to(*true, ctype);
+                *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(*true);
+                int is_null1 = is_null_pointer_constant(*cond);
                 int is_null2 = is_null_pointer_constant(expr->cond_false);
 
                 if (is_null1 && is_null2) {
-                        *true = cast_to(*true, &ptr_ctype);
+                        *cond = cast_to(*cond, &ptr_ctype);
                         expr->cond_false = cast_to(expr->cond_false, &ptr_ctype);
                         ctype = &ptr_ctype;
                         goto out;
                 }
                 if (is_null1 && (rclass & TYPE_PTR)) {
-                        if (is_null1 == 2)
-                                bad_null(*true);
-                        *true = cast_to(*true, rtype);
+                        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 == 2)
+                        if (is_null2 == NULL_ZERO)
                                 bad_null(expr->cond_false);
                         expr->cond_false = cast_to(expr->cond_false, ltype);
                         ctype = ltype;
                         goto out;
                 }

@@ -1238,11 +1268,13 @@
                 goto out;
         }
         typediff = "different base types";
 
 Err:
-        expression_error(expr, "incompatible types in conditional expression (%s)", typediff);
+        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)) {

@@ -1264,11 +1296,11 @@
                 struct symbol *sym = alloc_symbol(ctype->pos, SYM_PTR);
                 *sym = *ctype;
                 sym->ctype.modifiers |= qual;
                 ctype = sym;
         }
-        *true = cast_to(*true, ctype);
+        *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 */

@@ -1304,10 +1336,15 @@
                         /* 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;

@@ -1392,11 +1429,11 @@
                 unsigned long mod1, mod2;
                 struct symbol *b1, *b2;
                 // NULL pointer is always OK
                 int is_null = is_null_pointer_constant(*rp);
                 if (is_null) {
-                        if (is_null == 2)
+                        if (is_null == NULL_ZERO)
                                 bad_null(*rp);
                         goto Cast;
                 }
                 if (!(sclass & TYPE_PTR)) {
                         *typediff = "different base types";

@@ -1542,11 +1579,10 @@
 }
 
 static struct symbol *evaluate_assignment(struct expression *expr)
 {
         struct expression *left = expr->left;
-        struct expression *where = expr;
         struct symbol *ltype;
 
         if (!lvalue_expression(left)) {
                 expression_error(expr, "not an lvalue");
                 return NULL;

@@ -1556,11 +1592,11 @@
 
         if (expr->op != '=') {
                 if (!evaluate_assign_op(expr))
                         return NULL;
         } else {
-                if (!compatible_assignment_types(where, ltype, &expr->right, "assignment"))
+                if (!compatible_assignment_types(expr, ltype, &expr->right, "assignment"))
                         return NULL;
         }
 
         evaluate_assign_to(left, ltype);
 

@@ -1583,15 +1619,15 @@
                                 ptr = alloc_symbol(s->pos, SYM_PTR);
                                 if (arg->type == SYM_ARRAY)
                                         ptr->ctype = arg->ctype;
                                 else
                                         ptr->ctype.base_type = arg;
-                                ptr->ctype.as |= s->ctype.as;
+                                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 = 0;
+                                s->ctype.as = NULL;
                                 s->ctype.modifiers &= ~MOD_PTRINHERIT;
                                 s->bit_size = 0;
                                 s->examined = 0;
                                 examine_symbol_type(s);
                                 break;

@@ -1601,11 +1637,11 @@
                         }
                 }
         } END_FOR_EACH_PTR(s);
 }
 
-static struct symbol *convert_to_as_mod(struct symbol *sym, int as, int mod)
+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);

@@ -1633,16 +1669,16 @@
         if (sym->ctype.modifiers & MOD_REGISTER) {
                 warning(expr->pos, "taking address of 'register' variable '%s'", show_ident(sym->ident));
                 sym->ctype.modifiers &= ~MOD_REGISTER;
         }
         if (sym->type == SYM_NODE) {
-                ptr->ctype.as |= sym->ctype.as;
+                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) {
-                ptr->ctype.as |= sym->ctype.as;
+                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;
 

@@ -1774,18 +1810,22 @@
 
         /* Dereferencing a node drops all the node information. */
         if (ctype->type == SYM_NODE)
                 ctype = ctype->ctype.base_type;
 
-        node = alloc_symbol(expr->pos, SYM_NODE);
         target = ctype->ctype.base_type;
+        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:

@@ -1799,10 +1839,11 @@
 
                 /*
                  * 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;
         }
 

@@ -1912,10 +1953,11 @@
                  * 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)].
                  */

@@ -2019,12 +2061,12 @@
 {
         int offset;
         struct symbol *ctype, *member;
         struct expression *deref = expr->deref, *add;
         struct ident *ident = expr->member;
+        struct ident *address_space;
         unsigned int mod;
-        int address_space;
 
         if (!evaluate_expression(deref))
                 return NULL;
         if (!ident) {
                 expression_error(expr, "bad member name");

@@ -2035,11 +2077,11 @@
         examine_symbol_type(ctype);
         address_space = ctype->ctype.as;
         mod = ctype->ctype.modifiers;
         if (ctype->type == SYM_NODE) {
                 ctype = ctype->ctype.base_type;
-                address_space |= ctype->ctype.as;
+                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;

@@ -2172,22 +2214,54 @@
                 if (Wpointer_arith)
                         warning(expr->pos, "expression using sizeof(void)");
                 size = bits_in_char;
         }
 
-        if (size == 1 && is_bool_type(type)) {
+        if (is_bool_type(type)) {
                 if (Wsizeof_bool)
-                        warning(expr->pos, "expression using sizeof bool");
-                size = bits_in_char;
+                        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);

@@ -2845,17 +2919,17 @@
         return flags;
 }
 
 static struct symbol *evaluate_cast(struct expression *expr)
 {
-        struct expression *target = expr->cast_expression;
+        struct expression *source = expr->cast_expression;
         struct symbol *ctype;
-        struct symbol *t1, *t2;
-        int class1, class2;
-        int as1 = 0, as2 = 0;
+        struct symbol *ttype, *stype;
+        int tclass, sclass;
+        struct ident *tas = NULL, *sas = NULL;
 
-        if (!target)
+        if (!source)
                 return NULL;
 
         /*
          * Special case: a cast can be followed by an
          * initializer, in which case we need to pass

@@ -2864,15 +2938,15 @@
          *
          * A more complex case is when the initializer is
          * dereferenced as part of a post-fix expression.
          * We need to produce an expression that can be dereferenced.
          */
-        if (target->type == EXPR_INITIALIZER) {
+        if (source->type == EXPR_INITIALIZER) {
                 struct symbol *sym = expr->cast_type;
                 struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
 
-                sym->initializer = target;
+                sym->initializer = source;
                 evaluate_symbol(sym);
 
                 addr->ctype = &lazy_ptr_ctype;  /* Lazy eval */
                 addr->symbol = sym;
                 if (sym->ctype.modifiers & MOD_TOPLEVEL)

@@ -2888,100 +2962,119 @@
 
         ctype = examine_symbol_type(expr->cast_type);
         expr->ctype = ctype;
         expr->cast_type = ctype;
 
-        evaluate_expression(target);
-        degenerate(target);
+        evaluate_expression(source);
+        degenerate(source);
 
-        class1 = classify_type(ctype, &t1);
+        tclass = classify_type(ctype, &ttype);
 
-        expr->flags = cast_flags(expr, target);
+        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 (t1 == &void_ctype)
+        if (ttype == &void_ctype)
                 goto out;
 
-        if (class1 & (TYPE_COMPOUND | TYPE_FN))
-                warning(expr->pos, "cast to non-scalar");
-
-        t2 = target->ctype;
-        if (!t2) {
+        stype = source->ctype;
+        if (!stype) {
                 expression_error(expr, "cast from unknown type");
                 goto out;
         }
-        class2 = classify_type(t2, &t2);
+        sclass = classify_type(stype, &stype);
 
-        if (class2 & TYPE_COMPOUND)
-                warning(expr->pos, "cast from non-scalar");
-
         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 (class2 & TYPE_FOULED)
-                t2 = unfoul(t2);
+        if (sclass & TYPE_FOULED)
+                stype = unfoul(stype);
 
-        if (t1 != t2) {
-                if ((class1 & TYPE_RESTRICT) && restricted_value(target, t1))
+        if (ttype != stype) {
+                if ((tclass & TYPE_RESTRICT) && restricted_value(source, ttype))
                         warning(expr->pos, "cast to %s",
-                                show_typename(t1));
-                if (class2 & TYPE_RESTRICT) {
-                        if (t1 == &bool_ctype) {
-                                if (class2 & TYPE_FOULED)
+                                show_typename(ttype));
+                if (sclass & TYPE_RESTRICT) {
+                        if (ttype == &bool_ctype) {
+                                if (sclass & TYPE_FOULED)
                                         warning(expr->pos, "%s degrades to integer",
-                                                show_typename(t2));
+                                                show_typename(stype));
                         } else {
                                 warning(expr->pos, "cast from %s",
-                                        show_typename(t2));
+                                        show_typename(stype));
                         }
                 }
         }
 
-        if (t1 == &ulong_ctype)
-                as1 = -1;
-        else if (class1 == TYPE_PTR) {
-                examine_pointer_target(t1);
-                as1 = t1->ctype.as;
+        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 (t2 == &ulong_ctype)
-                as2 = -1;
-        else if (class2 == TYPE_PTR) {
-                examine_pointer_target(t2);
-                as2 = t2->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 (!as1 && as2 > 0)
-                warning(expr->pos, "cast removes address space of expression");
-        if (as1 > 0 && as2 > 0 && as1 != as2)
-                warning(expr->pos, "cast between address spaces (<asn:%d>-><asn:%d>)", as2, as1);
-        if (as1 > 0 && !as2 &&
-            !is_null_pointer_constant(target) && Wcast_to_as)
+        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 to expression (<asn:%d>)", as1);
+                        "cast adds address space '%s' to expression", show_as(tas));
 
-        if (!(t1->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR &&
-            !as1 && (target->flags & CEF_ICE)) {
-                if (t1->ctype.base_type == &void_ctype) {
-                        if (is_zero_constant(target)) {
+        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 (t1 == &bool_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;
 }
 
 /*

@@ -3181,33 +3274,33 @@
         case EXPR_STRING:
                 return evaluate_string(expr);
         case EXPR_SYMBOL:
                 return evaluate_symbol_expression(expr);
         case EXPR_BINOP:
-                if (!evaluate_expression(expr->left))
+                evaluate_expression(expr->left);
+                evaluate_expression(expr->right);
+                if (!valid_subexpr_type(expr))
                         return NULL;
-                if (!evaluate_expression(expr->right))
-                        return NULL;
                 return evaluate_binop(expr);
         case EXPR_LOGICAL:
                 return evaluate_logical(expr);
         case EXPR_COMMA:
                 evaluate_expression(expr->left);
                 if (!evaluate_expression(expr->right))
                         return NULL;
                 return evaluate_comma(expr);
         case EXPR_COMPARE:
-                if (!evaluate_expression(expr->left))
+                evaluate_expression(expr->left);
+                evaluate_expression(expr->right);
+                if (!valid_subexpr_type(expr))
                         return NULL;
-                if (!evaluate_expression(expr->right))
-                        return NULL;
                 return evaluate_compare(expr);
         case EXPR_ASSIGNMENT:
-                if (!evaluate_expression(expr->left))
+                evaluate_expression(expr->left);
+                evaluate_expression(expr->right);
+                if (!valid_subexpr_type(expr))
                         return NULL;
-                if (!evaluate_expression(expr->right))
-                        return NULL;
                 return evaluate_assignment(expr);
         case EXPR_PREOP:
                 if (!evaluate_expression(expr->unop))
                         return NULL;
                 return evaluate_preop(expr);

@@ -3258,15 +3351,18 @@
                 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;
 }
 
-static void check_duplicates(struct symbol *sym)
+void check_duplicates(struct symbol *sym)
 {
         int declared = 0;
         struct symbol *next = sym;
         int initialized = sym->initializer != NULL;
 

@@ -3289,11 +3385,11 @@
                         return;
                 }
         }
         if (!declared) {
                 unsigned long mod = sym->ctype.modifiers;
-                if (mod & (MOD_STATIC | MOD_REGISTER))
+                if (mod & (MOD_STATIC | MOD_REGISTER | MOD_EXT_VISIBLE))
                         return;
                 if (!(mod & MOD_TOPLEVEL))
                         return;
                 if (!Wdecl)
                         return;

@@ -3420,71 +3516,54 @@
 }
 
 static void evaluate_asm_statement(struct statement *stmt)
 {
         struct expression *expr;
+        struct expression *op;
         struct symbol *sym;
-        int state;
 
         expr = stmt->asm_string;
         if (!expr || expr->type != EXPR_STRING) {
                 sparse_error(stmt->pos, "need constant string for inline asm");
                 return;
         }
 
-        state = 0;
-        FOR_EACH_PTR(stmt->asm_outputs, expr) {
-                switch (state) {
-                case 0: /* Identifier */
-                        state = 1;
-                        continue;
+        FOR_EACH_PTR(stmt->asm_outputs, op) {
+                /* Identifier */
 
-                case 1: /* Constraint */
-                        state = 2;
+                /* Constraint */
+                expr = op->constraint;
                         if (!expr || expr->type != EXPR_STRING) {
                                 sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string");
-                                *THIS_ADDRESS(expr) = NULL;
-                                continue;
-                        }
+                        op->constraint = NULL;
+                } else
                         verify_output_constraint(expr, expr->string->data);
-                        continue;
 
-                case 2: /* Expression */
-                        state = 0;
+                /* 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);
-                        continue;
-                }
-        } END_FOR_EACH_PTR(expr);
+        } END_FOR_EACH_PTR(op);
 
-        state = 0;
-        FOR_EACH_PTR(stmt->asm_inputs, expr) {
-                switch (state) {
-                case 0: /* Identifier */
-                        state = 1;
-                        continue;
+        FOR_EACH_PTR(stmt->asm_inputs, op) {
+                /* Identifier */
 
-                case 1: /* Constraint */
-                        state = 2;
+                /* Constraint */
+                expr = op->constraint;
                         if (!expr || expr->type != EXPR_STRING) {
                                 sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string");
-                                *THIS_ADDRESS(expr) = NULL;
-                                continue;
-                        }
+                        op->constraint = NULL;
+                } else
                         verify_input_constraint(expr, expr->string->data);
-                        continue;
 
-                case 2: /* Expression */
-                        state = 0;
-                        if (!evaluate_expression(expr))
+                /* Expression */
+                if (!evaluate_expression(op->expr))
                                 return;
-                        continue;
-                }
-        } END_FOR_EACH_PTR(expr);
+        } END_FOR_EACH_PTR(op);
 
         FOR_EACH_PTR(stmt->asm_clobbers, expr) {
                 if (!expr) {
                         sparse_error(stmt->pos, "bad asm clobbers");
                         return;

@@ -3580,11 +3659,11 @@
 
 static void evaluate_goto_statement(struct statement *stmt)
 {
         struct symbol *label = stmt->goto_label;
 
-        if (label && !label->stmt && !lookup_keyword(label->ident, NS_KEYWORD))
+        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);
 }