aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLinus Torvalds <torvalds@penguin.transmeta.com>2003-04-08 17:29:52 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-07 21:00:21 -0700
commit50c89ca0b56c9cc7ed54fddb80e368af99a8f019 (patch)
tree2fe8737b0c36457b8e164b5ad0029d573ecfa632
parent32ebb3c8c74527a0ac468d622581c88497fca4a6 (diff)
downloadsparse-dev-50c89ca0b56c9cc7ed54fddb80e368af99a8f019.tar.gz
Ignore sign differences for "same type". Make the
type check return a description of the difference in types. Make "addressof(symbol)" peel off the SYM_NODE, and put the information in the pointer node instead.
-rw-r--r--evaluate.c88
1 files changed, 51 insertions, 37 deletions
diff --git a/evaluate.c b/evaluate.c
index cca1c011..07b48adf 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -373,11 +373,9 @@ static struct symbol *evaluate_add(struct expression *expr)
return evaluate_int_binop(expr);
}
-static int same_type(struct symbol *target, struct symbol *source,
+static const char * type_difference(struct symbol *target, struct symbol *source,
unsigned long target_mod_ignore, unsigned long source_mod_ignore)
{
- struct position pos = source->pos;
- int dropped_modifiers = 0;
for (;;) {
unsigned long mod1, mod2, diff;
unsigned long as1, as2;
@@ -385,7 +383,7 @@ static int same_type(struct symbol *target, struct symbol *source,
if (target == source)
break;
if (!target || !source)
- return 0;
+ return "different types";
/*
* Peel of per-node information.
* FIXME! Check alignment, address space, and context too here!
@@ -405,19 +403,6 @@ static int same_type(struct symbol *target, struct symbol *source,
as2 |= source->ctype.as;
}
- /* Ignore differences in storage types or addressability */
- diff = (mod1 ^ mod2) & ~(MOD_STORAGE | MOD_ADDRESSABLE);
- if (diff) {
- mod1 &= diff & ~target_mod_ignore;
- mod2 &= diff & ~source_mod_ignore;
- if (mod1 | mod2)
- return 0;
- }
-
- /* Must be same address space to be comparable */
- if (as1 != as2)
- return 0;
-
if (target->type != source->type) {
int type1 = target->type;
int type2 = source->type;
@@ -426,15 +411,26 @@ static int same_type(struct symbol *target, struct symbol *source,
type1 = type1 == SYM_ARRAY ? SYM_PTR : type1;
type2 = type2 == SYM_ARRAY ? SYM_PTR : type2;
if (type1 != type2)
- return 0;
+ return "different base types";
+ }
+
+ /* Must be same address space to be comparable */
+ if (as1 != as2)
+ return "different address spaces";
+
+ /* Ignore differences in storage types, sign, or addressability */
+ diff = (mod1 ^ mod2) & ~(MOD_STORAGE | MOD_ADDRESSABLE | MOD_SIGNED | MOD_UNSIGNED);
+ if (diff) {
+ mod1 &= diff & ~target_mod_ignore;
+ mod2 &= diff & ~source_mod_ignore;
+ if (mod1 | mod2)
+ return "different modifiers";
}
target = target->ctype.base_type;
source = source->ctype.base_type;
}
- if (dropped_modifiers)
- warn(pos, "assignment drops modifiers");
- return 1;
+ return NULL;
}
static struct symbol *common_ptr_type(struct expression *l, struct expression *r)
@@ -455,6 +451,7 @@ static struct symbol *common_ptr_type(struct expression *l, struct expression *r
static struct symbol *evaluate_ptr_sub(struct expression *expr, struct expression *l, struct expression *r)
{
+ const char *typediff;
struct symbol *ctype;
struct symbol *ltype = l->ctype, *rtype = r->ctype;
@@ -466,10 +463,11 @@ static struct symbol *evaluate_ptr_sub(struct expression *expr, struct expressio
return evaluate_ptr_add(expr, l, r);
ctype = ltype;
- if (!same_type(ltype, rtype, MOD_IGN, MOD_IGN)) {
+ typediff = type_difference(ltype, rtype, MOD_IGN, MOD_IGN);
+ if (typediff) {
ctype = common_ptr_type(l, r);
if (!ctype) {
- warn(expr->pos, "subtraction of different types can't work");
+ warn(expr->pos, "subtraction of different types can't work (%s)", typediff);
return NULL;
}
}
@@ -662,6 +660,7 @@ static struct symbol * evaluate_conditional(struct expression *expr)
{
struct expression *cond, *true, *false;
struct symbol *ctype, *ltype, *rtype;
+ const char * typediff;
cond = expr->conditional;
true = expr->cond_true ? : cond;
@@ -671,12 +670,13 @@ static struct symbol * evaluate_conditional(struct expression *expr)
rtype = false->ctype;
ctype = ltype;
- if (!same_type(ltype, rtype, MOD_IGN, MOD_IGN)) {
+ typediff = type_difference(ltype, rtype, MOD_IGN, MOD_IGN);
+ if (typediff) {
ctype = compatible_integer_binop(expr, &true, &expr->cond_false);
if (!ctype) {
ctype = compatible_ptr_type(true, expr->cond_false);
if (!ctype) {
- warn(expr->pos, "incompatible types in conditional expression");
+ warn(expr->pos, "incompatible types in conditional expression (%s)", typediff);
return NULL;
}
}
@@ -695,8 +695,11 @@ static struct symbol * evaluate_conditional(struct expression *expr)
static int compatible_assignment_types(struct expression *expr, struct symbol *target,
struct expression **rp, struct symbol *source, const char *where)
{
+ const char *typediff;
+
/* It's ok if the target is more volatile or const than the source */
- if (same_type(target, source, MOD_VOLATILE | MOD_CONST, 0))
+ typediff = type_difference(target, source, MOD_VOLATILE | MOD_CONST, 0);
+ if (!typediff)
return 1;
if (compatible_integer_types(target, source)) {
@@ -723,10 +726,16 @@ static int compatible_assignment_types(struct expression *expr, struct symbol *t
target = target_base;
target_base = target->ctype.base_type;
}
- if (source->type == SYM_ARRAY && same_type(target_base, source_base, MOD_IGN, MOD_IGN))
- return 1;
- if (source->type == SYM_FN && same_type(target_base, source, MOD_IGN, MOD_IGN))
- return 1;
+ if (source->type == SYM_ARRAY) {
+ const char *typediff = type_difference(target_base, source_base, MOD_IGN, MOD_IGN);
+ if (!typediff)
+ return 1;
+ }
+ if (source->type == SYM_FN) {
+ const char *typediff = type_difference(target_base, source, MOD_IGN, MOD_IGN);
+ if (!typediff)
+ return 1;
+ }
// NULL pointer?
if (right->type == EXPR_VALUE && !right->value)
@@ -738,17 +747,17 @@ static int compatible_assignment_types(struct expression *expr, struct symbol *t
struct symbol *target_base = target->ctype.base_type;
if (source_base == &void_ctype || target_base == &void_ctype)
return 1;
- warn(expr->pos, "incorrect type in %s", where);
+ warn(expr->pos, "incorrect type in %s (%s)", where, typediff);
return 1;
}
// FIXME!! Cast it!
- warn(expr->pos, "different types in %s", where);
+ warn(expr->pos, "different types in %s (%s)", where, typediff);
return 0;
}
// FIXME!! Cast it?
- warn(expr->pos, "incorrect type in %s", where);
+ warn(expr->pos, "incorrect type in %s (%s)", where, typediff);
warn(expr->pos, " expected %s", show_typename(target));
warn(expr->pos, " got %s", show_typename(source));
return 0;
@@ -820,6 +829,10 @@ static struct symbol *evaluate_addressof(struct expression *expr)
return NULL;
}
+ symbol = alloc_symbol(expr->pos, SYM_PTR);
+ symbol->ctype.alignment = POINTER_ALIGNMENT;
+ symbol->bit_size = BITS_IN_POINTER;
+
ctype = op->ctype;
if (ctype->type == SYM_NODE) {
ctype->ctype.modifiers |= MOD_ADDRESSABLE;
@@ -827,13 +840,14 @@ static struct symbol *evaluate_addressof(struct expression *expr)
warn(expr->pos, "taking address of 'register' variable '%s'", show_ident(ctype->ident));
ctype->ctype.modifiers &= ~MOD_REGISTER;
}
+ symbol->ctype.modifiers = ctype->ctype.modifiers;
+ symbol->ctype.as = ctype->ctype.as;
+ symbol->ctype.context = ctype->ctype.context;
+ symbol->ctype.contextmask = ctype->ctype.contextmask;
+ ctype = ctype->ctype.base_type;
}
- symbol = alloc_symbol(expr->pos, SYM_PTR);
symbol->ctype.base_type = ctype;
- symbol->ctype.alignment = POINTER_ALIGNMENT;
- symbol->bit_size = BITS_IN_POINTER;
-
*expr = *op->unop;
expr->ctype = symbol;
return symbol;