diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index feb6a71ab21f..e5de23f84213 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,21 @@
+2005-10-20  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+	PR rtl-optimization/23585
+	* rtlanal.c (rtx_addr_can_trap_p_1): New predicate extracted from...
+	(rtx_addr_can_trap_p): ... here.  Invoke rtx_addr_can_trap_p_1.
+	(may_trap_p_1): New predicate extracted from...
+	(may_trap_p): ... here.  Invoke may_trap_p_1.
+	(may_trap_or_fault_p): New predicate.
+	* rtl.h (may_trap_or_fault_p): Declare it.
+	* reorg.c (steal_delay_list_from_target): Use may_trap_or_fault_p
+	instead of may_trap_p.
+	(steal_delay_list_from_fallthrough): Likewise.
+	(fill_simple_delay_slots): Likewise.
+	(fill_slots_from_thread): Likewise.
+	* function.c (pad_to_arg_alignment): Rework comment about
+	SPARC_STACK_BOUNDARY_HACK.
+	* config/sparc/sparc.h: Likewise.
+
 2005-10-19  Adrian Straetling  <straetling@de.ibm.com>
 
 	* config/s390/s390.c (s390_expand_insv): New.
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index bb81dcc2208f..a72cc90910b6 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -624,11 +624,9 @@ if (TARGET_ARCH64				\
 
 /* Boundary (in *bits*) on which stack pointer should be aligned.  */
 /* FIXME, this is wrong when TARGET_ARCH64 and TARGET_STACK_BIAS, because
-   then sp+2047 is 128-bit aligned so sp is really only byte-aligned.  */
+   then %sp+2047 is 128-bit aligned so %sp is really only byte-aligned.  */
 #define STACK_BOUNDARY (TARGET_ARCH64 ? 128 : 64)
-/* Temporary hack until the FIXME above is fixed.  This macro is used
-   only in pad_to_arg_alignment in function.c; see the comment there
-   for details about what it does.  */
+/* Temporary hack until the FIXME above is fixed.  */
 #define SPARC_STACK_BOUNDARY_HACK (TARGET_ARCH64 && TARGET_STACK_BIAS)
 
 /* ALIGN FRAMES on double word boundaries */
diff --git a/gcc/function.c b/gcc/function.c
index 7cff2a0d1dc6..941021edc667 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -3370,10 +3370,9 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
   HOST_WIDE_INT sp_offset = STACK_POINTER_OFFSET;
 
 #ifdef SPARC_STACK_BOUNDARY_HACK
-  /* The sparc port has a bug.  It sometimes claims a STACK_BOUNDARY
-     higher than the real alignment of %sp.  However, when it does this,
-     the alignment of %sp+STACK_POINTER_OFFSET will be STACK_BOUNDARY.
-     This is a temporary hack while the sparc port is fixed.  */
+  /* ??? The SPARC port may claim a STACK_BOUNDARY higher than
+     the real alignment of %sp.  However, when it does this, the
+     alignment of %sp+STACK_POINTER_OFFSET is STACK_BOUNDARY.  */
   if (SPARC_STACK_BOUNDARY_HACK)
     sp_offset = 0;
 #endif
diff --git a/gcc/reorg.c b/gcc/reorg.c
index 8b9d7efccfbf..46154f1fd3a7 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -1337,7 +1337,7 @@ steal_delay_list_from_target (rtx insn, rtx condition, rtx seq,
       if (! must_annul
 	  && ((condition == const_true_rtx
 	       || (! insn_sets_resource_p (trial, other_needed, 0)
-		   && ! may_trap_p (PATTERN (trial)))))
+		   && ! may_trap_or_fault_p (PATTERN (trial)))))
 	  ? eligible_for_delay (insn, total_slots_filled, trial, flags)
 	  : (must_annul || (delay_list == NULL && new_delay_list == NULL))
 	     && (must_annul = 1,
@@ -1431,7 +1431,7 @@ steal_delay_list_from_fallthrough (rtx insn, rtx condition, rtx seq,
       if (! must_annul
 	  && ((condition == const_true_rtx
 	       || (! insn_sets_resource_p (trial, other_needed, 0)
-		   && ! may_trap_p (PATTERN (trial)))))
+		   && ! may_trap_or_fault_p (PATTERN (trial)))))
 	  ? eligible_for_delay (insn, *pslots_filled, trial, flags)
 	  : (must_annul || delay_list == NULL) && (must_annul = 1,
 	     check_annul_list_true_false (1, delay_list)
@@ -2323,7 +2323,7 @@ fill_simple_delay_slots (int non_jumps_p)
 #ifdef HAVE_cc0
 		    && ! (reg_mentioned_p (cc0_rtx, pat) && ! sets_cc0_p (pat))
 #endif
-		    && ! (maybe_never && may_trap_p (pat))
+		    && ! (maybe_never && may_trap_or_fault_p (pat))
 		    && (trial = try_split (pat, trial, 0))
 		    && eligible_for_delay (insn, slots_filled, trial, flags)
 		    && ! can_throw_internal(trial))
