AFAICS, that should do null pointer constants right.  We assign
special instance of void * (&null_ctype) to (void *)<zero integer
constant expression> and replace it with normal void * when we
don't want null pointer constant.  is_zero_constant() checks if
we have an integer constant expression, does conservative expand
(i.e. instead of generating an error on 1/0, etc. leaves the
node unreplaced) and checks if we have reduced the sucker to
EXPR_VALUE[0] without comma taint.

Implemented all (AFAICS) special cases involving null pointer
constants; most changes in evaluate_compare() and evaluate_conditional().
Both are still incomplete; handling of qualifiers is still missing,
but that's a separate story.

Note that we get two new sets of warnings on the kernel build; one is
due to wrong size_t (handled in the next patch; didn't show up until
now since we didn't warn on comparison of pointers to incompatible
types) and another is a pile of warnings about integer 0 used as NULL
on
        if (p == 0)
where p is a pointer.  Additionally, there's an idiotic
        (p>0)
in one place (again, p is a pointer).  Bugger if I know how gcc doesn't
warn on that one, it's certainly a standard violation and bloody pointless
even as extension...

Signed-off-by: Al Viro <[EMAIL PROTECTED]>
---
 evaluate.c   |  216 +++++++++++++++++++++++++++++++++++++++-------------------
 expand.c     |   38 +++++++---
 expression.h |    1 +
 symbol.c     |    4 +-
 symbol.h     |    3 +-
 5 files changed, 178 insertions(+), 84 deletions(-)

diff --git a/evaluate.c b/evaluate.c
index 3156e9d..b97a4d7 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -274,7 +274,7 @@ static struct expression * cast_to(struct expression *old, 
struct symbol *type)
 
        warn_for_different_enum_types (old->pos, old->ctype, type);
 
