diff mbox

[9/9] enum: rewrite bound checking

Message ID 20180509234853.20821-10-luc.vanoostenryck@gmail.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Luc Van Oostenryck May 9, 2018, 11:48 p.m. UTC
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 to be much 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@gmail.com>
---
 parse.c | 83 +++++++++++++++++++++++----------------------------------
 1 file changed, 33 insertions(+), 50 deletions(-)
diff mbox

Patch

diff --git a/parse.c b/parse.c
index 4e853d1b9..03611c140 100644
--- a/parse.c
+++ b/parse.c
@@ -763,36 +763,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;
-}
-
 ///
 // rshift() - a 'safe' right shift.
 //	This allow to use a shift amount as big (or bigger)
@@ -805,18 +775,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)
@@ -840,7 +831,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;
@@ -919,15 +910,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;
 
@@ -943,17 +926,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;