[PATCH 12/12] enum: rewrite bound checking

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

 



To determine the base type of enums it is needed to keep
track of the range that the enumerators can take.

However, this tracking seems is more complex than needed.
It's now simplified like the following:
-) a single 'struct range' keep track of the biggest positive
   value and the smallest negative one (if any)
-) the bound checking in itself is then quite similar to
   what was already done:
   *) adjust the bit size if the type is negative
   *) check that the positive bound is in range
   *) if the type is unsigned
	-> check that the negative bound is 0
   *) if the type is signed
	-> check that the negative bound is in range

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx>
---
 parse.c | 83 +++++++++++++++++++++++----------------------------------
 1 file changed, 33 insertions(+), 50 deletions(-)

diff --git a/parse.c b/parse.c
index 41d5fd93a..d104d9dcb 100644
--- a/parse.c
+++ b/parse.c
@@ -775,36 +775,6 @@ static struct token *union_specifier(struct token *token, struct decl_state *ctx
 	return struct_union_enum_specifier(SYM_UNION, token, ctx, parse_union_declaration);
 }
 
-
-typedef struct {
-	int x;
-	unsigned long long y;
-} Num;
-
-static void upper_boundary(Num *n, Num *v)
-{
-	if (n->x > v->x)
-		return;
-	if (n->x < v->x) {
-		*n = *v;
-		return;
-	}
-	if (n->y < v->y)
-		n->y = v->y;
-}
-
-static void lower_boundary(Num *n, Num *v)
-{
-	if (n->x < v->x)
-		return;
-	if (n->x > v->x) {
-		*n = *v;
-		return;
-	}
-	if (n->y > v->y)
-		n->y = v->y;
-}
-
 ///
 // safe right shift
 //
@@ -818,18 +788,39 @@ static unsigned long long rshift(unsigned long long val, unsigned int n)
 	return val >> n;
 }
 
-static int type_is_ok(struct symbol *type, Num *upper, Num *lower)
+struct range {
+	long long		neg;
+	unsigned long long	pos;
+};
+
+static void update_range(struct range *range, struct symbol *type, unsigned long long uval)
+{
+	long long sval = uval;
+	if (is_signed_type(type) && (sval < 0)) {
+		if (sval < range->neg)
+			range->neg = sval;
+	} else {
+		if (uval > range->pos)
+			range->pos = uval;
+	}
+}
+
+static int type_is_ok(struct symbol *type, struct range range)
 {
 	int shift = type->bit_size;
 	int is_unsigned = type->ctype.modifiers & MOD_UNSIGNED;
 
 	if (!is_unsigned)
 		shift--;
-	if (upper->x == 0 && rshift(upper->y, shift))
+	if (rshift(range.pos, shift))
 		return 0;
-	if (lower->x == 0 || (!is_unsigned && rshift(~lower->y, shift) == 0))
+	if (range.neg == 0)
 		return 1;
-	return 0;
+	if (is_unsigned)
+		return 0;
+	if (rshift(~range.neg, shift))
+		return 0;
+	return 1;
 }
 
 static void cast_enum_list(struct symbol_list *list, struct symbol *base_type)
@@ -853,7 +844,7 @@ static struct token *parse_enum_declaration(struct token *token, struct symbol *
 {
 	unsigned long long lastval = 0;
 	struct symbol *ctype = NULL, *base_type = NULL;
-	Num upper = {-1, 0}, lower = {1, 0};
+	struct range range = { };
 	int mix_bitwise = 0;
 
 	parent->examined = 1;
@@ -932,15 +923,7 @@ static struct token *parse_enum_declaration(struct token *token, struct symbol *
 			parent->ctype.base_type = base_type;
 		}
 		if (is_int_type(base_type)) {
-			Num v = {.y = lastval};
-			if (ctype->ctype.modifiers & MOD_UNSIGNED)
-				v.x = 0;
-			else if ((long long)lastval >= 0)
-				v.x = 0;
-			else
-				v.x = -1;
-			upper_boundary(&upper, &v);
-			lower_boundary(&lower, &v);
+			update_range(&range, ctype, lastval);
 		}
 		token = next;
 
@@ -956,17 +939,17 @@ static struct token *parse_enum_declaration(struct token *token, struct symbol *
 	}
 	else if (!is_int_type(base_type))
 		base_type = base_type;
-	else if (type_is_ok(&int_ctype, &upper, &lower))
+	else if (type_is_ok(&int_ctype, range))
 		base_type = &int_ctype;
-	else if (type_is_ok(&uint_ctype, &upper, &lower))
+	else if (type_is_ok(&uint_ctype, range))
 		base_type = &uint_ctype;
-	else if (type_is_ok(&long_ctype, &upper, &lower))
+	else if (type_is_ok(&long_ctype, range))
 		base_type = &long_ctype;
-	else if (type_is_ok(&ulong_ctype, &upper, &lower))
+	else if (type_is_ok(&ulong_ctype, range))
 		base_type = &ulong_ctype;
-	else if (type_is_ok(&llong_ctype, &upper, &lower))
+	else if (type_is_ok(&llong_ctype, range))
 		base_type = &llong_ctype;
-	else if (type_is_ok(&ullong_ctype, &upper, &lower))
+	else if (type_is_ok(&ullong_ctype, range))
 		base_type = &ullong_ctype;
 	else
 		base_type = &bad_ctype;
-- 
2.18.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