diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0932c9a8df29f592521f5fe3aea5c67c8ffd8fcf..0cb236d63111d5609b6f4575d45f7bae9aa0aff6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2008-06-04  Richard Guenther  <rguenther@suse.de>
+
+	* tree-ssa-structalias.c (handle_ptr_arith): Correctly handle
+	negative or non-representable offsets.
+
 2008-06-03  H.J. Lu  <hongjiu.lu@intel.com>
 
 	*  config/i386/i386.c (ix86_gen_leave): New.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 536462e66d4190171e5d4730e54ace7a98e3c89f..d43613a3a06ebb51e11e6eea8b2b11ff0a695237 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2008-06-04  Richard Guenther  <rguenther@suse.de>
+
+	* gcc.c-torture/execute/20080604-1.c: New testcase.
+
 2008-06-03  Andy Hutchinson  <hutchinsonandy@aim.com>
 
 	PR/34880
diff --git a/gcc/testsuite/gcc.c-torture/execute/20080604-1.c b/gcc/testsuite/gcc.c-torture/execute/20080604-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..5ba35cb2cf5c22ef825793facfcdff697da3e3f7
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20080604-1.c
@@ -0,0 +1,32 @@
+struct barstruct { char const* some_string; } x;
+extern void abort (void);
+void __attribute__((noinline))
+foo(void)
+{
+  if (!x.some_string)
+    abort ();
+}
+void baz(int b)
+{
+  struct barstruct bar;
+  struct barstruct* barptr;
+  if (b)
+    barptr = &bar;
+  else
+    {
+      barptr = &x + 1;
+      barptr = barptr - 1;
+    }
+  barptr->some_string = "Everything OK";
+  foo();
+  barptr->some_string = "Everything OK";
+}
+int main()
+{
+  x.some_string = (void *)0;
+  baz(0);
+  if (!x.some_string)
+    abort ();
+  return 0;
+}
+
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 0e422146f9b3c509567de9c77aacde0636162ba3..570c173b3a949de24149a6d9d8178714458a0cb8 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -3531,8 +3531,7 @@ handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
   unsigned int i = 0;
   unsigned int j = 0;
   VEC (ce_s, heap) *temp = NULL;
-  unsigned int rhsoffset = 0;
-  bool unknown_addend = false;
+  unsigned HOST_WIDE_INT rhsunitoffset, rhsoffset;
 
   if (TREE_CODE (expr) != POINTER_PLUS_EXPR)
     return false;
@@ -3541,13 +3540,18 @@ handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
   op1 = TREE_OPERAND (expr, 1);
   gcc_assert (POINTER_TYPE_P (TREE_TYPE (op0)));
 
-  get_constraint_for (op0, &temp);
+  /* If the offset is not a non-negative integer constant that fits
+     in a HOST_WIDE_INT, we cannot handle it here.  */
+  if (!host_integerp (op1, 1))
+    return false;
 
-  /* Handle non-constants by making constraints from integer.  */
-  if (TREE_CODE (op1) == INTEGER_CST)
-    rhsoffset = TREE_INT_CST_LOW (op1) * BITS_PER_UNIT;
-  else
-    unknown_addend = true;
+  /* Make sure the bit-offset also fits.  */
+  rhsunitoffset = TREE_INT_CST_LOW (op1);
+  rhsoffset = rhsunitoffset * BITS_PER_UNIT;
+  if (rhsunitoffset != rhsoffset / BITS_PER_UNIT)
+    return false;
+
+  get_constraint_for (op0, &temp);
 
   for (i = 0; VEC_iterate (ce_s, lhsc, i, c); i++)
     for (j = 0; VEC_iterate (ce_s, temp, j, c2); j++)
@@ -3564,30 +3568,6 @@ handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
 	    c2->var = temp->id;
 	    c2->offset = 0;
 	  }
-	else if (unknown_addend)
-	  {
-	    /* Can't handle *a + integer where integer is unknown.  */
-	    if (c2->type != SCALAR)
-	      {
-		struct constraint_expr intc;
-		intc.var = integer_id;
-		intc.offset = 0;
-		intc.type = SCALAR;
-		process_constraint (new_constraint (*c, intc));
-	      }
-	    else
-	      {
-		/* We known it lives somewhere within c2->var.  */
-		varinfo_t tmp = get_varinfo (c2->var);
-		for (; tmp; tmp = tmp->next)
-		  {
-		    struct constraint_expr tmpc = *c2;
-		    c2->var = tmp->id;
-		    c2->offset = 0;
-		    process_constraint (new_constraint (*c, tmpc));
-		  }
-	      }
-	  }
 	else
 	  c2->offset = rhsoffset;
 	process_constraint (new_constraint (*c, *c2));