diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-05-08 03:23:16 +0200 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-10-05 03:29:19 +0200 |
commit | 93e27240be709db220629c1b198b1461f6b05ddc (patch) | |
tree | e49440c886764a600f21c96ac318b67a6389d39f | |
parent | 89e7785477a5270bba4e5f0b7b59c363659412f7 (diff) | |
download | sparse-93e27240be709db220629c1b198b1461f6b05ddc.tar.gz |
enum: rewrite bound checking
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 more complex than needed.
It's now simplified like this:
-) 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>
-rw-r--r-- | parse.c | 84 |
1 files changed, 34 insertions, 50 deletions
@@ -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,40 @@ 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, unsigned long long uval, struct symbol *vtype) +{ + long long sval = uval; + + if (is_signed_type(vtype) && (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 +845,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 +924,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, lastval, ctype); } token = next; @@ -956,17 +940,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; |