OSDN Git Service

* config/freebsd-spec.h (FBSD_CPP_PREDEFINES): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index b2a0438..445f325 100644 (file)
@@ -1,6 +1,6 @@
 /* Output Dwarf2 format symbol table information from the GNU C compiler.
-   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
-   Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003 Free Software Foundation, Inc.
    Contributed by Gary Funck (gary@intrepid.com).
    Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
    Extensively modified by Jason Merrill (jason@cygnus.com).
@@ -279,10 +279,8 @@ static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table;
 /* Number of elements currently allocated for fde_table.  */
 static unsigned fde_table_allocated;
 
-#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
 /* Number of elements in fde_table currently in use.  */
-static unsigned fde_table_in_use;
-#endif
+static GTY(()) unsigned fde_table_in_use;
 
 /* Size (in elements) of increments by which we may expand the
    fde_table.  */
@@ -310,6 +308,7 @@ struct indirect_string_node GTY(())
 static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
 
 static GTY(()) int dw2_string_counter;
+static GTY(()) unsigned long dwarf2out_cfi_label_num;
 
 #if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
 
@@ -338,7 +337,7 @@ static void dwarf2out_frame_debug_expr      PARAMS ((rtx, const char *));
 /* Support for complex CFA locations.  */
 static void output_cfa_loc             PARAMS ((dw_cfi_ref));
 static void get_cfa_from_loc_descr     PARAMS ((dw_cfa_location *,
-                                               struct dw_loc_descr_struct *));
+                                               struct dw_loc_descr_struct *));
 static struct dw_loc_descr_struct *build_cfa_loc
                                        PARAMS ((dw_cfa_location *));
 static void def_cfa_1                  PARAMS ((const char *,
@@ -561,9 +560,8 @@ char *
 dwarf2out_cfi_label ()
 {
   static char label[20];
-  static unsigned long label_num = 0;
 
-  ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++);
+  ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", dwarf2out_cfi_label_num++);
   ASM_OUTPUT_LABEL (asm_out_file, label);
   return label;
 }
@@ -1238,7 +1236,7 @@ static dw_cfa_location cfa_temp;
   Rule 1:
   (set <reg1> <reg2>:cfa.reg)
   effects: cfa.reg = <reg1>
-           cfa.offset unchanged
+          cfa.offset unchanged
           cfa_temp.reg = <reg1>
           cfa_temp.offset = cfa.offset
 
@@ -1359,7 +1357,7 @@ dwarf2out_frame_debug_expr (expr, label)
     case REG:
       /* Rule 1 */
       /* Update the CFA rule wrt SP or FP.  Make sure src is
-         relative to the current CFA register.  */
+        relative to the current CFA register.  */
       switch (GET_CODE (src))
        {
          /* Setting FP from SP.  */
@@ -1622,7 +1620,7 @@ dwarf2out_frame_debug_expr (expr, label)
          else
            {
              /* Otherwise, we'll need to look in the stack to
-                 calculate the CFA.  */
+                calculate the CFA.  */
              rtx x = XEXP (dest, 0);
 
              if (GET_CODE (x) != REG)
@@ -2125,13 +2123,13 @@ output_call_frame_info (for_eh)
              dw2_asm_output_data_uleb128 (size, "Augmentation size");
 
              if (fde->uses_eh_lsda)
-               {
-                 ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
+               {
+                 ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
                                               fde->funcdef_number);
-                 dw2_asm_output_encoded_addr_rtx (
+                 dw2_asm_output_encoded_addr_rtx (
                        lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
                        "Language Specific Data Area");
-               }
+               }
              else
                {
                  if (lsda_encoding == DW_EH_PE_aligned)
@@ -2153,7 +2151,7 @@ output_call_frame_info (for_eh)
 
       /* Pad the FDE out to an address sized boundary.  */
       ASM_OUTPUT_ALIGN (asm_out_file,
-                       floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
+                       floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
       ASM_OUTPUT_LABEL (asm_out_file, l2);
     }
 
@@ -2955,9 +2953,9 @@ output_loc_operands (loc)
     case DW_OP_skip:
     case DW_OP_bra:
       /* We currently don't make any attempt to make sure these are
-         aligned properly like we do for the main unwind info, so
-         don't support emitting things larger than a byte if we're
-         only doing unwinding.  */
+        aligned properly like we do for the main unwind info, so
+        don't support emitting things larger than a byte if we're
+        only doing unwinding.  */
       abort ();
 #endif
     case DW_OP_const1u:
@@ -3460,6 +3458,7 @@ static GTY(()) limbo_die_node *limbo_die_list;
 
 /* Filenames referenced by this compilation unit.  */
 static GTY(()) varray_type file_table;
+static GTY(()) varray_type file_table_emitted;
 static GTY(()) size_t file_table_last_lookup_index;
 
 /* A pointer to the base of a table of references to DIE's that describe
@@ -3753,6 +3752,8 @@ static dw_die_ref modified_type_die       PARAMS ((tree, int, int, dw_die_ref));
 static int type_is_enum                        PARAMS ((tree));
 static unsigned int reg_number         PARAMS ((rtx));
 static dw_loc_descr_ref reg_loc_descriptor PARAMS ((rtx));
+static dw_loc_descr_ref one_reg_loc_descriptor PARAMS ((unsigned int));
+static dw_loc_descr_ref multiple_reg_loc_descriptor PARAMS ((rtx, rtx));
 static dw_loc_descr_ref int_loc_descriptor PARAMS ((HOST_WIDE_INT));
 static dw_loc_descr_ref based_loc_descr        PARAMS ((unsigned, long));
 static int is_based_loc                        PARAMS ((rtx));
@@ -3820,7 +3821,7 @@ static void gen_field_die         PARAMS ((tree, dw_die_ref));
 static void gen_ptr_to_mbr_type_die    PARAMS ((tree, dw_die_ref));
 static dw_die_ref gen_compile_unit_die PARAMS ((const char *));
 static void gen_string_type_die                PARAMS ((tree, dw_die_ref));
-static void gen_inheritance_die                PARAMS ((tree, dw_die_ref));
+static void gen_inheritance_die                PARAMS ((tree, tree, dw_die_ref));
 static void gen_member_die             PARAMS ((tree, dw_die_ref));
 static void gen_struct_or_union_type_die PARAMS ((tree, dw_die_ref));
 static void gen_subroutine_type_die    PARAMS ((tree, dw_die_ref));
@@ -3846,6 +3847,14 @@ static void add_loc_descr_to_loc_list   PARAMS ((dw_loc_list_ref *,
 static void output_loc_list            PARAMS ((dw_loc_list_ref));
 static char *gen_internal_sym          PARAMS ((const char *));
 
+static void prune_unmark_dies          PARAMS ((dw_die_ref));
+static void prune_unused_types_mark     PARAMS ((dw_die_ref, int));
+static void prune_unused_types_walk     PARAMS ((dw_die_ref));
+static void prune_unused_types_walk_attribs PARAMS ((dw_die_ref));
+static void prune_unused_types_prune    PARAMS ((dw_die_ref));
+static void prune_unused_types          PARAMS ((void));
+static int maybe_emit_file              PARAMS ((int));
+
 /* Section names used to hold DWARF debugging information.  */
 #ifndef DEBUG_INFO_SECTION
 #define DEBUG_INFO_SECTION     ".debug_info"
@@ -5219,6 +5228,7 @@ splice_child_die (parent, child)
        break;
       }
 
+  child->die_parent = parent;
   child->die_sib = parent->die_child;
   parent->die_child = child;
 }
@@ -5701,12 +5711,12 @@ same_dw_val_p (v1, v2, mark)
       return v1->v.val_unsigned == v2->v.val_unsigned;
     case dw_val_class_long_long:
       return v1->v.val_long_long.hi == v2->v.val_long_long.hi
-             && v1->v.val_long_long.low == v2->v.val_long_long.low;
+            && v1->v.val_long_long.low == v2->v.val_long_long.low;
     case dw_val_class_float:
       if (v1->v.val_float.length != v2->v.val_float.length)
        return 0;
       for (i = 0; i < v1->v.val_float.length; i++)
-        if (v1->v.val_float.array[i] != v2->v.val_float.array[i])
+       if (v1->v.val_float.array[i] != v2->v.val_float.array[i])
          return 0;
       return 1;
     case dw_val_class_flag:
@@ -6147,7 +6157,7 @@ break_out_includes (die)
       if (is_dupl)
        *pnode = node->next;
       else
-        {
+       {
          pnode = &node->next;
          record_comdat_symbol_number (node->die, cu_hash_table,
                comdat_symbol_number);
@@ -6339,7 +6349,10 @@ size_of_die (die)
          size += 1;
          break;
        case dw_val_class_die_ref:
-         size += DWARF_OFFSET_SIZE;
+         if (AT_ref_external (a))
+           size += DWARF2_ADDR_SIZE;
+         else
+           size += DWARF_OFFSET_SIZE;
          break;
        case dw_val_class_fde_ref:
          size += DWARF_OFFSET_SIZE;
@@ -7080,7 +7093,7 @@ output_aranges ()
   if (DWARF_ARANGES_PAD_SIZE)
     {
       /* Pad using a 2 byte words so that padding is correct for any
-         pointer size.  */
+        pointer size.  */
       dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
                           2 * DWARF2_ADDR_SIZE);
       for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
@@ -7291,6 +7304,14 @@ output_file_names ()
   size_t i;
   int idx;
 
+  /* Handle the case where file_table is empty.  */
+  if (VARRAY_ACTIVE_SIZE (file_table) <= 1)
+    {
+      dw2_asm_output_data (1, 0, "End directory table");
+      dw2_asm_output_data (1, 0, "End file name table");
+      return;
+    }
+
   /* Allocate the various arrays we need.  */
   files = (struct file_info *) alloca (VARRAY_ACTIVE_SIZE (file_table)
                                       * sizeof (struct file_info));
@@ -7576,8 +7597,8 @@ output_line_info ()
         prologue.  */
 
       /* Don't emit anything for redundant notes.  Just updating the
-         address doesn't accomplish anything, because we already assume
-         that anything after the last address is this line.  */
+        address doesn't accomplish anything, because we already assume
+        that anything after the last address is this line.  */
       if (line_info->dw_line_num == current_line
          && line_info->dw_file_num == current_file)
        continue;
@@ -7603,7 +7624,7 @@ output_line_info ()
       else
        {
          /* This can handle any delta.  This takes
-             4+DWARF2_ADDR_SIZE bytes.  */
+            4+DWARF2_ADDR_SIZE bytes.  */
          dw2_asm_output_data (1, 0, "DW_LNE_set_address");
          dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
          dw2_asm_output_data (1, DW_LNE_set_address, NULL);
@@ -7825,9 +7846,9 @@ base_type_die (type)
     {
     case INTEGER_TYPE:
       /* Carefully distinguish the C character types, without messing
-         up if the language is not C. Note that we check only for the names
-         that contain spaces; other names might occur by coincidence in other
-         languages.  */
+        up if the language is not C. Note that we check only for the names
+        that contain spaces; other names might occur by coincidence in other
+        languages.  */
       if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
             && (type == char_type_node
                 || ! strcmp (type_name, "signed char")
@@ -8139,24 +8160,90 @@ reg_number (rtl)
 }
 
 /* Return a location descriptor that designates a machine register or
-   zero if there is no such.  */
+   zero if there is none.  */
 
 static dw_loc_descr_ref
 reg_loc_descriptor (rtl)
      rtx rtl;
 {
-  dw_loc_descr_ref loc_result = NULL;
   unsigned reg;
+  rtx regs;
 
   if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
     return 0;
 
   reg = reg_number (rtl);
-  if (reg <= 31)
-    loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0);
+  regs = (*targetm.dwarf_register_span) (rtl);
+
+  if (HARD_REGNO_NREGS (reg, GET_MODE (rtl)) > 1
+      || regs)
+    return multiple_reg_loc_descriptor (rtl, regs);
+  else
+    return one_reg_loc_descriptor (reg);
+}
+
+/* Return a location descriptor that designates a machine register for
+   a given hard register number.  */
+
+static dw_loc_descr_ref
+one_reg_loc_descriptor (regno)
+     unsigned int regno;
+{
+  if (regno <= 31)
+    return new_loc_descr (DW_OP_reg0 + regno, 0, 0);
   else
-    loc_result = new_loc_descr (DW_OP_regx, reg, 0);
+    return new_loc_descr (DW_OP_regx, regno, 0);
+}
+
+/* Given an RTL of a register, return a location descriptor that
+   designates a value that spans more than one register.  */
 
+static dw_loc_descr_ref
+multiple_reg_loc_descriptor (rtl, regs)
+     rtx rtl, regs;
+{
+  int nregs, size, i;
+  unsigned reg;
+  dw_loc_descr_ref loc_result = NULL;
+
+  reg = reg_number (rtl);
+  nregs = HARD_REGNO_NREGS (reg, GET_MODE (rtl));
+
+  /* Simple, contiguous registers.  */
+  if (regs == NULL_RTX)
+    {
+      size = GET_MODE_SIZE (GET_MODE (rtl)) / nregs;
+
+      loc_result = NULL;
+      while (nregs--)
+       {
+         dw_loc_descr_ref t;
+
+         t = one_reg_loc_descriptor (reg);
+         add_loc_descr (&loc_result, t);
+         add_loc_descr (&loc_result, new_loc_descr (DW_OP_piece, size, 0));
+         ++reg;
+       }
+      return loc_result;
+    }
+
+  /* Now onto stupid register sets in non contiguous locations.  */
+
+  if (GET_CODE (regs) != PARALLEL)
+    abort ();
+
+  size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+  loc_result = NULL;
+
+  for (i = 0; i < XVECLEN (regs, 0); ++i)
+    {
+      dw_loc_descr_ref t;
+
+      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)));
+      add_loc_descr (&loc_result, t);
+      size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
+      add_loc_descr (&loc_result, new_loc_descr (DW_OP_piece, size, 0));
+    }
   return loc_result;
 }
 
@@ -8264,9 +8351,7 @@ mem_loc_descriptor (rtl, mode)
      actually within the array.  That's *not* necessarily the same as the
      zeroth element of the array.  */
 
-#ifdef ASM_SIMPLIFY_DWARF_ADDR
-  rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
-#endif
+  rtl = (*targetm.delegitimize_address) (rtl);
 
   switch (GET_CODE (rtl))
     {
@@ -8280,28 +8365,28 @@ mem_loc_descriptor (rtl, mode)
 
     case SUBREG:
       /* The case of a subreg may arise when we have a local (register)
-         variable or a formal (register) parameter which doesn't quite fill
-         up an entire register.  For now, just assume that it is
-         legitimate to make the Dwarf info refer to the whole register which
-         contains the given subreg.  */
+        variable or a formal (register) parameter which doesn't quite fill
+        up an entire register.  For now, just assume that it is
+        legitimate to make the Dwarf info refer to the whole register which
+        contains the given subreg.  */
       rtl = SUBREG_REG (rtl);
 
       /* ... fall through ...  */
 
     case REG:
       /* Whenever a register number forms a part of the description of the
-         method for calculating the (dynamic) address of a memory resident
-         object, DWARF rules require the register number be referred to as
-         a "base register".  This distinction is not based in any way upon
-         what category of register the hardware believes the given register
-         belongs to.  This is strictly DWARF terminology we're dealing with
-         here. Note that in cases where the location of a memory-resident
-         data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
-         OP_CONST (0)) the actual DWARF location descriptor that we generate
-         may just be OP_BASEREG (basereg).  This may look deceptively like
-         the object in question was allocated to a register (rather than in
-         memory) so DWARF consumers need to be aware of the subtle
-         distinction between OP_REG and OP_BASEREG.  */
+        method for calculating the (dynamic) address of a memory resident
+        object, DWARF rules require the register number be referred to as
+        a "base register".  This distinction is not based in any way upon
+        what category of register the hardware believes the given register
+        belongs to.  This is strictly DWARF terminology we're dealing with
+        here. Note that in cases where the location of a memory-resident
+        data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
+        OP_CONST (0)) the actual DWARF location descriptor that we generate
+        may just be OP_BASEREG (basereg).  This may look deceptively like
+        the object in question was allocated to a register (rather than in
+        memory) so DWARF consumers need to be aware of the subtle
+        distinction between OP_REG and OP_BASEREG.  */
       if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
        mem_loc_result = based_loc_descr (reg_number (rtl), 0);
       break;
@@ -8350,7 +8435,7 @@ mem_loc_descriptor (rtl, mode)
 
     case PRE_MODIFY:
       /* Extract the PLUS expression nested inside and fall into
-         PLUS code below.  */
+        PLUS code below.  */
       rtl = XEXP (rtl, 1);
       goto plus;
 
@@ -8471,10 +8556,10 @@ loc_descriptor (rtl)
     {
     case SUBREG:
       /* The case of a subreg may arise when we have a local (register)
-         variable or a formal (register) parameter which doesn't quite fill
-         up an entire register.  For now, just assume that it is
-         legitimate to make the Dwarf info refer to the whole register which
-         contains the given subreg.  */
+        variable or a formal (register) parameter which doesn't quite fill
+        up an entire register.  For now, just assume that it is
+        legitimate to make the Dwarf info refer to the whole register which
+        contains the given subreg.  */
       rtl = SUBREG_REG (rtl);
 
       /* ... fall through ...  */
@@ -9195,9 +9280,9 @@ add_const_value_attribute (die, rtl)
 
     case CONST_DOUBLE:
       /* Note that a CONST_DOUBLE rtx could represent either an integer or a
-         floating-point constant.  A CONST_DOUBLE is used whenever the
-         constant requires more than one word in order to be adequately
-         represented.  We output CONST_DOUBLEs as blocks.  */
+        floating-point constant.  A CONST_DOUBLE is used whenever the
+        constant requires more than one word in order to be adequately
+        represented.  We output CONST_DOUBLEs as blocks.  */
       {
        enum machine_mode mode = GET_MODE (rtl);
 
@@ -9254,16 +9339,16 @@ add_const_value_attribute (die, rtl)
 
     case PLUS:
       /* In cases where an inlined instance of an inline function is passed
-         the address of an `auto' variable (which is local to the caller) we
-         can get a situation where the DECL_RTL of the artificial local
-         variable (for the inlining) which acts as a stand-in for the
-         corresponding formal parameter (of the inline function) will look
-         like (plus:SI (reg:SI FRAME_PTR) (const_int ...)).  This is not
-         exactly a compile-time constant expression, but it isn't the address
-         of the (artificial) local variable either.  Rather, it represents the
-         *value* which the artificial local variable always has during its
-         lifetime.  We currently have no way to represent such quasi-constant
-         values in Dwarf, so for now we just punt and generate nothing.  */
+        the address of an `auto' variable (which is local to the caller) we
+        can get a situation where the DECL_RTL of the artificial local
+        variable (for the inlining) which acts as a stand-in for the
+        corresponding formal parameter (of the inline function) will look
+        like (plus:SI (reg:SI FRAME_PTR) (const_int ...)).  This is not
+        exactly a compile-time constant expression, but it isn't the address
+        of the (artificial) local variable either.  Rather, it represents the
+        *value* which the artificial local variable always has during its
+        lifetime.  We currently have no way to represent such quasi-constant
+        values in Dwarf, so for now we just punt and generate nothing.  */
       break;
 
     default:
@@ -9356,17 +9441,19 @@ rtl_for_decl_location (decl)
   rtl = DECL_RTL_IF_SET (decl);
 
   /* When generating abstract instances, ignore everything except
-     constants and symbols living in memory.  */
+     constants, symbols living in memory, and symbols living in
+     fixed registers.  */
   if (! reload_completed)
     {
       if (rtl
          && (CONSTANT_P (rtl)
              || (GET_CODE (rtl) == MEM
-                 && CONSTANT_P (XEXP (rtl, 0)))))
+                 && CONSTANT_P (XEXP (rtl, 0)))
+             || (GET_CODE (rtl) == REG
+                 && TREE_CODE (decl) == VAR_DECL
+                 && TREE_STATIC (decl))))
        {
-#ifdef ASM_SIMPLIFY_DWARF_ADDR
-         rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
-#endif
+         rtl = (*targetm.delegitimize_address) (rtl);
          return rtl;
        }
       rtl = NULL_RTX;
@@ -9472,10 +9559,8 @@ rtl_for_decl_location (decl)
        }
     }
 
-#ifdef ASM_SIMPLIFY_DWARF_ADDR
   if (rtl)
-    rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
-#endif
+    rtl = (*targetm.delegitimize_address) (rtl);
 
   /* If we don't look past the constant pool, we risk emitting a
      reference to a constant pool entry that isn't referenced from
@@ -9653,23 +9738,23 @@ add_bound_info (subrange_die, bound_attr, bound)
 
     case SAVE_EXPR:
       /* If optimization is turned on, the SAVE_EXPRs that describe how to
-         access the upper bound values may be bogus.  If they refer to a
-         register, they may only describe how to get at these values at the
-         points in the generated code right after they have just been
-         computed.  Worse yet, in the typical case, the upper bound values
-         will not even *be* computed in the optimized code (though the
-         number of elements will), so these SAVE_EXPRs are entirely
-         bogus. In order to compensate for this fact, we check here to see
-         if optimization is enabled, and if so, we don't add an attribute
-         for the (unknown and unknowable) upper bound.  This should not
-         cause too much trouble for existing (stupid?)  debuggers because
-         they have to deal with empty upper bounds location descriptions
-         anyway in order to be able to deal with incomplete array types.
-         Of course an intelligent debugger (GDB?)  should be able to
-         comprehend that a missing upper bound specification in an array
-         type used for a storage class `auto' local array variable
-         indicates that the upper bound is both unknown (at compile- time)
-         and unknowable (at run-time) due to optimization.
+        access the upper bound values may be bogus.  If they refer to a
+        register, they may only describe how to get at these values at the
+        points in the generated code right after they have just been
+        computed.  Worse yet, in the typical case, the upper bound values
+        will not even *be* computed in the optimized code (though the
+        number of elements will), so these SAVE_EXPRs are entirely
+        bogus. In order to compensate for this fact, we check here to see
+        if optimization is enabled, and if so, we don't add an attribute
+        for the (unknown and unknowable) upper bound.  This should not
+        cause too much trouble for existing (stupid?)  debuggers because
+        they have to deal with empty upper bounds location descriptions
+        anyway in order to be able to deal with incomplete array types.
+        Of course an intelligent debugger (GDB?)  should be able to
+        comprehend that a missing upper bound specification in an array
+        type used for a storage class `auto' local array variable
+        indicates that the upper bound is both unknown (at compile- time)
+        and unknowable (at run-time) due to optimization.
 
         We assume that a MEM rtx is safe because gcc wouldn't put the
         value there unless it was going to be used repeatedly in the
@@ -9790,7 +9875,7 @@ add_subscript_info (type_die, type)
 
       /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
         and (in GNU C only) variable bounds.  Handle all three forms
-         here.  */
+        here.  */
       subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
       if (domain)
        {
@@ -9852,9 +9937,9 @@ add_byte_size_attribute (die, tree_node)
       break;
     case FIELD_DECL:
       /* For a data member of a struct or union, the DW_AT_byte_size is
-         generally given as the number of bytes normally allocated for an
-         object of the *declared* type of the member itself.  This is true
-         even for bit-fields.  */
+        generally given as the number of bytes normally allocated for an
+        object of the *declared* type of the member itself.  This is true
+        even for bit-fields.  */
       size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
       break;
     default:
@@ -9979,7 +10064,7 @@ add_abstract_origin_attribute (die, origin)
         function, if we're in an exception handler or some such; make
         sure that the abstract function has been written out.
 
-         Doing this for nested functions is wrong, however; functions are
+        Doing this for nested functions is wrong, however; functions are
         distinct units, and our context might not even be inline.  */
       tree fn = origin;
 
@@ -10239,8 +10324,8 @@ type_tag (type)
        t = TYPE_NAME (type);
 
       /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
-         a TYPE_DECL node, regardless of whether or not a `typedef' was
-         involved.  */
+        a TYPE_DECL node, regardless of whether or not a `typedef' was
+        involved.  */
       else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
               && ! DECL_IGNORED_P (TYPE_NAME (type)))
        t = DECL_NAME (TYPE_NAME (type));
@@ -10888,8 +10973,8 @@ gen_subprogram_die (decl, context_die)
 #endif
 
       /* Define the "frame base" location for this routine.  We use the
-         frame pointer or stack pointer registers, since the RTL for local
-         variables is relative to one of them.  */
+        frame pointer or stack pointer registers, since the RTL for local
+        variables is relative to one of them.  */
       fp_reg
        = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
       add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
@@ -10927,7 +11012,7 @@ gen_subprogram_die (decl, context_die)
       tree parm;
 
       /* When generating DIEs, generate the unspecified_parameters DIE
-         instead if we come across the arg "__builtin_va_alist" */
+        instead if we come across the arg "__builtin_va_alist" */
       for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
        if (TREE_CODE (parm) == PARM_DECL)
          {
@@ -10940,11 +11025,11 @@ gen_subprogram_die (decl, context_die)
          }
 
       /* Decide whether we need an unspecified_parameters DIE at the end.
-         There are 2 more cases to do this for: 1) the ansi ... declaration -
-         this is detectable when the end of the arg list is not a
-         void_type_node 2) an unprototyped function declaration (not a
-         definition).  This just means that we have no info about the
-         parameters at all.  */
+        There are 2 more cases to do this for: 1) the ansi ... declaration -
+        this is detectable when the end of the arg list is not a
+        void_type_node 2) an unprototyped function declaration (not a
+        definition).  This just means that we have no info about the
+        parameters at all.  */
       fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
       if (fn_arg_types != NULL)
        {
@@ -11363,8 +11448,8 @@ gen_string_type_die (type, context_die)
 /* Generate the DIE for a base class.  */
 
 static void
-gen_inheritance_die (binfo, context_die)
-     tree binfo;
+gen_inheritance_die (binfo, access, context_die)
+     tree binfo, access;
      dw_die_ref context_die;
 {
   dw_die_ref die = new_die (DW_TAG_inheritance, context_die, binfo);
@@ -11375,9 +11460,9 @@ gen_inheritance_die (binfo, context_die)
   if (TREE_VIA_VIRTUAL (binfo))
     add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
 
-  if (TREE_VIA_PUBLIC (binfo))
+  if (access == access_public_node)
     add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
-  else if (TREE_VIA_PROTECTED (binfo))
+  else if (access == access_protected_node)
     add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
 }
 
@@ -11389,6 +11474,7 @@ gen_member_die (type, context_die)
      dw_die_ref context_die;
 {
   tree member;
+  tree binfo = TYPE_BINFO (type);
   dw_die_ref child;
 
   /* If this is not an incomplete type, output descriptions of each of its
@@ -11404,14 +11490,17 @@ gen_member_die (type, context_die)
      the TREE node representing the appropriate (containing) type.  */
 
   /* First output info about the base classes.  */
-  if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
+  if (binfo && BINFO_BASETYPES (binfo))
     {
-      tree bases = TYPE_BINFO_BASETYPES (type);
+      tree bases = BINFO_BASETYPES (binfo);
+      tree accesses = BINFO_BASEACCESSES (binfo);
       int n_bases = TREE_VEC_LENGTH (bases);
       int i;
 
       for (i = 0; i < n_bases; i++)
-       gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die);
+       gen_inheritance_die (TREE_VEC_ELT (bases, i),
+                            (accesses ? TREE_VEC_ELT (accesses, i)
+                             : access_public_node), context_die);
     }
 
   /* Now output info about the data members and type members.  */
@@ -11491,7 +11580,7 @@ gen_struct_or_union_type_die (type, context_die)
   if (complete)
     {
       /* Prevent infinite recursion in cases where the type of some member of
-         this type is expressed in terms of this type itself.  */
+        this type is expressed in terms of this type itself.  */
       TREE_ASM_WRITTEN (type) = 1;
       add_byte_size_attribute (type_die, type);
       if (TYPE_STUB_DECL (type) != NULL_TREE)
@@ -11600,20 +11689,12 @@ gen_type_die (type, context_die)
   if (type == NULL_TREE || type == error_mark_node)
     return;
 
-  /* We are going to output a DIE to represent the unqualified version
-     of this type (i.e. without any const or volatile qualifiers) so
-     get the main variant (i.e. the unqualified version) of this type
-     now.  (Vectors are special because the debugging info is in the
-     cloned type itself).  */
-  if (TREE_CODE (type) != VECTOR_TYPE)
-    type = type_main_variant (type);
-
-  if (TREE_ASM_WRITTEN (type))
-    return;
-
   if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
       && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
     {
+      if (TREE_ASM_WRITTEN (type))
+       return;
+
       /* Prevent broken recursion; we can't hand off to the same type.  */
       if (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) == type)
        abort ();
@@ -11623,6 +11704,17 @@ gen_type_die (type, context_die)
       return;
     }
 
+  /* We are going to output a DIE to represent the unqualified version
+     of this type (i.e. without any const or volatile qualifiers) so
+     get the main variant (i.e. the unqualified version) of this type
+     now.  (Vectors are special because the debugging info is in the
+     cloned type itself).  */
+  if (TREE_CODE (type) != VECTOR_TYPE)
+    type = type_main_variant (type);
+
+  if (TREE_ASM_WRITTEN (type))
+    return;
+
   switch (TREE_CODE (type))
     {
     case ERROR_MARK:
@@ -11638,7 +11730,7 @@ gen_type_die (type, context_die)
       TREE_ASM_WRITTEN (type) = 1;
 
       /* For these types, all that is required is that we output a DIE (or a
-         set of DIEs) to represent the "basis" type.  */
+        set of DIEs) to represent the "basis" type.  */
       gen_type_die (TREE_TYPE (type), context_die);
       break;
 
@@ -11651,7 +11743,7 @@ gen_type_die (type, context_die)
       gen_type_die (TREE_TYPE (type), context_die);
 
       /* Now output a DIE to represent this pointer-to-data-member type
-         itself.  */
+        itself.  */
       gen_ptr_to_mbr_type_die (type, context_die);
       break;
 
@@ -11696,11 +11788,11 @@ gen_type_die (type, context_die)
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
       /* If this is a nested type whose containing class hasn't been written
-         out yet, writing it out will cover this one, too.  This does not apply
-         to instantiations of member class templates; they need to be added to
-         the containing class as they are generated.  FIXME: This hurts the
-         idea of combining type decls from multiple TUs, since we can't predict
-         what set of template instantiations we'll get.  */
+        out yet, writing it out will cover this one, too.  This does not apply
+        to instantiations of member class templates; they need to be added to
+        the containing class as they are generated.  FIXME: This hurts the
+        idea of combining type decls from multiple TUs, since we can't predict
+        what set of template instantiations we'll get.  */
       if (TYPE_CONTEXT (type)
          && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
          && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
@@ -11843,12 +11935,12 @@ gen_block_die (stmt, context_die, depth)
   else
     {
       /* In the case where the current block represents an inlining of the
-         "body block" of an inline function, we must *NOT* output any DIE for
-         this block because we have already output a DIE to represent the whole
-         inlined function scope and the "body block" of any function doesn't
-         really represent a different scope according to ANSI C rules.  So we
-         check here to make sure that this block does not represent a "body
-         block inlining" before trying to set the MUST_OUTPUT_DIE flag.  */
+        "body block" of an inline function, we must *NOT* output any DIE for
+        this block because we have already output a DIE to represent the whole
+        inlined function scope and the "body block" of any function doesn't
+        really represent a different scope according to ANSI C rules.  So we
+        check here to make sure that this block does not represent a "body
+        block inlining" before trying to set the MUST_OUTPUT_DIE flag.  */
       if (! is_body_block (origin ? origin : stmt))
        {
          /* Determine if this block directly contains any "significant"
@@ -11973,7 +12065,7 @@ gen_decl_die (decl, context_die)
 
     case CONST_DECL:
       /* The individual enumerators of an enum type get output when we output
-         the Dwarf representation of the relevant enum type itself.  */
+        the Dwarf representation of the relevant enum type itself.  */
       break;
 
     case FUNCTION_DECL:
@@ -12023,16 +12115,16 @@ gen_decl_die (decl, context_die)
 
     case TYPE_DECL:
       /* If we are in terse mode, don't generate any DIEs to represent any
-         actual typedefs.  */
+        actual typedefs.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
        break;
 
       /* In the special case of a TYPE_DECL node representing the declaration
-         of some type tag, if the given TYPE_DECL is marked as having been
-         instantiated from some other (original) TYPE_DECL node (e.g. one which
-         was generated within the original definition of an inline function) we
-         have to generate a special (abbreviated) DW_TAG_structure_type,
-         DW_TAG_union_type, or DW_TAG_enumeration_type DIE here.  */
+        of some type tag, if the given TYPE_DECL is marked as having been
+        instantiated from some other (original) TYPE_DECL node (e.g. one which
+        was generated within the original definition of an inline function) we
+        have to generate a special (abbreviated) DW_TAG_structure_type,
+        DW_TAG_union_type, or DW_TAG_enumeration_type DIE here.  */
       if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
        {
          gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
@@ -12053,12 +12145,12 @@ gen_decl_die (decl, context_die)
 
     case VAR_DECL:
       /* If we are in terse mode, don't generate any DIEs to represent any
-         variable declarations or definitions.  */
+        variable declarations or definitions.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
        break;
 
       /* Output any DIEs that are needed to specify the type of this data
-         object.  */
+        object.  */
       gen_type_die (TREE_TYPE (decl), context_die);
 
       /* And its containing type.  */
@@ -12067,9 +12159,9 @@ gen_decl_die (decl, context_die)
        gen_type_die_for_member (origin, decl, context_die);
 
       /* Now output the DIE to represent the data object itself.  This gets
-         complicated because of the possibility that the VAR_DECL really
-         represents an inlined instance of a formal parameter for an inline
-         function.  */
+        complicated because of the possibility that the VAR_DECL really
+        represents an inlined instance of a formal parameter for an inline
+        function.  */
       origin = decl_ultimate_origin (decl);
       if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
        gen_formal_parameter_die (decl, context_die);
@@ -12156,32 +12248,32 @@ dwarf2out_decl (decl)
 
     case FUNCTION_DECL:
       /* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a
-         builtin function.  Explicit programmer-supplied declarations of
-         these same functions should NOT be ignored however.  */
+        builtin function.  Explicit programmer-supplied declarations of
+        these same functions should NOT be ignored however.  */
       if (DECL_EXTERNAL (decl) && DECL_BUILT_IN (decl))
        return;
 
       /* What we would really like to do here is to filter out all mere
-         file-scope declarations of file-scope functions which are never
-         referenced later within this translation unit (and keep all of ones
-         that *are* referenced later on) but we aren't clairvoyant, so we have
-         no idea which functions will be referenced in the future (i.e. later
-         on within the current translation unit). So here we just ignore all
-         file-scope function declarations which are not also definitions.  If
-         and when the debugger needs to know something about these functions,
-         it will have to hunt around and find the DWARF information associated
-         with the definition of the function.
+        file-scope declarations of file-scope functions which are never
+        referenced later within this translation unit (and keep all of ones
+        that *are* referenced later on) but we aren't clairvoyant, so we have
+        no idea which functions will be referenced in the future (i.e. later
+        on within the current translation unit). So here we just ignore all
+        file-scope function declarations which are not also definitions.  If
+        and when the debugger needs to know something about these functions,
+        it will have to hunt around and find the DWARF information associated
+        with the definition of the function.
 
         We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
-         nodes represent definitions and which ones represent mere
-         declarations.  We have to check DECL_INITIAL instead. That's because
-         the C front-end supports some weird semantics for "extern inline"
-         function definitions.  These can get inlined within the current
-         translation unit (an thus, we need to generate Dwarf info for their
-         abstract instances so that the Dwarf info for the concrete inlined
-         instances can have something to refer to) but the compiler never
-         generates any out-of-lines instances of such things (despite the fact
-         that they *are* definitions).
+        nodes represent definitions and which ones represent mere
+        declarations.  We have to check DECL_INITIAL instead. That's because
+        the C front-end supports some weird semantics for "extern inline"
+        function definitions.  These can get inlined within the current
+        translation unit (an thus, we need to generate Dwarf info for their
+        abstract instances so that the Dwarf info for the concrete inlined
+        instances can have something to refer to) but the compiler never
+        generates any out-of-lines instances of such things (despite the fact
+        that they *are* definitions).
 
         The important point is that the C front-end marks these "extern
         inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
@@ -12200,18 +12292,18 @@ dwarf2out_decl (decl)
 
     case VAR_DECL:
       /* Ignore this VAR_DECL if it refers to a file-scope extern data object
-         declaration and if the declaration was never even referenced from
-         within this entire compilation unit.  We suppress these DIEs in
-         order to save space in the .debug section (by eliminating entries
-         which are probably useless).  Note that we must not suppress
-         block-local extern declarations (whether used or not) because that
-         would screw-up the debugger's name lookup mechanism and cause it to
-         miss things which really ought to be in scope at a given point.  */
+        declaration and if the declaration was never even referenced from
+        within this entire compilation unit.  We suppress these DIEs in
+        order to save space in the .debug section (by eliminating entries
+        which are probably useless).  Note that we must not suppress
+        block-local extern declarations (whether used or not) because that
+        would screw-up the debugger's name lookup mechanism and cause it to
+        miss things which really ought to be in scope at a given point.  */
       if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
        return;
 
       /* If we are in terse mode, don't generate any DIEs to represent any
-         variable declarations or definitions.  */
+        variable declarations or definitions.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
        return;
       break;
@@ -12222,11 +12314,11 @@ dwarf2out_decl (decl)
        return;
 
       /* Don't bother trying to generate any DIEs to represent any of the
-         normal built-in types for the language we are compiling.  */
+        normal built-in types for the language we are compiling.  */
       if (DECL_SOURCE_LINE (decl) == 0)
        {
          /* OK, we need to generate one for `bool' so GDB knows what type
-             comparisons have.  */
+            comparisons have.  */
          if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
               == DW_LANG_C_plus_plus)
              && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE
@@ -12329,7 +12421,7 @@ lookup_filename (file_name)
       const char *last
        = VARRAY_CHAR_PTR (file_table, file_table_last_lookup_index);
       if (strcmp (file_name, last) == 0)
-        return file_table_last_lookup_index;
+       return file_table_last_lookup_index;
     }
 
   /* Didn't match the previous lookup, search the table */
@@ -12345,15 +12437,31 @@ lookup_filename (file_name)
   file_table_last_lookup_index = n;
   save_file_name = (char *) ggc_strdup (file_name);
   VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
+  VARRAY_PUSH_UINT (file_table_emitted, 0);
+
+  return i;
+}
 
-  if (DWARF2_ASM_LINE_DEBUG_INFO)
+static int
+maybe_emit_file (fileno)
+     int fileno;
+{
+  static int emitcount = 0;  
+  if (DWARF2_ASM_LINE_DEBUG_INFO && fileno > 0)
     {
-      fprintf (asm_out_file, "\t.file %u ", i);
-      output_quoted_string (asm_out_file, file_name);
-      fputc ('\n', asm_out_file);
+      if (!VARRAY_UINT (file_table_emitted, fileno))
+       {
+         VARRAY_UINT (file_table_emitted, fileno) = ++emitcount;
+         fprintf (asm_out_file, "\t.file %u ",
+                  VARRAY_UINT (file_table_emitted, fileno));
+         output_quoted_string (asm_out_file,
+                               VARRAY_CHAR_PTR (file_table, fileno));
+         fputc ('\n', asm_out_file);
+       }
+      return VARRAY_UINT (file_table_emitted, fileno);
     }
-
-  return i;
+  else
+    return fileno;
 }
 
 static void
@@ -12361,9 +12469,11 @@ init_file_table ()
 {
   /* Allocate the initial hunk of the file_table.  */
   VARRAY_CHAR_PTR_INIT (file_table, 64, "file_table");
+  VARRAY_UINT_INIT (file_table_emitted, 64, "file_table_emitted");
 
   /* Skip the first entry - file numbers begin at 1.  */
   VARRAY_PUSH_CHAR_PTR (file_table, NULL);
+  VARRAY_PUSH_UINT (file_table_emitted, 0);
   file_table_last_lookup_index = 0;
 }
 
@@ -12389,6 +12499,8 @@ dwarf2out_source_line (line, filename)
        {
          unsigned file_num = lookup_filename (filename);
 
+         file_num = maybe_emit_file (file_num);
+
          /* Emit the .loc directive understood by GNU as.  */
          fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
 
@@ -12480,6 +12592,7 @@ dwarf2out_start_source_file (lineno, filename)
       dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
       dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
                                   lineno);
+      maybe_emit_file (lookup_filename (filename));
       dw2_asm_output_data_uleb128 (lookup_filename (filename),
                                   "Filename we just started");
     }
