diff options
author | 2007-07-10 14:24:55 -0400 | |
---|---|---|
committer | 2007-07-14 12:16:52 -0700 | |
commit | b1bb92a1b27673988c8561b42b69e7acbc7cbaf3 (patch) | |
tree | 1bf3026b0cc93b5c23feab48e6e07700efa8a35d /evaluate.c | |
parent | [PATCH] start cleaning type_difference() (diff) | |
download | sparse-b1bb92a1b27673988c8561b42b69e7acbc7cbaf3.tar.gz sparse-b1bb92a1b27673988c8561b42b69e7acbc7cbaf3.tar.bz2 sparse-b1bb92a1b27673988c8561b42b69e7acbc7cbaf3.zip |
[PATCH] get compatible_assignment_types() deal with all cases
a) pointer to _Bool is OK
b) struct to same struct or union to same union is OK; void to void etc. are not
c) to/from void * with loss of qualifiers or with different address space
should give the right warning itself instead of "different base types"
it would get from fallback to type_difference()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'evaluate.c')
-rw-r--r-- | evaluate.c | 57 |
1 files changed, 43 insertions, 14 deletions
@@ -1259,11 +1259,17 @@ static int compatible_assignment_types(struct expression *expr, struct symbol *t goto Cast; if (!restricted_value(*rp, target)) return 1; + if (s == t) + return 1; } else if (!(sclass & TYPE_RESTRICT)) goto Cast; + typediff = "different base types"; + goto Err; } - if (tclass & TYPE_PTR) { + 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) { @@ -1271,29 +1277,52 @@ static int compatible_assignment_types(struct expression *expr, struct symbol *t bad_null(*rp); goto Cast; } - if (sclass & TYPE_PTR && t->ctype.as == s->ctype.as) { - /* we should be more lazy here */ - int mod1 = t->ctype.modifiers; - int mod2 = s->ctype.modifiers; - s = get_base_type(s); - t = get_base_type(t); - + if (!(sclass & TYPE_PTR)) { + typediff = "different base types"; + goto Err; + } + /* we should be more lazy here */ + mod1 = t->ctype.modifiers; + mod2 = s->ctype.modifiers; + b1 = get_base_type(t); + b2 = get_base_type(s); + if (b1 == &void_ctype || b2 == &void_ctype) { /* * assignments to/from void * are OK, provided that * we do not remove qualifiers from pointed to [C] * or mix address spaces [sparse]. */ - if (!(mod2 & ~mod1 & (MOD_VOLATILE | MOD_CONST))) - if (s == &void_ctype || t == &void_ctype) - goto Cast; + if (t->ctype.as != s->ctype.as) { + typediff = "different address spaces"; + goto Err; + } + if (mod2 & ~mod1 & MOD_IGN) { + typediff = "different modifiers"; + goto Err; + } + goto Cast; } + /* It's OK if the target is more volatile or const than the source */ + typediff = type_difference(target, source, + MOD_VOLATILE | MOD_CONST, 0); + if (typediff) + goto Err; + return 1; } - /* It's OK if the target is more volatile or const than the source */ - typediff = type_difference(target, source, MOD_VOLATILE | MOD_CONST, 0); - if (!typediff) + 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"; + goto Err; + } + typediff = "invalid types"; + +Err: 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)); |