diff options
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/c/c-fold.c | 1 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 25 |
3 files changed, 22 insertions, 9 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 95b7718..a2773b0 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,8 @@ +2017-11-21 Marc Glisse <marc.glisse@inria.fr> + + * c-fold.c (c_fully_fold_internal): Handle POINTER_DIFF_EXPR. + * c-typeck.c (pointer_diff): Use POINTER_DIFF_EXPR. + 2017-11-20 David Malcolm <dmalcolm@redhat.com> PR c/81404 diff --git a/gcc/c/c-fold.c b/gcc/c/c-fold.c index 6a6c716..8895462 100644 --- a/gcc/c/c-fold.c +++ b/gcc/c/c-fold.c @@ -306,6 +306,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, case MINUS_EXPR: case MULT_EXPR: case POINTER_PLUS_EXPR: + case POINTER_DIFF_EXPR: case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 8a09ea2..7f85c6b 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3778,7 +3778,7 @@ parser_build_binary_op (location_t location, enum tree_code code, } /* Return a tree for the difference of pointers OP0 and OP1. - The resulting tree has type int. */ + The resulting tree has type ptrdiff_t. */ static tree pointer_diff (location_t loc, tree op0, tree op1) @@ -3810,7 +3810,7 @@ pointer_diff (location_t loc, tree op0, tree op1) op1 = convert (common_type, op1); } - /* Determine integer type to perform computations in. This will usually + /* Determine integer type result of the subtraction. This will usually be the same as the result type (ptrdiff_t), but may need to be a wider type if pointers for the address space are wider than ptrdiff_t. */ if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0))) @@ -3825,14 +3825,21 @@ pointer_diff (location_t loc, tree op0, tree op1) pedwarn (loc, OPT_Wpointer_arith, "pointer to a function used in subtraction"); - /* First do the subtraction as integers; - then drop through to build the divide operator. - Do not do default conversions on the minus operator - in case restype is a short type. */ + /* First do the subtraction, then build the divide operator + and only convert at the very end. + Do not do default conversions in case restype is a short type. */ + + /* POINTER_DIFF_EXPR requires a signed integer type of the same size as + pointers. If some platform cannot provide that, or has a larger + ptrdiff_type to support differences larger than half the address + space, cast the pointers to some larger integer type and do the + computations in that type. */ + if (TYPE_PRECISION (inttype) > TYPE_PRECISION (TREE_TYPE (op0))) + op0 = build_binary_op (loc, MINUS_EXPR, convert (inttype, op0), + convert (inttype, op1), false); + else + op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1); - op0 = build_binary_op (loc, - MINUS_EXPR, convert (inttype, op0), - convert (inttype, op1), false); /* This generates an error if op1 is pointer to incomplete type. */ if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1)))) error_at (loc, "arithmetic on pointer to an incomplete type"); |