@@ -12639,6 +12752,215 @@ output_indirect_string (h, v)
   return 1;
 }
 
+
+
+/* Clear the marks for a die and its children.
+   Be cool if the mark isn't set.  */
+
+static void
+prune_unmark_dies (die)
+     dw_die_ref die;
+{
+  dw_die_ref c;
+  die->die_mark = 0;
+  for (c = die->die_child; c; c = c->die_sib)
+    prune_unmark_dies (c);
+}
+
+
+/* Given DIE that we're marking as used, find any other dies
+   it references as attributes and mark them as used.  */
+
+static void
+prune_unused_types_walk_attribs (die)
+     dw_die_ref die;
+{
+  dw_attr_ref a;
+
+  for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+    {
+      if (a->dw_attr_val.val_class == dw_val_class_die_ref)
+       {
+         /* A reference to another DIE.
+            Make sure that it will get emitted.  */
+         prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
+       }
+      else if (a->dw_attr == DW_AT_decl_file)
+       {
+         /* A reference to a file.  Make sure the file name is emitted.  */
+         a->dw_attr_val.v.val_unsigned =
+           maybe_emit_file (a->dw_attr_val.v.val_unsigned);
+       }
+    }
+}
+
+
+/* Mark DIE as being used.  If DOKIDS is true, then walk down
+   to DIE's children.  */
+
+static void
+prune_unused_types_mark (die, dokids)
+     dw_die_ref die;
+     int dokids;
+{
+  dw_die_ref c;
+
+  if (die->die_mark == 0)
+    {
+      /* We haven't done this node yet.  Mark it as used.  */
+      die->die_mark = 1;
+
+      /* We also have to mark its parents as used.
+        (But we don't want to mark our parents' kids due to this.)  */
+      if (die->die_parent)
+       prune_unused_types_mark (die->die_parent, 0);
+
+      /* Mark any referenced nodes.  */
+      prune_unused_types_walk_attribs (die);
+    }
+
+  if (dokids && die->die_mark != 2)
+    {
+      /* We need to walk the children, but haven't done so yet.
+        Remember that we've walked the kids.  */
+      die->die_mark = 2;
+
+      /* Walk them.  */
+      for (c = die->die_child; c; c = c->die_sib)
+       {
+         /* If this is an array type, we need to make sure our
+            kids get marked, even if they're types.  */
+         if (die->die_tag == DW_TAG_array_type)
+           prune_unused_types_mark (c, 1);
+         else
+           prune_unused_types_walk (c);
+       }
+    }
+}
+
+
+/* Walk the tree DIE and mark types that we actually use.  */
+
+static void
+prune_unused_types_walk (die)
+     dw_die_ref die;
+{
+  dw_die_ref c;
+
+  /* Don't do anything if this node is already marked.  */
+  if (die->die_mark)
+    return;
+
+  switch (die->die_tag) {
+  case DW_TAG_const_type:
+  case DW_TAG_packed_type:
+  case DW_TAG_pointer_type:
+  case DW_TAG_reference_type:
+  case DW_TAG_volatile_type:
+  case DW_TAG_typedef:
+  case DW_TAG_array_type:
+  case DW_TAG_structure_type:
+  case DW_TAG_union_type:
+  case DW_TAG_class_type:
+  case DW_TAG_friend:
+  case DW_TAG_variant_part:
+  case DW_TAG_enumeration_type:
+  case DW_TAG_subroutine_type:
+  case DW_TAG_string_type:
+  case DW_TAG_set_type:
+  case DW_TAG_subrange_type:
+  case DW_TAG_ptr_to_member_type:
+  case DW_TAG_file_type:
+    /* It's a type node --- don't mark it.  */
+    return;
+
+  default:
+    /* Mark everything else.  */
+    break;
+  }
+
+  die->die_mark = 1;
+
+  /* Now, mark any dies referenced from here.  */
+  prune_unused_types_walk_attribs (die);
+
+  /* Mark children.  */
+  for (c = die->die_child; c; c = c->die_sib)
+    prune_unused_types_walk (c);
+}
+
+
+/* Remove from the tree DIE any dies that aren't marked.  */
+
+static void
+prune_unused_types_prune (die)
+     dw_die_ref die;
+{
+  dw_die_ref c, p, n;
+  if (!die->die_mark)
+    abort();
+
+  p = NULL;
+  for (c = die->die_child; c; c = n)
+    {
+      n = c->die_sib;
+      if (c->die_mark)
+       {
+         prune_unused_types_prune (c);
+         p = c;
+       }
+      else
+       {
+         if (p)
+           p->die_sib = n;
+         else
+           die->die_child = n;
+         free_die (c);
+       }
+    }
+}
+
+
+/* Remove dies representing declarations that we never use.  */
+
+static void
+prune_unused_types ()
+{
+  unsigned int i;
+  limbo_die_node *node;
+
+  /* Clear all the marks.  */
+  prune_unmark_dies (comp_unit_die);
+  for (node = limbo_die_list; node; node = node->next)
+    prune_unmark_dies (node->die);
+
+  /* Set the mark on nodes that are actually used.  */
+  prune_unused_types_walk (comp_unit_die);
+  for (node = limbo_die_list; node; node = node->next)
+    prune_unused_types_walk (node->die);
+
+  /* Also set the mark on nodes referenced from the
+     pubname_table or arange_table.  */
+  for (i=0; i < pubname_table_in_use; i++)
+    {
+      prune_unused_types_mark (pubname_table[i].die, 1);
+    }
+  for (i=0; i < arange_table_in_use; i++)
+    {
+      prune_unused_types_mark (arange_table[i], 1);
+    }
+
+  /* Get rid of nodes that aren't marked.  */
+  prune_unused_types_prune (comp_unit_die);
+  for (node = limbo_die_list; node; node = node->next)
+    prune_unused_types_prune (node->die);
+
+  /* Leave the marks clear.  */
+  prune_unmark_dies (comp_unit_die);
+  for (node = limbo_die_list; node; node = node->next)
+    prune_unmark_dies (node->die);
+}
+
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
@@ -12654,6 +12976,16 @@ dwarf2out_finish (input_filename)
   add_name_attribute (comp_unit_die, input_filename);
   if (input_filename[0] != DIR_SEPARATOR)
     add_comp_dir_attribute (comp_unit_die);
+  else if (get_AT (comp_unit_die, DW_AT_comp_dir) == NULL)
+    {
+      size_t i;
+      for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
+       if (VARRAY_CHAR_PTR (file_table, i)[0] != DIR_SEPARATOR)
+         {
+           add_comp_dir_attribute (comp_unit_die);
+           break;
+         }
+    }
 
   /* Traverse the limbo die list, and add parent/child links.  The only
      dies without parents that should be here are concrete instances of
@@ -12718,6 +13050,9 @@ dwarf2out_finish (input_filename)
      we'll see the end of an include file before the beginning.  */
   reverse_all_dies (comp_unit_die);
 
+  if (flag_eliminate_unused_debug_types)
+    prune_unused_types ();
+
   /* Generate separate CUs for each of the include files we've seen.
      They will go into limbo_die_list.  */
   if (flag_eliminate_dwarf2_dups)