diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fc8466f020b1ac87683a7a7031e6c0d69ae9b724..7197965da33b26a546717619a76c52666e72719e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2005-09-10  Richard Henderson  <rth@redhat.com>
+
+	PR debug/23806
+	* dbxout.c (dbxout_expand_expr): New.
+	(dbxout_symbol): Use it.
+
 2005-09-10  Richard Earnshaw  <richard.earnshaw@arm.com>
 
 	* arm.c (arm_gen_rotated_half_load): Delete.
diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 48c00b5100a3b49867be82c786a609e7308faa95..d295ac7612abae9166f6b9738a8700df9fe158da 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -2324,6 +2324,63 @@ dbxout_class_name_qualifiers (tree decl)
     }
 }
 
+/* This is a specialized subset of expand_expr for use by dbxout_symbol in
+   evaluating DECL_VALUE_EXPR.  In particular, we stop if we find decls that
+   havn't been expanded, or if the expression is getting so complex we won't
+   be able to represent it in stabs anyway.  Returns NULL on failure.  */
+
+static rtx
+dbxout_expand_expr (tree expr)
+{
+  switch (TREE_CODE (expr))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+      if (DECL_HAS_VALUE_EXPR_P (expr))
+	return dbxout_expand_expr (DECL_VALUE_EXPR (expr));
+      /* FALLTHRU */
+
+    case CONST_DECL:
+    case RESULT_DECL:
+      return DECL_RTL_IF_SET (expr);
+
+    case INTEGER_CST:
+      return expand_expr (expr, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+
+    case COMPONENT_REF:
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case BIT_FIELD_REF:
+      {
+	enum machine_mode mode;
+	HOST_WIDE_INT bitsize, bitpos;
+	tree offset, tem;
+	int volatilep = 0, unsignedp = 0;
+	rtx x;
+
+	tem = get_inner_reference (expr, &bitsize, &bitpos, &offset,
+				   &mode, &unsignedp, &volatilep, true);
+
+	x = dbxout_expand_expr (tem);
+	if (x == NULL || !MEM_P (x))
+	  return NULL;
+	if (offset != NULL)
+	  {
+	    if (!host_integerp (offset, 0))
+	      return NULL;
+	    x = adjust_address_nv (x, mode, tree_low_cst (offset, 0));
+	  }
+	if (bitpos != 0)
+	  x = adjust_address_nv (x, mode, bitpos / BITS_PER_UNIT);
+
+	return x;
+      }
+
+    default:
+      return NULL;
+    }
+}
+
 /* Output a .stabs for the symbol defined by DECL,
    which must be a ..._DECL node in the normal namespace.
    It may be a CONST_DECL, a FUNCTION_DECL, a PARM_DECL or a VAR_DECL.
@@ -2608,23 +2665,13 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED)
       gcc_unreachable ();
 
     case RESULT_DECL:
-      /* Named return value, treat like a VAR_DECL.  */
-      decl_rtl = DECL_RTL_IF_SET (decl);
-      goto do_var_decl;
-
     case VAR_DECL:
       /* Don't mention a variable that is external.
 	 Let the file that defines it describe it.  */
       if (DECL_EXTERNAL (decl))
 	break;
 
-      if (DECL_HAS_VALUE_EXPR_P (decl))
-	decl_rtl = expand_expr (DECL_VALUE_EXPR (decl), NULL_RTX, VOIDmode,
-				EXPAND_INITIALIZER);
-      else
-	decl_rtl = DECL_RTL_IF_SET (decl);
-
-    do_var_decl:
+      decl_rtl = dbxout_expand_expr (decl);
       if (!decl_rtl)
 	DBXOUT_DECR_NESTING_AND_RETURN (0);