Hi! The match.pd framework uses op0 == op1 || operand_equal_p (op0, op1, 0) style comparisons heavily; the reason why we don't optimize away say volatile int i; ... int j = i - i; into int j = (i, 0); is only because both the C and C++ FE convert the volatile arguments to non-volatile ones before the arithmetic operation (e.g. c_common_type returns a non-qualified type). Unfortunately, in C FE this doesn't happen for POINTER_DIFF_EXPR, where no conversion happens. The following patch makes sure we convert the pointer arguments to some non-qualified pointers first.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/8.2? 2018-06-15 Jakub Jelinek <ja...@redhat.com> PR c/86093 * c-typeck.c (pointer_diff): Cast both pointers to unqualified types before doing POINTER_DIFF_EXPR. * c-c++-common/pr86093.c: New test. --- gcc/c/c-typeck.c.jj 2018-05-31 20:53:32.003439351 +0200 +++ gcc/c/c-typeck.c 2018-06-15 15:35:44.185308552 +0200 @@ -3840,7 +3840,12 @@ pointer_diff (location_t loc, tree 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); + { + /* Cast away qualifiers. */ + op0 = convert (c_common_type (TREE_TYPE (op0), TREE_TYPE (op0)), op0); + op1 = convert (c_common_type (TREE_TYPE (op1), TREE_TYPE (op1)), op1); + op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1); + } /* This generates an error if op1 is pointer to incomplete type. */ if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1)))) --- gcc/testsuite/c-c++-common/pr86093.c.jj 2018-06-15 15:51:40.344192815 +0200 +++ gcc/testsuite/c-c++-common/pr86093.c 2018-06-15 15:51:23.340177502 +0200 @@ -0,0 +1,12 @@ +/* PR c/86093 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-not "return 0;" "optimized" } } */ + +char *volatile p; + +__PTRDIFF_TYPE__ +foo (void) +{ + return p - p; +} Jakub