-       if (is_same_type(old, type))
+       if (old->ctype != &null_ctype && is_same_type(old, type))
                return old;
 
        /*
@@ -567,6 +567,9 @@ static struct symbol *evaluate_ptr_add(struct expression 
*expr, struct symbol *c
        int multiply;
        int bit_size;
 
+       if (ctype == &null_ctype)
+               ctype = &ptr_ctype;
+
        examine_symbol_type(ctype);
 
        if (!ctype->ctype.base_type) {
@@ -784,13 +787,10 @@ const char * type_difference(struct symbol *target, 
struct symbol *source,
        return NULL;
 }
 
-static int is_null_ptr(struct expression *expr)
+static void bad_null(struct expression *expr)
 {
-       if (expr->type != EXPR_VALUE || expr->value)
-               return 0;
-       if (Wnon_pointer_null && !is_ptr_type(expr->ctype))
+       if (Wnon_pointer_null)
                warning(expr->pos, "Using plain integer as NULL pointer");
-       return 1;
 }
 
 /*
@@ -973,12 +973,23 @@ static int modify_for_unsigned(int op)
        return op;
 }
 
+static inline int is_null_pointer_constant(struct expression *e)
+{
+       if (e->ctype == &null_ctype)
+               return 1;
+       if (!(e->flags & Int_const_expr))
+               return 0;
+       return is_zero_constant(e) ? 2 : 0;
+}
+
 static struct symbol *evaluate_compare(struct expression *expr)
 {
        struct expression *left = expr->left, *right = expr->right;
-       struct symbol *ltype = left->ctype, *rtype = right->ctype;
+       struct symbol *ltype, *rtype;
+       int lclass = classify_type(degenerate(left), &ltype);
+       int rclass = classify_type(degenerate(right), &rtype);
        struct symbol *ctype;
-       int lclass, rclass;
+       const char *typediff;
 
        if (expr->flags) {
                if (!(expr->left->flags & expr->right->flags & Int_const_expr))
@@ -989,29 +1000,69 @@ static struct symbol *evaluate_compare(struct expression 
*expr)
        if (is_type_type(ltype) && is_type_type(rtype))
                goto OK;
 
-       if (is_safe_type(ltype) || is_safe_type(rtype))
+       if (is_safe_type(left->ctype) || is_safe_type(right->ctype))
                warning(expr->pos, "testing a 'safe expression'");
 
-       lclass = classify_type(ltype, &ltype);
-       rclass = classify_type(rtype, &rtype);
-
-       /* Pointer types? */
-       if ((lclass | rclass) & TYPE_PTR) {
-               // FIXME! Check the types for compatibility
-               expr->op = modify_for_unsigned(expr->op);
+       /* number on number */
+       if (lclass & rclass & TYPE_NUM) {
+               ctype = usual_conversions(expr->op, expr->left, expr->right,
+                                         lclass, rclass, ltype, rtype);
+               expr->left = cast_to(expr->left, ctype);
+               expr->right = cast_to(expr->right, ctype);
+               if (ctype->ctype.modifiers & MOD_UNSIGNED)
+                       expr->op = modify_for_unsigned(expr->op);
                goto OK;
        }
 
-       /* Both should be numbers */
-       if (!(lclass & rclass & TYPE_NUM))
+       /* at least one must be a pointer */
+       if (!((lclass | rclass) & TYPE_PTR))
+               return bad_expr_type(expr);
+
+       /* equality comparisons can be with null pointer constants */
+       if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) {
+               int is_null1 = is_null_pointer_constant(left);
+               int is_null2 = is_null_pointer_constant(right);
+               if (is_null1 == 2)
+                       bad_null(left);
+               if (is_null2 == 2)
+                       bad_null(right);
+               if (is_null1 && is_null2) {
+                       int positive = expr->op == SPECIAL_EQUAL;
+                       expr->type = EXPR_VALUE;
+                       expr->value = positive;
+                       goto OK;
+               }
+               if (is_null1) {
+                       left = cast_to(left, rtype);
+                       goto OK;
+               }
+               if (is_null2) {
+                       right = cast_to(right, ltype);
+                       goto OK;
+               }
+               /* they also have special treatment for pointers to void */
+               if (lclass & rclass & TYPE_PTR) {
+                       if (get_base_type(ltype) == &void_ctype) {
+                               right = cast_to(right, ltype);
+                               goto OK;
+                       }
+                       if (get_base_type(rtype) == &void_ctype) {
+                               left = cast_to(left, rtype);
+                               goto OK;
+                       }
+               }
+       }
+       /* both should be pointers */
+       if (!(lclass & rclass & TYPE_PTR))
                return bad_expr_type(expr);
 
