summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-10-02 15:21:39 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-10-05 03:29:20 +0200
commitd39fc24d828166e7e2db63b9ab96a26552727f11 (patch)
treee0aab35e8efe54a68e1a99031b25dcebc0b8cc95
parent93e27240be709db220629c1b198b1461f6b05ddc (diff)
downloadsparse-d39fc24d828166e7e2db63b9ab96a26552727f11.tar.gz
enum: keep enumerators as int if they fit
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@gmail.com>
-rw-r--r--parse.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/parse.c b/parse.c
index 231d4051..8ccfdea2 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;