 compile-i386.c | 10 ----------
 evaluate.c     | 30 +++++++++++++++++++++++++-----
 show-parse.c   |  9 ---------
 symbol.h       |  1 +
 4 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/compile-i386.c b/compile-i386.c
index b47095252053..31d3dbca1060 100644
--- a/compile-i386.c
+++ b/compile-i386.c
@@ -176,7 +176,6 @@ static const char *current_section;
 static void emit_comment(const char * fmt, ...) FORMAT_ATTR(1);
 static void emit_move(struct storage *src, struct storage *dest,
 		      struct symbol *ctype, const char *comment);
-static int type_is_signed(struct symbol *sym);
 static struct storage *x86_address_gen(struct expression *expr);
 static struct storage *x86_symbol_expr(struct symbol *sym);
 static void x86_symbol(struct symbol *sym);
@@ -2250,15 +2249,6 @@ static void x86_symbol_init(struct symbol *sym)
 	priv->addr = new;
 }
 
-static int type_is_signed(struct symbol *sym)
-{
-	if (sym->type == SYM_NODE)
-		sym = sym->ctype.base_type;
-	if (sym->type == SYM_PTR)
-		return 0;
-	return !(sym->ctype.modifiers & MOD_UNSIGNED);
-}
-
 static struct storage *x86_label_expr(struct expression *expr)
 {
 	struct storage *new = stack_alloc(4);
diff --git a/evaluate.c b/evaluate.c
index 99dedb5c5bde..5c49c9c92a69 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -31,6 +31,15 @@ struct symbol *current_fn;
 static struct symbol *degenerate(struct expression *expr);
 static struct symbol *evaluate_symbol(struct symbol *sym);
 
+int type_is_signed(struct symbol *sym)
+{
+	if (sym->type == SYM_NODE)
+		sym = sym->ctype.base_type;
+	if (sym->type == SYM_PTR)
+		return 0;
+	return !(sym->ctype.modifiers & MOD_UNSIGNED);
+}
+
 static struct symbol *evaluate_symbol_expression(struct expression *expr)
 {
 	struct expression *addr;
@@ -282,12 +291,18 @@ static struct expression * cast_to(struct expression *old, struct symbol *type)
 	 */
 	switch (old->type) {
 	case EXPR_PREOP:
-		if (old->ctype->bit_size < type->bit_size)
+		if (old->op == '~' || old->op == '-') {
+			if (old->ctype->bit_size > type->bit_size) {
+				old->ctype = type;
+				old->unop = cast_to(old->unop, type);
+				return old;
+			}
+			if (old->ctype->bit_size == type->bit_size)
+				break;
+			if (type_is_signed(old->ctype))
+				break;
+			warning(old->pos, "implicit unsigned widening cast of a '%c' expression", old->op);
 			break;
-		if (old->op == '~') {
-			old->ctype = type;
-			old->unop = cast_to(old->unop, type);
-			return old;
 		}
 		break;
 
@@ -310,6 +325,7 @@ static struct expression * cast_to(struct expression *old, struct symbol *type)
 		/* nothing */;
 	}
 
+
 	expr = alloc_expression(old->pos, EXPR_IMPLIED_CAST);
 	expr->flags = old->flags;
 	expr->ctype = type;
@@ -1757,6 +1773,10 @@ Normal:
 	}
 	if (expr->op == '+')
 		*expr = *expr->unop;
+	else if (expr->unop->type == EXPR_PREOP && expr->unop->op == expr->op) {
+		if (expr->unop->ctype == ctype)
+			*expr = *expr->unop->unop;
+	}
 	expr->ctype = ctype;
 	return ctype;
 Restr:
diff --git a/show-parse.c b/show-parse.c
index 1333e301c151..c8e864476fac 100644
--- a/show-parse.c
+++ b/show-parse.c
@@ -933,15 +933,6 @@ static int show_symbol_init(struct symbol *sym)
 	return 0;
 }
 
-static int type_is_signed(struct symbol *sym)
-{
-	if (sym->type == SYM_NODE)
-		sym = sym->ctype.base_type;
-	if (sym->type == SYM_PTR)
-		return 0;
-	return !(sym->ctype.modifiers & MOD_UNSIGNED);
-}
-
 static int show_cast_expr(struct expression *expr)
 {
 	struct symbol *old_type, *new_type;
diff --git a/symbol.h b/symbol.h
index 1e745799a8d0..6928faf4fec6 100644
--- a/symbol.h
+++ b/symbol.h
@@ -389,5 +389,6 @@ extern int is_ptr_type(struct symbol *);
 
 void create_fouled(struct symbol *type);
 struct symbol *befoul(struct symbol *type);
+int type_is_signed(struct symbol *sym);
 
 #endif /* SYMBOL_H */
