aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-typeck.c
diff options
context:
space:
mode:
authorMarc Glisse <marc.glisse@inria.fr>2017-11-21 19:23:56 +0100
committerMarc Glisse <glisse@gcc.gnu.org>2017-11-21 18:23:56 +0000
commit1af4ebf5985ef2aaac13862654044d84a3cd7ae4 (patch)
tree6136f270e536b46d7d9de96d28e38794684035dd /gcc/c/c-typeck.c
parentffb41aab7a9b8475e773b75fdebd194f4491c9db (diff)
downloadgcc-1af4ebf5985ef2aaac13862654044d84a3cd7ae4.zip
gcc-1af4ebf5985ef2aaac13862654044d84a3cd7ae4.tar.gz
gcc-1af4ebf5985ef2aaac13862654044d84a3cd7ae4.tar.bz2
New POINTER_DIFF_EXPR
2017-11-21 Marc Glisse <marc.glisse@inria.fr> gcc/c/ * c-fold.c (c_fully_fold_internal): Handle POINTER_DIFF_EXPR. * c-typeck.c (pointer_diff): Use POINTER_DIFF_EXPR. gcc/c-family/ * c-pretty-print.c (pp_c_additive_expression, c_pretty_printer::expression): Handle POINTER_DIFF_EXPR. gcc/cp/ * constexpr.c (cxx_eval_constant_expression, potential_constant_expression_1): Handle POINTER_DIFF_EXPR. * cp-gimplify.c (cp_fold): Likewise. * error.c (dump_expr): Likewise. * typeck.c (pointer_diff): Use POINTER_DIFF_EXPR. gcc/ * doc/generic.texi: Document POINTER_DIFF_EXPR, update POINTER_PLUS_EXPR. * cfgexpand.c (expand_debug_expr): Handle POINTER_DIFF_EXPR. * expr.c (expand_expr_real_2): Likewise. * fold-const.c (const_binop, fold_addr_of_array_ref_difference, fold_binary_loc): Likewise. * match.pd (X-X, P+(Q-P), &D-P, (P+N)-P, P-(P+N), (P+M)-(P+N), P-Q==0, -(A-B), X-Z<Y-Z, (X-Z)-(Y-Z), Z-X<Z-Y, (Z-X)-(Z-Y), (A-B)+(C-A)): New transformations for POINTER_DIFF_EXPR, based on MINUS_EXPR transformations. * optabs-tree.c (optab_for_tree_code): Handle POINTER_DIFF_EXPR. * tree-cfg.c (verify_expr, verify_gimple_assign_binary): Likewise. * tree-inline.c (estimate_operator_cost): Likewise. * tree-pretty-print.c (dump_generic_node, op_code_prio, op_symbol_code): Likewise. * tree-vect-stmts.c (vectorizable_operation): Likewise. * vr-values.c (extract_range_from_binary_expr): Likewise. * varasm.c (initializer_constant_valid_p_1): Likewise. * tree.def: New tree code POINTER_DIFF_EXPR. From-SVN: r255021
Diffstat (limited to 'gcc/c/c-typeck.c')
-rw-r--r--gcc/c/c-typeck.c25
1 files changed, 16 insertions, 9 deletions
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");