@@ -2376,7 +2376,7 @@ fill_simple_delay_slots (int non_jumps_p)
 #ifdef HAVE_cc0
 	      && ! reg_mentioned_p (cc0_rtx, PATTERN (next_trial))
 #endif
-	      && ! (maybe_never && may_trap_p (PATTERN (next_trial)))
+	      && ! (maybe_never && may_trap_or_fault_p (PATTERN (next_trial)))
 	      && (next_trial = try_split (PATTERN (next_trial), next_trial, 0))
 	      && eligible_for_delay (insn, slots_filled, next_trial, flags)
 	      && ! can_throw_internal (trial))
@@ -2656,7 +2656,7 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread,
 	  if (!must_annul
 	      && (condition == const_true_rtx
 	          || (! insn_sets_resource_p (trial, &opposite_needed, 1)
-		      && ! may_trap_p (pat))))
+		      && ! may_trap_or_fault_p (pat))))
 	    {
 	      old_trial = trial;
 	      trial = try_split (pat, trial, 0);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 6de76e288f3b..ceb23941b88f 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1611,6 +1611,7 @@ extern int side_effects_p (rtx);
 extern int volatile_refs_p (rtx);
 extern int volatile_insn_p (rtx);
 extern int may_trap_p (rtx);
+extern int may_trap_or_fault_p (rtx);
 extern int inequality_comparisons_p (rtx);
 extern rtx replace_rtx (rtx, rtx, rtx);
 extern rtx replace_regs (rtx, rtx *, unsigned int, int);
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 9064b009a9bc..594b2e47f643 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -223,10 +223,13 @@ rtx_varies_p (rtx x, int for_alias)
   return 0;
 }
 
-/* Return 0 if the use of X as an address in a MEM can cause a trap.  */
+/* Return nonzero if the use of X as an address in a MEM can cause a trap.
+   MODE is the mode of the MEM (not that of X) and UNALIGNED_MEMS controls
+   whether nonzero is returned for unaligned memory accesses on strict
+   alignment machines.  */
 
-int
-rtx_addr_can_trap_p (rtx x)
+static int
+rtx_addr_can_trap_p_1 (rtx x, enum machine_mode mode, bool unaligned_mems)
 {
   enum rtx_code code = GET_CODE (x);
 
@@ -252,27 +255,52 @@ rtx_addr_can_trap_p (rtx x)
       return 1;
 
     case CONST:
-      return rtx_addr_can_trap_p (XEXP (x, 0));
+      return rtx_addr_can_trap_p_1 (XEXP (x, 0), mode, unaligned_mems);
 
     case PLUS:
-      /* An address is assumed not to trap if it is an address that can't
-	 trap plus a constant integer or it is the pic register plus a
-	 constant.  */
-      return ! ((! rtx_addr_can_trap_p (XEXP (x, 0))
-		 && GET_CODE (XEXP (x, 1)) == CONST_INT)
-		|| (XEXP (x, 0) == pic_offset_table_rtx
-		    && CONSTANT_P (XEXP (x, 1))));
+      /* An address is assumed not to trap if:
+	 - it is an address that can't trap plus a constant integer,
+	   with the proper remainder modulo the mode size if we are
+	   considering unaligned memory references.  */
+      if (!rtx_addr_can_trap_p_1 (XEXP (x, 0), mode, unaligned_mems)
+	  && GET_CODE (XEXP (x, 1)) == CONST_INT)
+	{
+	  HOST_WIDE_INT offset;
+
+	  if (!STRICT_ALIGNMENT || !unaligned_mems)
+	    return 0;
+
+	  offset = INTVAL (XEXP (x, 1));
+
+#ifdef SPARC_STACK_BOUNDARY_HACK
+	  /* ??? The SPARC port may claim a STACK_BOUNDARY higher than
+	     the real alignment of %sp.  However, when it does this, the
+	     alignment of %sp+STACK_POINTER_OFFSET is STACK_BOUNDARY.  */
+	  if (SPARC_STACK_BOUNDARY_HACK
+	      && (XEXP (x, 0) == stack_pointer_rtx
+		  || XEXP (x, 0) == hard_frame_pointer_rtx))
+	    offset -= STACK_POINTER_OFFSET;
+#endif
+
+	  return offset % GET_MODE_SIZE (mode) != 0;
+	}
+
+      /* - or it is the pic register plus a constant.  */
+      if (XEXP (x, 0) == pic_offset_table_rtx && CONSTANT_P (XEXP (x, 1)))
+	return 0;
+
+      return 1;
 
     case LO_SUM:
     case PRE_MODIFY:
-      return rtx_addr_can_trap_p (XEXP (x, 1));
+      return rtx_addr_can_trap_p_1 (XEXP (x, 1), mode, unaligned_mems);
 
     case PRE_DEC:
     case PRE_INC:
     case POST_DEC:
     case POST_INC:
     case POST_MODIFY:
-      return rtx_addr_can_trap_p (XEXP (x, 0));
+      return rtx_addr_can_trap_p_1 (XEXP (x, 0), mode, unaligned_mems);
 
     default:
       break;
@@ -282,6 +310,14 @@ rtx_addr_can_trap_p (rtx x)
   return 1;
 }
 
