This patch fixes PR 50565, a failure to accept certain offsetof-type expressions in static initializers introduced by my constant expressions changes. (These expressions are permitted but not required by ISO C to be accepted; the intent of my constant expressions model is that they should be valid in GNU C.)
The problem comes down to an expression with the difference of two pointers being cast to int on a 64-bit system, resulting in convert_to_integer moving the conversions inside the subtraction. (These optimizations at conversion time should really be done later as a part of folding, or even later than that, rather than unconditionally in convert_to_*, but that's another issue.) So when the expression reaches c_fully_fold it is a difference of narrowed pointers being folded, which the compiler cannot optimize as it can a difference of unnarrowed pointers with the same base object. Before the introduction of c_fully_fold the difference would have been folded when built and so the narrowing of operands would never have been applied to it. This patch disables the narrowing in the case of pointer subtraction, as it doesn't seem particularly likely to be useful there and is known to prevent this folding required for these initializers to be accepted. Bootstrapped with no regressions on x86_64-unknown-linux-gnu. OK to commit? 2011-10-11 Joseph Myers <jos...@codesourcery.com> PR c/50565 * convert.c (convert_to_integer): Do not narrow operands of pointer subtraction. testsuite: 2011-10-11 Joseph Myers <jos...@codesourcery.com> PR c/50565 * gcc.c-torture/compile/pr50565-1.c, gcc.c-torture/compile/pr50565-2.c: New tests. Index: gcc/testsuite/gcc.c-torture/compile/pr50565-1.c =================================================================== --- gcc/testsuite/gcc.c-torture/compile/pr50565-1.c (revision 0) +++ gcc/testsuite/gcc.c-torture/compile/pr50565-1.c (revision 0) @@ -0,0 +1,4 @@ +struct s { char p[2]; }; +static struct s v; +const int o0 = (int) ((void *) &v.p[0] - (void *) &v) + 0U; +const int o1 = (int) ((void *) &v.p[0] - (void *) &v) + 1U; Index: gcc/testsuite/gcc.c-torture/compile/pr50565-2.c =================================================================== --- gcc/testsuite/gcc.c-torture/compile/pr50565-2.c (revision 0) +++ gcc/testsuite/gcc.c-torture/compile/pr50565-2.c (revision 0) @@ -0,0 +1,4 @@ +struct s { char p[2]; }; +static struct s v; +const int o0 = (int) ((void *) &v.p[0] - (void *) &v) + 0; +const int o1 = (int) ((void *) &v.p[0] - (void *) &v) + 1; Index: gcc/convert.c =================================================================== --- gcc/convert.c (revision 179754) +++ gcc/convert.c (working copy) @@ -745,6 +745,15 @@ convert_to_integer (tree type, tree expr tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type); tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type); + /* Do not try to narrow operands of pointer subtraction; + that will interfere with other folding. */ + if (ex_form == MINUS_EXPR + && CONVERT_EXPR_P (arg0) + && CONVERT_EXPR_P (arg1) + && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0))) + && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg1, 0)))) + break; + if (outprec >= BITS_PER_WORD || TRULY_NOOP_TRUNCATION (outprec, inprec) || inprec > TYPE_PRECISION (TREE_TYPE (arg0)) -- Joseph S. Myers jos...@codesourcery.com