-       ctype = usual_conversions(expr->op, expr->left, expr->right,
-                                 lclass, rclass, ltype, rtype);
-       expr->left = cast_to(expr->left, ctype);
-       expr->right = cast_to(expr->right, ctype);
-       if (ctype->ctype.modifiers & MOD_UNSIGNED)
-               expr->op = modify_for_unsigned(expr->op);
+       expr->op = modify_for_unsigned(expr->op);
+       typediff = type_difference(ltype, rtype, MOD_IGN, MOD_IGN);
+       if (!typediff)
+               goto OK;
+
+       expression_error(expr, "incompatible types in comparison expression 
(%s)", typediff);
+       return NULL;
 
 OK:
        expr->ctype = &bool_ctype;
@@ -1032,12 +1083,12 @@ static struct symbol *compatible_ptr_type(struct 
expression *left, struct expres
                rtype = rtype->ctype.base_type;
 
        if (ltype->type == SYM_PTR) {
-               if (is_null_ptr(right) || rtype->ctype.base_type == &void_ctype)
+               if (rtype->ctype.base_type == &void_ctype)
                        return ltype;
        }
 
        if (rtype->type == SYM_PTR) {
-               if (is_null_ptr(left) || ltype->ctype.base_type == &void_ctype)
+               if (ltype->ctype.base_type == &void_ctype)
                        return rtype;
        }
        return NULL;
@@ -1090,13 +1141,45 @@ static struct symbol 
*evaluate_conditional_expression(struct expression *expr)
                expr->cond_false = cast_to(expr->cond_false, ctype);
                goto out;
        }
-       ctype = compatible_ptr_type(*true, expr->cond_false);
-       if (ctype)
-               goto out;
+       if ((lclass | rclass) & TYPE_PTR) {
+               int is_null1 = is_null_pointer_constant(*true);
+               int is_null2 = is_null_pointer_constant(expr->cond_false);
+               if (is_null1 && is_null2) {
+                       *true = cast_to(*true, &ptr_ctype);
+                       expr->cond_false = cast_to(expr->cond_false, 
&ptr_ctype);
+                       ctype = &ptr_ctype;
+                       goto out;
+               }
+               if (is_null1 && (rclass & TYPE_PTR)) {
+                       if (is_null1 == 2)
+                               bad_null(*true);
+                       *true = cast_to(*true, rtype);
+                       ctype = rtype;
+                       goto out;
+               }
+               if (is_null2 && (lclass & TYPE_PTR)) {
+                       if (is_null2 == 2)
+                               bad_null(expr->cond_false);
+                       expr->cond_false = cast_to(expr->cond_false, ltype);
+                       ctype = ltype;
+                       goto out;
+               }
+               if (!(lclass & rclass & TYPE_PTR)) {
+                       typediff = "different types";
+                       goto Err;
+               }
+               /* OK, it's pointer on pointer */
+               /* XXX - we need to handle qualifiers */
+               ctype = compatible_ptr_type(*true, expr->cond_false);
+               if (ctype)
+                       goto out;
+       }
        ctype = ltype;
        typediff = type_difference(ltype, rtype, MOD_IGN, MOD_IGN);
        if (!typediff)
                goto out;
+
+Err:
        expression_error(expr, "incompatible types in conditional expression 
(%s)", typediff);
        return NULL;
 
@@ -1185,6 +1268,16 @@ static int compatible_assignment_types(struct expression 
*expr, struct symbol *t
                        goto Cast;
        }
 
+       if (tclass & TYPE_PTR) {
+               // NULL pointer is always OK
+               int is_null = is_null_pointer_constant(*rp);
+               if (is_null) {
+                       if (is_null == 2)
+                               bad_null(*rp);
+                       goto Cast;
+               }
+       }
+
        /* It's OK if the target is more volatile or const than the source */
        typediff = type_difference(target, source, MOD_VOLATILE | MOD_CONST, 0);
        if (!typediff)
@@ -1192,14 +1285,9 @@ static int compatible_assignment_types(struct expression 
*expr, struct symbol *t
 
        /* Pointer destination? */
        if (tclass & TYPE_PTR) {
-               struct expression *right = *rp;
                int source_as;
                int target_as;
 
-               // NULL pointer is always OK
-               if (is_null_ptr(right))
-                       goto Cast;
-
                /* "void *" matches anything as long as the address space is OK 
*/
                target_as = t->ctype.as | target->ctype.as;
                source_as = s->ctype.as | source->ctype.as;
@@ -1941,7 +2029,10 @@ static int evaluate_arguments(struct symbol *f, struct 
symbol *fn, struct expres
                                if (!(mod & (MOD_LONG|MOD_LONGLONG)))
                                        *p = cast_to(expr, &double_ctype);
                        } else if (class & TYPE_PTR) {
-                               degenerate(expr);
+                               if (expr->ctype == &null_ctype)
+                                       *p = cast_to(expr, &ptr_ctype);
+                               else
+                                       degenerate(expr);
                        }
                } else {
                        static char where[30];
@@ -2438,31 +2529,6 @@ static int get_as(struct symbol *sym)
        return as;
 }
 
-static void cast_to_as(struct expression *e, int as)
-{
-       struct expression *v = e->cast_expression;
-       struct symbol *type = v->ctype;
-
-       if (!Wcast_to_address_space)
-               return;
-
-       if (v->type != EXPR_VALUE || v->value)
-               goto out;
-
-       /* cast from constant 0 to pointer is OK */
-       if (is_int_type(type))
-               return;
-
-       if (type->type == SYM_NODE)
-               type = type->ctype.base_type;
-
-       if (type->type == SYM_PTR && type->ctype.base_type == &void_ctype)
-               return;
-
-out:
-       warning(e->pos, "cast adds address space to expression (<asn:%d>)", as);
-}
-
 static struct symbol *evaluate_cast(struct expression *expr)
 {
        struct expression *target = expr->cast_expression;
@@ -2557,17 +2623,23 @@ static struct symbol *evaluate_cast(struct expression 
*expr)
                warning(expr->pos, "cast removes address space of expression");
        if (as1 > 0 && as2 > 0 && as1 != as2)
                warning(expr->pos, "cast between address spaces 
(<asn:%d>-><asn:%d>)", as2, as1);
-       if (as1 > 0 && !as2)
-               cast_to_as(expr, as1);
-
-       /*
-        * Casts of constant values are special: they
-        * can be NULL, and thus need to be simplified
-        * early.
-        */
-       if (target->type == EXPR_VALUE)
-               cast_value(expr, ctype, target, target->ctype);
-
+       if (as1 > 0 && !as2 &&
+           !is_null_pointer_constant(target) && Wcast_to_address_space)
+               warning(expr->pos,
+                       "cast adds address space to expression (<asn:%d>)", 
as1);
+
+       if (!(ctype->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR &&
+           !as1 && (target->flags & Int_const_expr)) {
+               if (t1->ctype.base_type == &void_ctype) {
+                       if (is_zero_constant(target)) {
+                               /* NULL */
+                               expr->type = EXPR_VALUE;
+                               expr->ctype = &null_ctype;
+                               expr->value = 0;
+                               return ctype;
+                       }
+               }
+       }
 out:
        return ctype;
 }
@@ -3153,6 +3225,8 @@ struct symbol *evaluate_statement(struct statement *stmt)
        case STMT_EXPRESSION:
                if (!evaluate_expression(stmt->expression))
                        return NULL;
+               if (stmt->expression->ctype == &null_ctype)
+                       stmt->expression = cast_to(stmt->expression, 
&ptr_ctype);
                return degenerate(stmt->expression);
 
        case STMT_COMPOUND: {
diff --git a/expand.c b/expand.c
index 780b643..b2eeef8 100644
--- a/expand.c
+++ b/expand.c
@@ -34,6 +34,7 @@
 
 static int expand_expression(struct expression *);
 static int expand_statement(struct statement *);
+static int conservative;
 
 static int expand_symbol_expression(struct expression *expr)
 {
@@ -97,7 +98,7 @@ Int:
        expr->value = value & mask;
 
        // Stop here unless checking for truncation
-       if (!Wcast_truncate)
+       if (!Wcast_truncate || conservative)
                return;
        
        // Check if we dropped any bits..
@@ -138,10 +139,8 @@ Float:
 
 static int check_shift_count(struct expression *expr, struct symbol *ctype, 
unsigned int count)
 {
-       if (count >= ctype->bit_size) {
-               warning(expr->pos, "shift too big (%u) for type %s", count, 
show_typename(ctype));
-               count &= ctype->bit_size-1;
-       }
+       warning(expr->pos, "shift too big (%u) for type %s", count, 
show_typename(ctype));
+       count &= ctype->bit_size-1;
        return count;
 }
 
@@ -163,8 +162,12 @@ static int simplify_int_binop(struct expression *expr, 
struct symbol *ctype)
                return 0;
        r = right->value;
        if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
-               r = check_shift_count(expr, ctype, r);
-               right->value = r;
+               if (r >= ctype->bit_size) {
+                       if (conservative)
+                               return 0;
+                       r = check_shift_count(expr, ctype, r);
+                       right->value = r;
+               }
        }
        if (left->type != EXPR_VALUE)
                return 0;
@@ -257,10 +260,12 @@ static int simplify_int_binop(struct expression *expr, 
struct symbol *ctype)
        expr->taint = left->taint | right->taint;
        return 1;
 Div:
-       warning(expr->pos, "division by zero");
+       if (!conservative)
+               warning(expr->pos, "division by zero");
        return 0;
 Overflow:
-       warning(expr->pos, "constant integer operation overflow");
+       if (!conservative)
+               warning(expr->pos, "constant integer operation overflow");
        return 0;
 }
 
@@ -340,7 +345,8 @@ static int simplify_float_binop(struct expression *expr)
        expr->fvalue = res;
        return 1;
 Div:
-       warning(expr->pos, "division by zero");
+       if (!conservative)
+               warning(expr->pos, "division by zero");
        return 0;
 }
 
@@ -660,7 +666,8 @@ static int simplify_preop(struct expression *expr)
        return 1;
 
 Overflow:
-       warning(expr->pos, "constant integer operation overflow");
+       if (!conservative)
+               warning(expr->pos, "constant integer operation overflow");
        return 0;
 }
 
@@ -1222,3 +1229,12 @@ long long const_expression_value(struct expression *expr)
 {
        return __get_expression_value(expr, 1);
 }
+
+int is_zero_constant(struct expression *expr)
+{
+       int saved = conservative;
+       conservative = 1;
+       expand_expression(expr);
+       conservative = saved;
+       return expr->type == EXPR_VALUE && !expr->value;
+}
diff --git a/expression.h b/expression.h
index 23ca408..02eec02 100644
--- a/expression.h
+++ b/expression.h
@@ -154,6 +154,7 @@ struct expression {
 };
 
 /* Constant expression values */
+int is_zero_constant(struct expression *);
 long long get_expression_value(struct expression *);
 long long const_expression_value(struct expression *);
 
diff --git a/symbol.c b/symbol.c
index cec7e02..9dfeb41 100644
--- a/symbol.c
+++ b/symbol.c
@@ -753,7 +753,8 @@ struct symbol       bool_ctype, void_ctype, type_ctype,
                llong_ctype, sllong_ctype, ullong_ctype,
                float_ctype, double_ctype, ldouble_ctype,
                string_ctype, ptr_ctype, lazy_ptr_ctype,
-               incomplete_ctype, label_ctype, bad_ctype;
+               incomplete_ctype, label_ctype, bad_ctype,
+               null_ctype;
 
 struct symbol  zero_int;
 
@@ -829,6 +830,7 @@ static const struct ctype_declare {
 
        { &string_ctype,    SYM_PTR,      0,                        
&bits_in_pointer,        &pointer_alignment, &char_ctype },
        { &ptr_ctype,       SYM_PTR,      0,                        
&bits_in_pointer,        &pointer_alignment, &void_ctype },
+       { &null_ctype,      SYM_PTR,      0,                        
&bits_in_pointer,        &pointer_alignment, &void_ctype },
        { &label_ctype,     SYM_PTR,      0,                        
&bits_in_pointer,        &pointer_alignment, &void_ctype },
        { &lazy_ptr_ctype,  SYM_PTR,      0,                        
&bits_in_pointer,        &pointer_alignment, &void_ctype },
        { NULL, }
diff --git a/symbol.h b/symbol.h
index 2bde84d..a59feee 100644
--- a/symbol.h
+++ b/symbol.h
@@ -229,7 +229,8 @@ extern struct symbol        bool_ctype, void_ctype, 
type_ctype,
                        llong_ctype, sllong_ctype, ullong_ctype,
                        float_ctype, double_ctype, ldouble_ctype,
                        string_ctype, ptr_ctype, lazy_ptr_ctype,
-                       incomplete_ctype, label_ctype, bad_ctype;
+                       incomplete_ctype, label_ctype, bad_ctype,
+                       null_ctype;
 
 /* Special internal symbols */
 extern struct symbol   zero_int;
-- 
1.5.0-rc2.GIT
-
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to