+/* Return nonzero if the use of X as an address in a MEM can cause a trap.  */
+
+int
+rtx_addr_can_trap_p (rtx x)
+{
+  return rtx_addr_can_trap_p_1 (x, VOIDmode, false);
+}
+
 /* Return true if X is an address that is known to not be zero.  */
 
 bool
@@ -2065,10 +2101,12 @@ side_effects_p (rtx x)
   return 0;
 }
 
-/* Return nonzero if evaluating rtx X might cause a trap.  */
+/* Return nonzero if evaluating rtx X might cause a trap.  UNALIGNED_MEMS
+   controls whether nonzero is returned for unaligned memory accesses on
+   strict alignment machines.  */
 
-int
-may_trap_p (rtx x)
+static int
+may_trap_p_1 (rtx x, bool unaligned_mems)
 {
   int i;
   enum rtx_code code;
@@ -2102,9 +2140,11 @@ may_trap_p (rtx x)
 
       /* Memory ref can trap unless it's a static var or a stack slot.  */
     case MEM:
-      if (MEM_NOTRAP_P (x))
+      if (MEM_NOTRAP_P (x)
+	  && (!STRICT_ALIGNMENT || !unaligned_mems))
 	return 0;
-      return rtx_addr_can_trap_p (XEXP (x, 0));
+      return
+	rtx_addr_can_trap_p_1 (XEXP (x, 0), GET_MODE (x), unaligned_mems);
 
       /* Division by a non-constant might trap.  */
     case DIV:
@@ -2180,19 +2220,73 @@ may_trap_p (rtx x)
     {
       if (fmt[i] == 'e')
 	{
-	  if (may_trap_p (XEXP (x, i)))
+	  if (may_trap_p_1 (XEXP (x, i), unaligned_mems))
 	    return 1;
 	}
       else if (fmt[i] == 'E')
 	{
 	  int j;
 	  for (j = 0; j < XVECLEN (x, i); j++)
-	    if (may_trap_p (XVECEXP (x, i, j)))
+	    if (may_trap_p_1 (XVECEXP (x, i, j), unaligned_mems))
 	      return 1;
 	}
     }
   return 0;
 }
+
+/* Return nonzero if evaluating rtx X might cause a trap.  */
+
+int
+may_trap_p (rtx x)
+{
+  return may_trap_p_1 (x, false);
+}
+
+/* Same as above, but additionally return non-zero if evaluating rtx X might
+   cause a fault.  We define a fault for the purpose of this function as a
+   erroneous execution condition that cannot be encountered during the normal
+   execution of a valid program; the typical example is an unaligned memory
+   access on a strict alignment machine.  The compiler guarantees that it
+   doesn't generate code that will fault from a valid program, but this
+   guarantee doesn't mean anything for individual instructions.  Consider
+   the following example:
+
+      struct S { int d; union { char *cp; int *ip; }; };
+
+      int foo(struct S *s)
+      {
+	if (s->d == 1)
+	  return *s->ip;
+	else
+	  return *s->cp;
+      }
+
+   on a strict alignment machine.  In a valid program, foo will never be
+   invoked on a structure for which d is equal to 1 and the underlying
+   unique field of the union not aligned on a 4-byte boundary, but the
+   expression *s->ip might cause a fault if considered individually.
+
+   At the RTL level, potentially problematic expressions will almost always
+   verify may_trap_p; for example, the above dereference can be emitted as
+   (mem:SI (reg:P)) and this expression is may_trap_p for a generic register.
+   However, suppose that foo is inlined in a caller that causes s->cp to
+   point to a local character variable and guarantees that s->d is not set
+   to 1; foo may have been effectively translated into pseudo-RTL as:
+
+      if ((reg:SI) == 1)
+	(set (reg:SI) (mem:SI (%fp - 7)))
+      else
+	(set (reg:QI) (mem:QI (%fp - 7)))
+
+   Now (mem:SI (%fp - 7)) is considered as not may_trap_p since it is a
+   memory reference to a stack slot, but it will certainly cause a fault
+   on a strict alignment machine.  */
+
+int
+may_trap_or_fault_p (rtx x)
+{
+  return may_trap_p_1 (x, true);
+}
 
 /* Return nonzero if X contains a comparison that is not either EQ or NE,
    i.e., an inequality.  */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7a536a72c187..82e1f048e183 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2005-10-20  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+	* g++.dg/opt/delay-slot-1.C: New test.
