Hi,

this is a regression present on the mainline and 4.6 branch caused by the 
constructor uniquization patch.  The tree_output_constant_def routine rejects 
offsetof-like computations that can be written in the C family of languages.
While the C compiler folds most of them early, it doesn't if an intermediate 
folding step is required.

The proposed fix is to make c_fully_fold also do the offsetof folding.

Tested on x86_64-suse-linux, OK for mainline and 4.6 branch?


2011-09-06  Eric Botcazou  <ebotca...@adacore.com>

        PR middle-end/50266
        * c-common.c (c_fully_fold_internal) <ADDR_EXPR>: Fold offsetof-like
        computations.


2011-09-06  Eric Botcazou  <ebotca...@adacore.com>

        * gcc.dg/init-offsetof-1.c: New test.


-- 
Eric Botcazou
Index: c-common.c
===================================================================
--- c-common.c	(revision 178488)
+++ c-common.c	(working copy)
@@ -1264,7 +1264,18 @@ c_fully_fold_internal (tree expr, bool i
       STRIP_TYPE_NOPS (op0);
       if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR)
 	op0 = decl_constant_value_for_optimization (op0);
-      if (op0 != orig_op0 || in_init)
+      if (op0 != orig_op0
+	  && code == ADDR_EXPR
+	  && (op1 = get_base_address (op0)) != NULL_TREE
+	  && TREE_CODE (op1) == INDIRECT_REF
+	  && TREE_CONSTANT (TREE_OPERAND (op1, 0)))
+	{
+	  tree offset = fold_offsetof (op0, op1);
+	  op1
+	    = fold_convert_loc (loc, TREE_TYPE (expr), TREE_OPERAND (op1, 0));
+	  ret = fold_build_pointer_plus_loc (loc, op1, offset);
+	}
+      else if (op0 != orig_op0 || in_init)
 	ret = in_init
 	  ? fold_build1_initializer_loc (loc, code, TREE_TYPE (expr), op0)
 	  : fold_build1_loc (loc, code, TREE_TYPE (expr), op0);
/* PR middle-end/50266 */
/* Testcase by <b...@arklinux.org> */

/* { dg-do compile } */
/* { dg-options "-Os" } */

struct a {
 unsigned int a;
 unsigned int b;
};

struct a *const p = (struct a *)0x4A004100;

void foo(void)
{
 unsigned int i = 0;
 unsigned int *const x[] = {
  &p->a,
  &p->b,
  0
 };

 (*(volatile unsigned int *)((x[i]))
   = (unsigned int)((unsigned int)((*(volatile unsigned int *)(x[i])))));
}

Reply via email to