In Standard C, enumerators have type 'int' and an unspecified base type. OTOH, GCC (and thus sparse) llows any integer type (and sparse also more or less allows bitwise types). After the enum's decalration is parsed, the enumerators are converted to the underlying type. Also, GCC (and thus sparse) uses an unsigned type unless one of the enumerators have a negative value. This is a problem, though, because when comparing simple integers with simple enumerators like: enum e { OK, ONE, TWO }; the integers will unexpectedly be promoted to unsigned. GCC avoid these promotions by not converting the enumerators that fit in an int. For GCC compatibility, do the same: do not convert enumerators that fit in an int. Note: this is somehow hackish but without this some enum usages in the kernel give useless warnings with sparse. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- parse.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/parse.c b/parse.c index 231d4051a..8ccfdea20 100644 --- a/parse.c +++ b/parse.c @@ -824,16 +824,53 @@ static int type_is_ok(struct symbol *type, struct range range) return 1; } +static struct range type_range(struct symbol *type) +{ + struct range range; + unsigned int size = type->bit_size; + unsigned long long max; + long long min; + + if (is_signed_type(type)) { + min = sign_bit(size); + max = min - 1; + } else { + min = 0; + max = bits_mask(size); + } + + range.pos = max; + range.neg = min; + return range; +} + +static int val_in_range(struct range *range, long long sval, struct symbol *vtype) +{ + unsigned long long uval = sval; + + if (is_signed_type(vtype) && (sval < 0)) + return range->neg <= sval; + else + return uval <= range->pos; +} + static void cast_enum_list(struct symbol_list *list, struct symbol *base_type) { + struct range irange = type_range(&int_ctype); struct symbol *sym; FOR_EACH_PTR(list, sym) { struct expression *expr = sym->initializer; struct symbol *ctype; + long long val; if (expr->type != EXPR_VALUE) continue; ctype = expr->ctype; + val = get_expression_value(expr); + if (is_int_type(ctype) && val_in_range(&irange, val, ctype)) { + expr->ctype = &int_ctype; + continue; + } expr->ctype = base_type; if (ctype->bit_size == base_type->bit_size) continue; -- 2.19.0