+
 2005-10-20  Erik Edelmann  <erik.edelmann@iki.fi>
 
 	PR fortran/21625
diff --git a/gcc/testsuite/g++.dg/opt/delay-slot-1.C b/gcc/testsuite/g++.dg/opt/delay-slot-1.C
new file mode 100644
index 000000000000..e180e48105e1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/delay-slot-1.C
@@ -0,0 +1,111 @@
+/* PR rtl-optimization/23585 */
+/* Testcase by Matti Rintala <matti.rintala@iki.fi> */
+
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+template <class _Ret, class _Tp>
+class const_mem_fun_t
+{
+public:
+  explicit
+  const_mem_fun_t(_Ret (_Tp::*__pf)() const)
+    : _M_f(__pf) {}
+  
+  _Ret
+  operator()(const _Tp* __p) const
+  { return (__p->*_M_f)(); }
+private:
+  _Ret (_Tp::*_M_f)() const;
+};
+
+template <class _Ret, class _Tp>
+class const_mem_fun_ref_t
+{
+public:
+  explicit
+  const_mem_fun_ref_t(_Ret (_Tp::*__pf)() const)
+    : _M_f(__pf) {}
+  
+  _Ret
+  operator()(const _Tp& __r) const
+  { return (__r.*_M_f)(); }
+private:
+  _Ret (_Tp::*_M_f)() const;
+};
+
+template <class _Ret, class _Tp, class _Arg>
+class const_mem_fun1_t
+{
+public:
+  explicit
+  const_mem_fun1_t(_Ret (_Tp::*__pf)(_Arg) const)
+    : _M_f(__pf) {}
+  
+  _Ret
+  operator()(const _Tp* __p, _Arg __x) const
+  { return (__p->*_M_f)(__x); }
+private:
+  _Ret (_Tp::*_M_f)(_Arg) const;
+};
+
+
+template <class _Ret, class _Tp, class _Arg>
+class const_mem_fun1_ref_t
+{
+public:
+  explicit
+  const_mem_fun1_ref_t(_Ret (_Tp::*__pf)(_Arg) const)
+    : _M_f(__pf) {}
+  
+  _Ret
+  operator()(const _Tp& __r, _Arg __x) const
+  { return (__r.*_M_f)(__x); }
+private:
+  _Ret (_Tp::*_M_f)(_Arg) const;
+};
+
+template <class _Ret, class _Tp>
+inline const_mem_fun_t<_Ret, _Tp>
+mem_fun(_Ret (_Tp::*__f)() const)
+{ return const_mem_fun_t<_Ret, _Tp>(__f); }
+
+template <class _Ret, class _Tp>
+inline const_mem_fun_ref_t<_Ret, _Tp>
+mem_fun_ref(_Ret (_Tp::*__f)() const)
+{ return const_mem_fun_ref_t<_Ret, _Tp>(__f); }
+
+template <class _Ret, class _Tp, class _Arg>
+inline const_mem_fun1_t<_Ret, _Tp, _Arg>
+mem_fun(_Ret (_Tp::*__f)(_Arg) const)
+{ return const_mem_fun1_t<_Ret, _Tp, _Arg>(__f); }
+
+template <class _Ret, class _Tp, class _Arg>
+inline const_mem_fun1_ref_t<_Ret, _Tp, _Arg>
+mem_fun_ref(_Ret (_Tp::*__f)(_Arg) const)
+{ return const_mem_fun1_ref_t<_Ret, _Tp, _Arg>(__f); }
+
+class Class {
+public:
+  void vf0c() const;
+  void vf1c(const int&) const;
+};
+
+int main()
+{
+  Class obj;
+  const Class& objc = obj;
+
+  mem_fun(&Class::vf0c)(&objc);
+  mem_fun(&Class::vf1c)(&objc, 1);
+
+  mem_fun_ref(&Class::vf0c)(objc);
+  mem_fun_ref(&Class::vf1c)(objc, 1);
+  return 0;
+}
+
+void Class::vf0c() const
+{}
+
+void Class::vf1c(const int&) const
+{}