Patchwork Fix PR 50565 (offsetof-type expressions in static initializers)

login
register
mail settings
Submitter Joseph S. Myers
Date Oct. 11, 2011, 3:32 p.m.
Message ID <Pine.LNX.4.64.1110111531270.30672@digraph.polyomino.org.uk>
Download mbox | patch
Permalink /patch/118997/
State New
Headers show

Comments

Joseph S. Myers - Oct. 11, 2011, 3:32 p.m.
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
Gabriel Dos Reis - Oct. 11, 2011, 11:11 p.m.
On Tue, Oct 11, 2011 at 10:32 AM, Joseph S. Myers
<joseph@codesourcery.com> wrote:

> 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.)

Interesting. C++11 classified this as "linktime" constants, e.g. they
are constant
expressions for static initialization purposes, but not compile-time constant
expressions, precisely because of this kind of issues.
Richard Guenther - Oct. 12, 2011, 11:48 a.m.
On Tue, Oct 11, 2011 at 5:32 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> 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?

Ok.

Thanks,
Richard.

> 2011-10-11  Joseph Myers  <joseph@codesourcery.com>
>
>        PR c/50565
>        * convert.c (convert_to_integer): Do not narrow operands of
>        pointer subtraction.
>
> testsuite:
> 2011-10-11  Joseph Myers  <joseph@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
> joseph@codesourcery.com
>

Patch

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  <joseph@codesourcery.com>

	PR c/50565
	* convert.c (convert_to_integer): Do not narrow operands of
	pointer subtraction.

testsuite:
2011-10-11  Joseph Myers  <joseph@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))