[PATCH 1/3] enum: keep enumerators as int if they fit

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux