OSDN Git Service

PR middle-end/31322
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 6d6080c..cbaf063 100644 (file)
@@ -1,6 +1,6 @@
 /* Output Dwarf2 format symbol table information from GCC.
    Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007 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).
@@ -156,6 +156,7 @@ static GTY(()) section *debug_macinfo_section;
 static GTY(()) section *debug_line_section;
 static GTY(()) section *debug_loc_section;
 static GTY(()) section *debug_pubnames_section;
+static GTY(()) section *debug_pubtypes_section;
 static GTY(()) section *debug_str_section;
 static GTY(()) section *debug_ranges_section;
 static GTY(()) section *debug_frame_section;
@@ -442,6 +443,17 @@ stripattributes (const char *s)
   return stripped;
 }
 
+/* MEM is a memory reference for the register size table, each element of
+   which has mode MODE.  Initialize column C as a return address column.  */
+
+static void
+init_return_column_size (enum machine_mode mode, rtx mem, unsigned int c)
+{
+  HOST_WIDE_INT offset = c * GET_MODE_SIZE (mode);
+  HOST_WIDE_INT size = GET_MODE_SIZE (Pmode);
+  emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
+}
+
 /* Generate code to initialize the register size table.  */
 
 void
@@ -456,13 +468,13 @@ expand_builtin_init_dwarf_reg_sizes (tree address)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
       int rnum = DWARF2_FRAME_REG_OUT (DWARF_FRAME_REGNUM (i), 1);
-      
+
       if (rnum < DWARF_FRAME_REGISTERS)
        {
          HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (mode);
          enum machine_mode save_mode = reg_raw_mode[i];
          HOST_WIDE_INT size;
-         
+
          if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
            save_mode = choose_hard_reg_mode (i, 1, true);
          if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
@@ -474,27 +486,20 @@ expand_builtin_init_dwarf_reg_sizes (tree address)
          size = GET_MODE_SIZE (save_mode);
          if (offset < 0)
            continue;
-         
+
          emit_move_insn (adjust_address (mem, mode, offset),
                          gen_int_mode (size, mode));
        }
     }
 
+  if (!wrote_return_column)
+    init_return_column_size (mode, mem, DWARF_FRAME_RETURN_COLUMN);
+
 #ifdef DWARF_ALT_FRAME_RETURN_COLUMN
-  gcc_assert (wrote_return_column);
-  i = DWARF_ALT_FRAME_RETURN_COLUMN;
-  wrote_return_column = false;
-#else
-  i = DWARF_FRAME_RETURN_COLUMN;
+  init_return_column_size (mode, mem, DWARF_ALT_FRAME_RETURN_COLUMN);
 #endif
 
-  if (! wrote_return_column)
-    {
-      enum machine_mode save_mode = Pmode;
-      HOST_WIDE_INT offset = i * GET_MODE_SIZE (mode);
-      HOST_WIDE_INT size = GET_MODE_SIZE (save_mode);
-      emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
-    }
+  targetm.init_dwarf_reg_sizes_extra (address);
 }
 
 /* Convert a DWARF call frame info. operation to its string name */
@@ -1521,13 +1526,31 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
     {
       int par_index;
       int limit = XVECLEN (expr, 0);
+      rtx elem;
+
+      /* PARALLELs have strict read-modify-write semantics, so we
+        ought to evaluate every rvalue before changing any lvalue.
+        It's cumbersome to do that in general, but there's an
+        easy approximation that is enough for all current users:
+        handle register saves before register assignments.  */
+      if (GET_CODE (expr) == PARALLEL)
+       for (par_index = 0; par_index < limit; par_index++)
+         {
+           elem = XVECEXP (expr, 0, par_index);
+           if (GET_CODE (elem) == SET
+               && MEM_P (SET_DEST (elem))
+               && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
+             dwarf2out_frame_debug_expr (elem, label);
+         }
 
       for (par_index = 0; par_index < limit; par_index++)
-       if (GET_CODE (XVECEXP (expr, 0, par_index)) == SET
-           && (RTX_FRAME_RELATED_P (XVECEXP (expr, 0, par_index))
-               || par_index == 0))
-         dwarf2out_frame_debug_expr (XVECEXP (expr, 0, par_index), label);
-
+       {
+         elem = XVECEXP (expr, 0, par_index);
+         if (GET_CODE (elem) == SET
+             && (!MEM_P (SET_DEST (elem)) || GET_CODE (expr) == SEQUENCE)
+             && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
+           dwarf2out_frame_debug_expr (elem, label);
+       }
       return;
     }
 
@@ -2030,7 +2053,7 @@ switch_to_eh_frame_section (void)
       /* We have no special eh_frame section.  Put the information in
         the data section and emit special labels to guide collect2.  */
       switch_to_section (data_section);
-      label = get_file_function_name ('F');
+      label = get_file_function_name ("F");
       ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
       targetm.asm_out.globalize_label (asm_out_file,
                                       IDENTIFIER_POINTER (label));
@@ -2195,7 +2218,7 @@ output_call_frame_info (int for_eh)
       && for_eh)
     for (i = 0; i < fde_table_in_use; i++)
       if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
-          && !fde_table[i].uses_eh_lsda
+         && !fde_table[i].uses_eh_lsda
          && ! DECL_WEAK (fde_table[i].decl))
        targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
                                      for_eh, /* empty */ 1);
@@ -2211,7 +2234,7 @@ output_call_frame_info (int for_eh)
       for (i = 0; i < fde_table_in_use; i++)
        if (fde_table[i].uses_eh_lsda)
          any_eh_needed = any_lsda_needed = true;
-        else if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
+       else if (TARGET_USES_WEAK_UNWIND_INFO && DECL_WEAK (fde_table[i].decl))
          any_eh_needed = true;
        else if (! fde_table[i].nothrow
                 && ! fde_table[i].all_throwers_are_sibcalls)
@@ -2281,6 +2304,7 @@ output_call_frame_info (int for_eh)
        {
          *p++ = 'P';
          augmentation_size += 1 + size_of_encoded_value (per_encoding);
+         assemble_external_libcall (eh_personality_libfunc);
        }
       if (any_lsda_needed)
        {
@@ -2399,9 +2423,9 @@ output_call_frame_info (int for_eh)
                                           "FDE initial location");
          if (fde->dw_fde_switched_sections)
            {
-             rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode, 
+             rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
                                      fde->dw_fde_unlikely_section_label);
-             rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode, 
+             rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
                                      fde->dw_fde_hot_section_label);
              SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL;
              SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL;
@@ -2439,7 +2463,7 @@ output_call_frame_info (int for_eh)
              dw2_asm_output_addr (DWARF2_ADDR_SIZE,
                                   fde->dw_fde_unlikely_section_label,
                                   "FDE initial location");
-             dw2_asm_output_delta (DWARF2_ADDR_SIZE, 
+             dw2_asm_output_delta (DWARF2_ADDR_SIZE,
                                    fde->dw_fde_unlikely_section_end_label,
                                    fde->dw_fde_unlikely_section_label,
                                    "FDE address range");
@@ -2572,7 +2596,7 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   fde = &fde_table[fde_table_in_use++];
   fde->decl = current_function_decl;
   fde->dw_fde_begin = dup_label;
-  fde->dw_fde_current_label = NULL;
+  fde->dw_fde_current_label = dup_label;
   fde->dw_fde_hot_section_label = NULL;
   fde->dw_fde_hot_section_end_label = NULL;
   fde->dw_fde_unlikely_section_label = NULL;
@@ -2653,6 +2677,13 @@ dwarf2out_frame_finish (void)
 /* And now, the subset of the debugging information support code necessary
    for emitting location expressions.  */
 
+/* Data about a single source file.  */
+struct dwarf_file_data GTY(())
+{
+  const char * filename;
+  int emitted_number;
+};
+
 /* We need some way to distinguish DW_OP_addr with a direct symbol
    relocation from DW_OP_addr with a dtp-relative symbol relocation.  */
 #define INTERNAL_DW_OP_tls_addr                (0x100 + DW_OP_addr)
@@ -2684,7 +2715,8 @@ enum dw_val_class
   dw_val_class_lbl_id,
   dw_val_class_lineptr,
   dw_val_class_str,
-  dw_val_class_macptr
+  dw_val_class_macptr,
+  dw_val_class_file
 };
 
 /* Describe a double word constant value.  */
@@ -2732,6 +2764,7 @@ typedef struct dw_val_struct GTY(())
       struct indirect_string_node * GTY ((tag ("dw_val_class_str"))) val_str;
       char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
       unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
+      struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
     }
   GTY ((desc ("%1.val_class"))) v;
 }
@@ -3746,10 +3779,13 @@ die_node;
 typedef struct pubname_struct GTY(())
 {
   dw_die_ref die;
-  char *name;
+  const char *name;
 }
 pubname_entry;
 
+DEF_VEC_O(pubname_entry);
+DEF_VEC_ALLOC_O(pubname_entry, gc);
+
 struct dw_ranges_struct GTY(())
 {
   int block_num;
@@ -3803,14 +3839,14 @@ limbo_die_node;
 /* Fixed size portion of the address range info.  */
 #define DWARF_ARANGES_HEADER_SIZE                                      \
   (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4,     \
-                DWARF2_ADDR_SIZE * 2)                                  \
+               DWARF2_ADDR_SIZE * 2)                                   \
    - DWARF_INITIAL_LENGTH_SIZE)
 
 /* Size of padding portion in the address range info.  It must be
    aligned to twice the pointer size.  */
 #define DWARF_ARANGES_PAD_SIZE \
   (DWARF_ROUND (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4, \
-                DWARF2_ADDR_SIZE * 2) \
+               DWARF2_ADDR_SIZE * 2)                              \
    - (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 4))
 
 /* Use assembler line directives if available.  */
@@ -3851,9 +3887,7 @@ static GTY(()) dw_die_ref comp_unit_die;
 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;
+static GTY((param_is (struct dwarf_file_data))) htab_t file_table;
 
 /* A hash table of references to DIE's that describe declarations.
    The key is a DECL_UID() which is a unique number identifying each decl.  */
@@ -3933,17 +3967,11 @@ static GTY(()) unsigned separate_line_info_table_in_use;
 
 /* A pointer to the base of a table that contains a list of publicly
    accessible names.  */
-static GTY ((length ("pubname_table_allocated"))) pubname_ref pubname_table;
+static GTY (()) VEC (pubname_entry, gc) *  pubname_table;
 
-/* Number of elements currently allocated for pubname_table.  */
-static GTY(()) unsigned pubname_table_allocated;
-
-/* Number of elements in pubname_table currently in use.  */
-static GTY(()) unsigned pubname_table_in_use;
-
-/* Size (in elements) of increments by which we may expand the
-   pubname_table.  */
-#define PUBNAME_TABLE_INCREMENT 64
+/* A pointer to the base of a table that contains a list of publicly
+   accessible types.  */
+static GTY (()) VEC (pubname_entry, gc) * pubtype_table;
 
 /* Array of dies for which we should generate .debug_arange info.  */
 static GTY((length ("arange_table_allocated"))) dw_die_ref *arange_table;
@@ -3985,12 +4013,15 @@ static int current_function_has_inlines;
 static int comp_unit_has_inlines;
 #endif
 
-/* Number of file tables emitted in maybe_emit_file().  */
-static GTY(()) int emitcount = 0;
+/* The last file entry emitted by maybe_emit_file().  */
+static GTY(()) struct dwarf_file_data * last_emitted_file;
 
 /* Number of internal labels generated by gen_internal_sym().  */
 static GTY(()) int label_num;
 
+/* Cached result of previous call to lookup_filename.  */
+static GTY(()) struct dwarf_file_data * file_table_last_lookup;
+
 #ifdef DWARF2_DEBUGGING_INFO
 
 /* Offset from the "steady-state frame pointer" to the frame base,
@@ -4105,7 +4136,7 @@ static void calc_die_sizes (dw_die_ref);
 static void mark_dies (dw_die_ref);
 static void unmark_dies (dw_die_ref);
 static void unmark_all_dies (dw_die_ref);
-static unsigned long size_of_pubnames (void);
+static unsigned long size_of_pubnames (VEC (pubname_entry,gc) *);
 static unsigned long size_of_aranges (void);
 static enum dwarf_form value_format (dw_attr_ref);
 static void output_value_format (dw_attr_ref);
@@ -4116,7 +4147,8 @@ static void output_compilation_unit_header (void);
 static void output_comp_unit (dw_die_ref, int);
 static const char *dwarf2_name (tree, int);
 static void add_pubname (tree, dw_die_ref);
-static void output_pubnames (void);
+static void add_pubtype (tree, dw_die_ref);
+static void output_pubnames (VEC (pubname_entry,gc) *);
 static void add_arange (tree, dw_die_ref);
 static void output_aranges (void);
 static unsigned int add_ranges (tree);
@@ -4124,7 +4156,6 @@ static void output_ranges (void);
 static void output_line_info (void);
 static void output_file_names (void);
 static dw_die_ref base_type_die (tree);
-static tree root_type (tree);
 static int is_base_type (tree);
 static bool is_subrange_type (tree);
 static dw_die_ref subrange_type_die (tree, dw_die_ref);
@@ -4219,8 +4250,7 @@ static dw_die_ref force_decl_die (tree);
 static dw_die_ref force_type_die (tree);
 static dw_die_ref setup_namespace_context (tree, dw_die_ref);
 static void declare_in_namespace (tree, dw_die_ref);
-static unsigned lookup_filename (const char *);
-static void init_file_table (void);
+static struct dwarf_file_data * lookup_filename (const char *);
 static void retry_incomplete_types (void);
 static void gen_type_die_for_member (tree, tree, dw_die_ref);
 static void splice_child_die (dw_die_ref, dw_die_ref);
@@ -4239,7 +4269,7 @@ static void prune_unused_types_walk (dw_die_ref);
 static void prune_unused_types_walk_attribs (dw_die_ref);
 static void prune_unused_types_prune (dw_die_ref);
 static void prune_unused_types (void);
-static int maybe_emit_file (int);
+static int maybe_emit_file (struct dwarf_file_data *fd);
 
 /* Section names used to hold DWARF debugging information.  */
 #ifndef DEBUG_INFO_SECTION
@@ -4318,7 +4348,7 @@ static int maybe_emit_file (int);
 static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char cold_text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
-static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES]; 
+static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
@@ -4834,7 +4864,7 @@ block_ultimate_origin (tree block)
                       ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
        }
       while (lookahead != NULL && lookahead != ret_val);
-      
+
       /* The block's abstract origin chain may not be the *ultimate* origin of
         the block. It could lead to a DECL that has an abstract origin set.
         If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
@@ -4877,7 +4907,7 @@ add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
   /* Maybe this should be an assert?  */
   if (die == NULL)
     return;
-  
+
   if (die->die_attr == NULL)
     die->die_attr = VEC_alloc (dw_attr_node, gc, 1);
   VEC_safe_push (dw_attr_node, gc, die->die_attr, attr);
@@ -5012,9 +5042,15 @@ add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
   slot = htab_find_slot_with_hash (debug_str_hash, str,
                                   htab_hash_string (str), INSERT);
   if (*slot == NULL)
-    *slot = ggc_alloc_cleared (sizeof (struct indirect_string_node));
-  node = (struct indirect_string_node *) *slot;
-  node->str = ggc_strdup (str);
+    {
+      node = (struct indirect_string_node *)
+              ggc_alloc_cleared (sizeof (struct indirect_string_node));
+      node->str = ggc_strdup (str);
+      *slot = node;
+    }
+  else
+    node = (struct indirect_string_node *) *slot;
+
   node->refcount++;
 
   attr.dw_attr = attr_kind;
@@ -5180,6 +5216,8 @@ add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
   add_dwarf_attr (die, &attr);
 }
 
+/* Get the RTX from to an address DIE attribute.  */
+
 static inline rtx
 AT_addr (dw_attr_ref a)
 {
@@ -5187,6 +5225,29 @@ AT_addr (dw_attr_ref a)
   return a->dw_attr_val.v.val_addr;
 }
 
+/* Add a file attribute value to a DIE.  */
+
+static inline void
+add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind,
+            struct dwarf_file_data *fd)
+{
+  dw_attr_node attr;
+
+  attr.dw_attr = attr_kind;
+  attr.dw_attr_val.val_class = dw_val_class_file;
+  attr.dw_attr_val.v.val_file = fd;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Get the dwarf_file_data from a file DIE attribute.  */
+
+static inline struct dwarf_file_data *
+AT_file (dw_attr_ref a)
+{
+  gcc_assert (a && AT_class (a) == dw_val_class_file);
+  return a->dw_attr_val.v.val_file;
+}
+
 /* Add a label identifier attribute value to a DIE.  */
 
 static inline void
@@ -5285,7 +5346,7 @@ get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
     else if (a->dw_attr == DW_AT_specification
             || a->dw_attr == DW_AT_abstract_origin)
       spec = AT_ref (a);
-  
+
   if (spec)
     return get_AT (spec, attr_kind);
 
@@ -5357,6 +5418,14 @@ get_AT_ref (dw_die_ref die, enum dwarf_attribute attr_kind)
   return a ? AT_ref (a) : NULL;
 }
 
+static inline struct dwarf_file_data *
+get_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+  dw_attr_ref a = get_AT (die, attr_kind);
+
+  return a ? AT_file (a) : NULL;
+}
+
 /* Return TRUE if the language is C or C++.  */
 
 static inline bool
@@ -5375,7 +5444,7 @@ static inline bool
 is_cxx (void)
 {
   unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
-  
+
   return lang == DW_LANG_C_plus_plus || lang == DW_LANG_ObjC_plus_plus;
 }
 
@@ -5462,7 +5531,7 @@ static void
 remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
 {
   dw_die_ref c;
-  
+
   c = die->die_child;
   if (c) do {
     dw_die_ref prev = c;
@@ -5500,7 +5569,7 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
 }
 
 /* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
-   is the specification, to the end of PARENT's list of children.  
+   is the specification, to the end of PARENT's list of children.
    This is done by removing and re-adding it.  */
 
 static void
@@ -5521,7 +5590,7 @@ splice_child_die (dw_die_ref parent, dw_die_ref child)
   gcc_assert (child->die_parent == parent
              || (child->die_parent
                  == get_AT_ref (parent, DW_AT_specification)));
-  
+
   for (p = child->die_parent->die_child; ; p = p->die_sib)
     if (p->die_sib == child)
       {
@@ -5766,6 +5835,10 @@ print_die (dw_die_ref die, FILE *outfile)
          else
            fprintf (outfile, "<null>");
          break;
+       case dw_val_class_file:
+         fprintf (outfile, "\"%s\" (%d)", AT_file (a)->filename,
+                  AT_file (a)->emitted_number);
+         break;
        default:
          break;
        }
@@ -5796,11 +5869,9 @@ print_dwarf_line_table (FILE *outfile)
   for (i = 1; i < line_info_table_in_use; i++)
     {
       line_info = &line_info_table[i];
-      fprintf (outfile, "%5d: ", i);
-      fprintf (outfile, "%-20s",
-              VARRAY_CHAR_PTR (file_table, line_info->dw_file_num));
-      fprintf (outfile, "%6ld", line_info->dw_line_num);
-      fprintf (outfile, "\n");
+      fprintf (outfile, "%5d: %4ld %6ld\n", i,
+              line_info->dw_file_num,
+              line_info->dw_line_num);
     }
 
   fprintf (outfile, "\n\n");
@@ -5874,11 +5945,9 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
 
   CHECKSUM (at->dw_attr);
 
-  /* We don't care about differences in file numbering.  */
-  if (at->dw_attr == DW_AT_decl_file
-      /* Or that this was compiled with a different compiler snapshot; if
-        the output is the same, that's what matters.  */
-      || at->dw_attr == DW_AT_producer)
+  /* We don't care that this was compiled with a different compiler
+     snapshot; if the output is the same, that's what matters.  */
+  if (at->dw_attr == DW_AT_producer)
     return;
 
   switch (AT_class (at))
@@ -5927,6 +5996,10 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
     case dw_val_class_macptr:
       break;
 
+    case dw_val_class_file:
+      CHECKSUM_STRING (AT_file (at)->filename);
+      break;
+
     default:
       break;
     }
@@ -6029,6 +6102,9 @@ same_dw_val_p (dw_val_node *v1, dw_val_node *v2, int *mark)
     case dw_val_class_macptr:
       return 1;
 
+    case dw_val_class_file:
+      return v1->v.val_file == v2->v.val_file;
+
     default:
       return 1;
     }
@@ -6042,11 +6118,9 @@ same_attr_p (dw_attr_ref at1, dw_attr_ref at2, int *mark)
   if (at1->dw_attr != at2->dw_attr)
     return 0;
 
-  /* We don't care about differences in file numbering.  */
-  if (at1->dw_attr == DW_AT_decl_file
-      /* Or that this was compiled with a different compiler snapshot; if
-        the output is the same, that's what matters.  */
-      || at1->dw_attr == DW_AT_producer)
+  /* We don't care that this was compiled with a different compiler
+     snapshot; if the output is the same, that's what matters. */
+  if (at1->dw_attr == DW_AT_producer)
     return 1;
 
   return same_dw_val_p (&at1->dw_attr_val, &at2->dw_attr_val, mark);
@@ -6072,7 +6146,7 @@ same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
   if (VEC_length (dw_attr_node, die1->die_attr)
       != VEC_length (dw_attr_node, die2->die_attr))
     return 0;
-  
+
   for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
     if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
       return 0;
@@ -6377,7 +6451,7 @@ break_out_includes (dw_die_ref die)
 
        /* This DIE is for a secondary CU; remove it from the main one.  */
        remove_child_with_prev (c, prev);
-       
+
        if (c->die_tag == DW_TAG_GNU_BINCL)
          unit = push_new_compile_unit (unit, c);
        else if (c->die_tag == DW_TAG_GNU_EINCL)
@@ -6485,16 +6559,16 @@ build_abbrev_table (dw_die_ref die)
       dw_attr_ref die_a, abbrev_a;
       unsigned ix;
       bool ok = true;
-      
+
       if (abbrev->die_tag != die->die_tag)
        continue;
       if ((abbrev->die_child != NULL) != (die->die_child != NULL))
        continue;
-      
+
       if (VEC_length (dw_attr_node, abbrev->die_attr)
          != VEC_length (dw_attr_node, die->die_attr))
        continue;
-  
+
       for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
        {
          abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
@@ -6622,6 +6696,9 @@ size_of_die (dw_die_ref die)
          else
            size += strlen (a->dw_attr_val.v.val_str->str) + 1;
          break;
+       case dw_val_class_file:
+         size += constant_size (maybe_emit_file (a->dw_attr_val.v.val_file));
+         break;
        default:
          gcc_unreachable ();
        }
@@ -6699,21 +6776,22 @@ unmark_all_dies (dw_die_ref die)
       unmark_all_dies (AT_ref (a));
 }
 
-/* Return the size of the .debug_pubnames table  generated for the
-   compilation unit.  */
+/* Return the size of the .debug_pubnames or .debug_pubtypes table
+   generated for the compilation unit.  */
 
 static unsigned long
-size_of_pubnames (void)
+size_of_pubnames (VEC (pubname_entry, gc) * names)
 {
   unsigned long size;
   unsigned i;
+  pubname_ref p;
 
   size = DWARF_PUBNAMES_HEADER_SIZE;
-  for (i = 0; i < pubname_table_in_use; i++)
-    {
-      pubname_ref p = &pubname_table[i];
-      size += DWARF_OFFSET_SIZE + strlen (p->name) + 1;
-    }
+  for (i = 0; VEC_iterate (pubname_entry, names, i, p); i++)
+    if (names != pubtype_table
+       || p->die->die_offset != 0
+       || !flag_eliminate_unused_debug_types)
+      size += strlen (p->name) + DWARF_OFFSET_SIZE + 1;
 
   size += DWARF_OFFSET_SIZE;
   return size;
@@ -6804,6 +6882,18 @@ value_format (dw_attr_ref a)
       return DW_FORM_data;
     case dw_val_class_str:
       return AT_string_form (a);
+    case dw_val_class_file:
+      switch (constant_size (maybe_emit_file (a->dw_attr_val.v.val_file)))
+       {
+       case 1:
+         return DW_FORM_data1;
+       case 2:
+         return DW_FORM_data2;
+       case 4:
+         return DW_FORM_data4;
+       default:
+         gcc_unreachable ();
+       }
 
     default:
       gcc_unreachable ();
@@ -7163,6 +7253,15 @@ output_die (dw_die_ref die)
            dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
          break;
 
+       case dw_val_class_file:
+         {
+           int f = maybe_emit_file (a->dw_attr_val.v.val_file);
+
+           dw2_asm_output_data (constant_size (f), f, "%s (%s)", name,
+                                a->dw_attr_val.v.val_file->filename);
+           break;
+         }
+
        default:
          gcc_unreachable ();
        }
@@ -7186,7 +7285,7 @@ output_compilation_unit_header (void)
     dw2_asm_output_data (4, 0xffffffff,
       "Initial length escape value indicating 64-bit DWARF extension");
   dw2_asm_output_data (DWARF_OFFSET_SIZE,
-                       next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
+                      next_die_offset - DWARF_INITIAL_LENGTH_SIZE,
                       "Length of Compilation Unit Info");
   dw2_asm_output_data (2, DWARF_VERSION, "DWARF version number");
   dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
@@ -7259,41 +7358,71 @@ dwarf2_name (tree decl, int scope)
 static void
 add_pubname (tree decl, dw_die_ref die)
 {
-  pubname_ref p;
+  pubname_entry e;
 
   if (! TREE_PUBLIC (decl))
     return;
 
-  if (pubname_table_in_use == pubname_table_allocated)
+  e.die = die;
+  e.name = xstrdup (dwarf2_name (decl, 1));
+  VEC_safe_push (pubname_entry, gc, pubname_table, &e);
+}
+
+/* Add a new entry to .debug_pubtypes if appropriate.  */
+
+static void
+add_pubtype (tree decl, dw_die_ref die)
+{
+  pubname_entry e;
+
+  e.name = NULL;
+  if ((TREE_PUBLIC (decl)
+       || die->die_parent == comp_unit_die)
+      && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
     {
-      pubname_table_allocated += PUBNAME_TABLE_INCREMENT;
-      pubname_table
-       = ggc_realloc (pubname_table,
-                      (pubname_table_allocated * sizeof (pubname_entry)));
-      memset (pubname_table + pubname_table_in_use, 0,
-             PUBNAME_TABLE_INCREMENT * sizeof (pubname_entry));
-    }
+      e.die = die;
+      if (TYPE_P (decl))
+       {
+         if (TYPE_NAME (decl))
+           {
+             if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
+               e.name = IDENTIFIER_POINTER (TYPE_NAME (decl));
+             else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
+                      && DECL_NAME (TYPE_NAME (decl)))
+               e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl)));
+             else
+              e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
+           }
+       }
+      else
+       e.name = xstrdup (dwarf2_name (decl, 1));
 
-  p = &pubname_table[pubname_table_in_use++];
-  p->die = die;
-  p->name = xstrdup (dwarf2_name (decl, 1));
+      /* If we don't have a name for the type, there's no point in adding
+        it to the table.  */
+      if (e.name && e.name[0] != '\0')
+       VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+    }
 }
 
 /* Output the public names table used to speed up access to externally
-   visible names.  For now, only generate entries for externally
-   visible procedures.  */
+   visible names; or the public types table used to find type definitions.  */
 
 static void
-output_pubnames (void)
+output_pubnames (VEC (pubname_entry, gc) * names)
 {
   unsigned i;
-  unsigned long pubnames_length = size_of_pubnames ();
+  unsigned long pubnames_length = size_of_pubnames (names);
+  pubname_ref pub;
 
   if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
     dw2_asm_output_data (4, 0xffffffff,
       "Initial length escape value indicating 64-bit DWARF extension");
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
-                      "Length of Public Names Info");
+  if (names == pubname_table)
+    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+                        "Length of Public Names Info");
+  else
+    dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+                        "Length of Public Type Names Info");
   dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
   dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
                         debug_info_section,
@@ -7301,17 +7430,21 @@ output_pubnames (void)
   dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
                       "Compilation Unit Length");
 
-  for (i = 0; i < pubname_table_in_use; i++)
+  for (i = 0; VEC_iterate (pubname_entry, names, i, pub); i++)
     {
-      pubname_ref pub = &pubname_table[i];
-
       /* We shouldn't see pubnames for DIEs outside of the main CU.  */
-      gcc_assert (pub->die->die_mark);
+      if (names == pubname_table)
+       gcc_assert (pub->die->die_mark);
 
-      dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
-                          "DIE offset");
+      if (names != pubtype_table
+         || pub->die->die_offset != 0
+         || !flag_eliminate_unused_debug_types)
+       {
+         dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
+                              "DIE offset");
 
-      dw2_asm_output_nstring (pub->name, -1, "external name");
+         dw2_asm_output_nstring (pub->name, -1, "external name");
+       }
     }
 
   dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
@@ -7376,7 +7509,7 @@ output_aranges (void)
                        text_section_label, "Length");
   if (flag_reorder_blocks_and_partition)
     {
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label, 
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
                           "Address");
       dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
                            cold_text_section_label, "Length");
@@ -7502,10 +7635,10 @@ output_ranges (void)
 /* Data structure containing information about input files.  */
 struct file_info
 {
-  char *path;          /* Complete file name.  */
-  char *fname;         /* File name part.  */
+  const char *path;    /* Complete file name.  */
+  const char *fname;   /* File name part.  */
   int length;          /* Length of entire string.  */
-  int file_idx;                /* Index in input file table.  */
+  struct dwarf_file_data * file_idx;   /* Index in input file table.  */
   int dir_idx;         /* Index in directory table.  */
 };
 
@@ -7513,12 +7646,11 @@ struct file_info
    files.  */
 struct dir_info
 {
-  char *path;          /* Path including directory name.  */
+  const char *path;    /* Path including directory name.  */
   int length;          /* Path length.  */
   int prefix;          /* Index of directory entry which is a prefix.  */
   int count;           /* Number of files in this directory.  */
   int dir_idx;         /* Index of directory used as base.  */
-  int used;            /* Used in the end?  */
 };
 
 /* Callback function for file_info comparison.  We sort by looking at
@@ -7559,6 +7691,60 @@ file_info_cmp (const void *p1, const void *p2)
     }
 }
 
+struct file_name_acquire_data
+{
+  struct file_info *files;
+  int used_files;
+  int max_files;
+};
+
+/* Traversal function for the hash table.  */
+
+static int
+file_name_acquire (void ** slot, void *data)
+{
+  struct file_name_acquire_data *fnad = data;
+  struct dwarf_file_data *d = *slot;
+  struct file_info *fi;
+  const char *f;
+
+  gcc_assert (fnad->max_files >= d->emitted_number);
+
+  if (! d->emitted_number)
+    return 1;
+
+  gcc_assert (fnad->max_files != fnad->used_files);
+
+  fi = fnad->files + fnad->used_files++;
+
+  /* Skip all leading "./".  */
+  f = d->filename;
+  while (f[0] == '.' && IS_DIR_SEPARATOR (f[1]))
+    f += 2;
+
+  /* Create a new array entry.  */
+  fi->path = f;
+  fi->length = strlen (f);
+  fi->file_idx = d;
+
+  /* Search for the file name part.  */
+  f = strrchr (f, DIR_SEPARATOR);
+#if defined (DIR_SEPARATOR_2)
+  {
+    char *g = strrchr (fi->path, DIR_SEPARATOR_2);
+
+    if (g != NULL)
+      {
+       if (f == NULL || f < g)
+         f = g;
+      }
+  }
+#endif
+
+  fi->fname = f == NULL ? fi->path : f + 1;
+  return 1;
+}
+
 /* Output the directory table and the file name table.  We try to minimize
    the total amount of memory needed.  A heuristic is used to avoid large
    slowdowns with many input files.  */
@@ -7566,62 +7752,49 @@ file_info_cmp (const void *p1, const void *p2)
 static void
 output_file_names (void)
 {
+  struct file_name_acquire_data fnad;
+  int numfiles;
   struct file_info *files;
   struct dir_info *dirs;
   int *saved;
   int *savehere;
   int *backmap;
-  size_t ndirs;
+  int ndirs;
   int idx_offset;
-  size_t i;
+  int i;
   int idx;
 
-  /* Handle the case where file_table is empty.  */
-  if (VARRAY_ACTIVE_SIZE (file_table) <= 1)
+  if (!last_emitted_file)
     {
       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 = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (struct file_info));
-  dirs = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (struct dir_info));
-
-  /* Sort the file names.  */
-  for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
-    {
-      char *f;
+  numfiles = last_emitted_file->emitted_number;
 
-      /* Skip all leading "./".  */
-      f = VARRAY_CHAR_PTR (file_table, i);
-      while (f[0] == '.' && f[1] == '/')
-       f += 2;
-
-      /* Create a new array entry.  */
-      files[i].path = f;
-      files[i].length = strlen (f);
-      files[i].file_idx = i;
+  /* Allocate the various arrays we need.  */
+  files = alloca (numfiles * sizeof (struct file_info));
+  dirs = alloca (numfiles * sizeof (struct dir_info));
 
-      /* Search for the file name part.  */
-      f = strrchr (f, '/');
-      files[i].fname = f == NULL ? files[i].path : f + 1;
-    }
+  fnad.files = files;
+  fnad.used_files = 0;
+  fnad.max_files = numfiles;
+  htab_traverse (file_table, file_name_acquire, &fnad);
+  gcc_assert (fnad.used_files == fnad.max_files);
 
-  qsort (files + 1, VARRAY_ACTIVE_SIZE (file_table) - 1,
-        sizeof (files[0]), file_info_cmp);
+  qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
 
   /* Find all the different directories used.  */
-  dirs[0].path = files[1].path;
-  dirs[0].length = files[1].fname - files[1].path;
+  dirs[0].path = files[0].path;
+  dirs[0].length = files[0].fname - files[0].path;
   dirs[0].prefix = -1;
   dirs[0].count = 1;
   dirs[0].dir_idx = 0;
-  dirs[0].used = 0;
-  files[1].dir_idx = 0;
+  files[0].dir_idx = 0;
   ndirs = 1;
 
-  for (i = 2; i < VARRAY_ACTIVE_SIZE (file_table); i++)
+  for (i = 1; i < numfiles; i++)
     if (files[i].fname - files[i].path == dirs[ndirs - 1].length
        && memcmp (dirs[ndirs - 1].path, files[i].path,
                   dirs[ndirs - 1].length) == 0)
@@ -7632,14 +7805,13 @@ output_file_names (void)
       }
     else
       {
-       size_t j;
+       int j;
 
        /* This is a new directory.  */
        dirs[ndirs].path = files[i].path;
        dirs[ndirs].length = files[i].fname - files[i].path;
        dirs[ndirs].count = 1;
        dirs[ndirs].dir_idx = ndirs;
-       dirs[ndirs].used = 0;
        files[i].dir_idx = ndirs;
 
        /* Search for a prefix.  */
@@ -7667,7 +7839,7 @@ output_file_names (void)
   memset (saved, '\0', ndirs * sizeof (saved[0]));
   for (i = 0; i < ndirs; i++)
     {
-      size_t j;
+      int j;
       int total;
 
       /* We can always save some space for the current directory.  But this
@@ -7690,7 +7862,7 @@ output_file_names (void)
 
              if (k == (int) i)
                {
-                 /* Yes it is.  We can possibly safe some memory but
+                 /* Yes it is.  We can possibly save some memory by
                     writing the filenames in dirs[j] relative to
                     dirs[i].  */
                  savehere[j] = dirs[i].length;
@@ -7699,7 +7871,7 @@ output_file_names (void)
            }
        }
 
-      /* Check whether we can safe enough to justify adding the dirs[i]
+      /* Check whether we can save enough to justify adding the dirs[i]
         directory.  */
       if (total > dirs[i].length + 1)
        {
@@ -7716,51 +7888,33 @@ output_file_names (void)
        }
     }
 
-  /* We have to emit them in the order they appear in the file_table array
-     since the index is used in the debug info generation.  To do this
-     efficiently we generate a back-mapping of the indices first.  */
-  backmap = alloca (VARRAY_ACTIVE_SIZE (file_table) * sizeof (int));
-  for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
-    {
-      backmap[files[i].file_idx] = i;
-
-      /* Mark this directory as used.  */
-      dirs[dirs[files[i].dir_idx].dir_idx].used = 1;
-    }
-
-  /* That was it.  We are ready to emit the information.  First emit the
-     directory name table.  We have to make sure the first actually emitted
-     directory name has index one; zero is reserved for the current working
-     directory.  Make sure we do not confuse these indices with the one for the
-     constructed table (even though most of the time they are identical).  */
+  /* Emit the directory name table.  */
   idx = 1;
   idx_offset = dirs[0].length > 0 ? 1 : 0;
   for (i = 1 - idx_offset; i < ndirs; i++)
-    if (dirs[i].used != 0)
-      {
-       dirs[i].used = idx++;
-       dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
-                               "Directory Entry: 0x%x", dirs[i].used);
-      }
+    dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
+                           "Directory Entry: 0x%x", i + idx_offset);
 
   dw2_asm_output_data (1, 0, "End directory table");
 
-  /* Correct the index for the current working directory entry if it
-     exists.  */
-  if (idx_offset == 0)
-    dirs[0].used = 0;
+  /* We have to emit them in the order of emitted_number since that's
+     used in the debug info generation.  To do this efficiently we
+     generate a back-mapping of the indices first.  */
+  backmap = alloca (numfiles * sizeof (int));
+  for (i = 0; i < numfiles; i++)
+    backmap[files[i].file_idx->emitted_number - 1] = i;
 
   /* Now write all the file names.  */
-  for (i = 1; i < VARRAY_ACTIVE_SIZE (file_table); i++)
+  for (i = 0; i < numfiles; i++)
     {
       int file_idx = backmap[i];
       int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
 
       dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
-                             "File Entry: 0x%lx", (unsigned long) i);
+                             "File Entry: 0x%x", (unsigned) i + 1);
 
       /* Include directory index.  */
-      dw2_asm_output_data_uleb128 (dirs[dir_idx].used, NULL);
+      dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
 
       /* Modification time.  */
       dw2_asm_output_data_uleb128 (0, NULL);
@@ -7916,9 +8070,7 @@ output_line_info (void)
        {
          current_file = line_info->dw_file_num;
          dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
-         dw2_asm_output_data_uleb128 (current_file, "(\"%s\")",
-                                      VARRAY_CHAR_PTR (file_table,
-                                                       current_file));
+         dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
        }
 
       /* Emit debug info for the current line number, choosing the encoding
@@ -8025,9 +8177,7 @@ output_line_info (void)
        {
          current_file = line_info->dw_file_num;
          dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
-         dw2_asm_output_data_uleb128 (current_file, "(\"%s\")",
-                                      VARRAY_CHAR_PTR (file_table,
-                                                       current_file));
+         dw2_asm_output_data_uleb128 (current_file, "%lu", current_file);
        }
 
       /* Emit debug info for the current line number, choosing the encoding
@@ -8161,35 +8311,6 @@ base_type_die (tree type)
   return base_type_result;
 }
 
-/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to
-   the Dwarf "root" type for the given input type.  The Dwarf "root" type of
-   a given type is generally the same as the given type, except that if the
-   given type is a pointer or reference type, then the root type of the given
-   type is the root type of the "basis" type for the pointer or reference
-   type.  (This definition of the "root" type is recursive.) Also, the root
-   type of a `const' qualified type or a `volatile' qualified type is the
-   root type of the given type without the qualifiers.  */
-
-static tree
-root_type (tree type)
-{
-  if (TREE_CODE (type) == ERROR_MARK)
-    return error_mark_node;
-
-  switch (TREE_CODE (type))
-    {
-    case ERROR_MARK:
-      return error_mark_node;
-
-    case POINTER_TYPE:
-    case REFERENCE_TYPE:
-      return type_main_variant (root_type (TREE_TYPE (type)));
-
-    default:
-      return type_main_variant (type);
-    }
-}
-
 /* Given a pointer to an arbitrary ..._TYPE tree node, return nonzero if the
    given input type is a Dwarf "fundamental" type.  Otherwise return null.  */
 
@@ -8276,26 +8397,26 @@ is_subrange_type (tree type)
       && tree_int_cst_equal (TYPE_MAX_VALUE (type), TYPE_MAX_VALUE (subtype)))
     {
       /* The type and its subtype have the same representation.  If in
-         addition the two types also have the same name, then the given
-         type is not a subrange type, but rather a plain base type.  */
+        addition the two types also have the same name, then the given
+        type is not a subrange type, but rather a plain base type.  */
       /* FIXME: brobecker/2004-03-22:
-         Sizetype INTEGER_CSTs nodes are canonicalized.  It should
-         therefore be sufficient to check the TYPE_SIZE node pointers
-         rather than checking the actual size.  Unfortunately, we have
-         found some cases, such as in the Ada "integer" type, where
-         this is not the case.  Until this problem is solved, we need to
-         keep checking the actual size.  */
+        Sizetype INTEGER_CSTs nodes are canonicalized.  It should
+        therefore be sufficient to check the TYPE_SIZE node pointers
+        rather than checking the actual size.  Unfortunately, we have
+        found some cases, such as in the Ada "integer" type, where
+        this is not the case.  Until this problem is solved, we need to
+        keep checking the actual size.  */
       tree type_name = TYPE_NAME (type);
       tree subtype_name = TYPE_NAME (subtype);
 
       if (type_name != NULL && TREE_CODE (type_name) == TYPE_DECL)
-        type_name = DECL_NAME (type_name);
+       type_name = DECL_NAME (type_name);
 
       if (subtype_name != NULL && TREE_CODE (subtype_name) == TYPE_DECL)
-        subtype_name = DECL_NAME (subtype_name);
+       subtype_name = DECL_NAME (subtype_name);
 
       if (type_name == subtype_name)
-        return false;
+       return false;
     }
 
   return true;
@@ -8318,16 +8439,16 @@ subrange_type_die (tree type, dw_die_ref context_die)
   if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
     {
       /* The size of the subrange type and its base type do not match,
-         so we need to generate a size attribute for the subrange type.  */
+        so we need to generate a size attribute for the subrange type.  */
       add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes);
     }
 
   if (TYPE_MIN_VALUE (type) != NULL)
     add_bound_info (subrange_die, DW_AT_lower_bound,
-                    TYPE_MIN_VALUE (type));
+                   TYPE_MIN_VALUE (type));
   if (TYPE_MAX_VALUE (type) != NULL)
     add_bound_info (subrange_die, DW_AT_upper_bound,
-                    TYPE_MAX_VALUE (type));
+                   TYPE_MAX_VALUE (type));
 
   return subrange_die;
 }
@@ -8355,7 +8476,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
     = get_qualified_type (type,
                          ((is_const_type ? TYPE_QUAL_CONST : 0)
                           | (is_volatile_type ? TYPE_QUAL_VOLATILE : 0)));
-  
+
   /* If we do, then we can just use its DIE, if it exists.  */
   if (qualified_type)
     {
@@ -8363,23 +8484,25 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
       if (mod_type_die)
        return mod_type_die;
     }
-  
+
   name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
-  
+
   /* Handle C typedef types.  */
   if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name))
     {
       tree dtype = TREE_TYPE (name);
-      
+
       if (qualified_type == dtype)
        {
          /* For a named type, use the typedef.  */
          gen_type_die (qualified_type, context_die);
          return lookup_type_die (qualified_type);
        }
-      else if (DECL_ORIGINAL_TYPE (name)
-              && (is_const_type < TYPE_READONLY (dtype)
-                  || is_volatile_type < TYPE_VOLATILE (dtype)))
+      else if (is_const_type < TYPE_READONLY (dtype)
+              || is_volatile_type < TYPE_VOLATILE (dtype)
+              || (is_const_type <= TYPE_READONLY (dtype)
+                  && is_volatile_type <= TYPE_VOLATILE (dtype)
+                  && DECL_ORIGINAL_TYPE (name) != type))
        /* cv-unqualified version of named type.  Just use the unnamed
           type to which it refers.  */
        return modified_type_die (DECL_ORIGINAL_TYPE (name),
@@ -8387,7 +8510,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
                                  context_die);
       /* Else cv-qualified version of named type; fall through.  */
     }
-  
+
   if (is_const_type)
     {
       mod_type_die = new_die (DW_TAG_const_type, comp_unit_die, type);
@@ -8422,7 +8545,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
   else
     {
       gen_type_die (type, context_die);
-      
+
       /* We have to get the type_main_variant here (and pass that to the
         `lookup_type_die' routine) because the ..._TYPE node we have
         might simply be a *copy* of some original type node (where the
@@ -8436,7 +8559,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
           not the main variant.  */
        return lookup_type_die (type);
     }
-  
+
   /* Builtin types don't have a DECL_ORIGINAL_TYPE.  For those,
      don't output a DW_TAG_typedef, since there isn't one in the
      user's program; just attach a DW_AT_name to the type.  */
@@ -8450,7 +8573,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type,
        name = DECL_NAME (name);
       add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
     }
-  
+
   if (qualified_type)
     equate_type_number_to_die (qualified_type, mod_type_die);
 
@@ -8489,13 +8612,12 @@ dbx_reg_number (rtx rtl)
   gcc_assert (regno < FIRST_PSEUDO_REGISTER);
 
 #ifdef LEAF_REG_REMAP
-  {
-    int leaf_reg;
-
-    leaf_reg = LEAF_REG_REMAP (regno);
-    if (leaf_reg != -1)
-      regno = (unsigned) leaf_reg;
-  }
+  if (current_function_uses_only_leaf_regs)
+    {
+      int leaf_reg = LEAF_REG_REMAP (regno);
+      if (leaf_reg != -1)
+       regno = (unsigned) leaf_reg;
+    }
 #endif
 
   return DBX_REGISTER_NUMBER (regno);
@@ -8564,13 +8686,12 @@ multiple_reg_loc_descriptor (rtx rtl, rtx regs)
 
   reg = REGNO (rtl);
 #ifdef LEAF_REG_REMAP
-  {
-    int leaf_reg;
-
-    leaf_reg = LEAF_REG_REMAP (reg);
-    if (leaf_reg != -1)
-      reg = (unsigned) leaf_reg;
-  }
+  if (current_function_uses_only_leaf_regs)
+    {
+      int leaf_reg = LEAF_REG_REMAP (reg);
+      if (leaf_reg != -1)
+       reg = (unsigned) leaf_reg;
+    }
 #endif
   gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
   nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
@@ -8675,9 +8796,9 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset)
            }
          gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx
                      : stack_pointer_rtx));
-          offset += frame_pointer_fb_offset;
+         offset += frame_pointer_fb_offset;
 
-          return new_loc_descr (DW_OP_fbreg, offset, 0);
+         return new_loc_descr (DW_OP_fbreg, offset, 0);
        }
     }
 
@@ -8699,6 +8820,32 @@ is_based_loc (rtx rtl)
               && GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
 }
 
+/* Return a descriptor that describes the concatenation of N locations
+   used to form the address of a memory location.  */
+
+static dw_loc_descr_ref
+concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode)
+{
+  unsigned int i;
+  dw_loc_descr_ref cc_loc_result = NULL;
+  unsigned int n = XVECLEN (concatn, 0);
+
+  for (i = 0; i < n; ++i)
+    {
+      dw_loc_descr_ref ref;
+      rtx x = XVECEXP (concatn, 0, i);
+
+      ref = mem_loc_descriptor (x, mode);
+      if (ref == NULL)
+       return NULL;
+
+      add_loc_descr (&cc_loc_result, ref);
+      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
+    }
+
+  return cc_loc_result;
+}
+
 /* The following routine converts the RTL for a variable or parameter
    (resident in memory) into an equivalent Dwarf representation of a
    mechanism for getting the address of that same variable onto the top of a
@@ -8894,6 +9041,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
       mem_loc_result = int_loc_descriptor (INTVAL (rtl));
       break;
 
+    case CONCATN:
+      mem_loc_result = concatn_mem_loc_descriptor (rtl, mode);
+      break;
+
     default:
       gcc_unreachable ();
     }
@@ -8923,6 +9074,32 @@ concat_loc_descriptor (rtx x0, rtx x1)
   return cc_loc_result;
 }
 
+/* Return a descriptor that describes the concatenation of N
+   locations.  */
+
+static dw_loc_descr_ref
+concatn_loc_descriptor (rtx concatn)
+{
+  unsigned int i;
+  dw_loc_descr_ref cc_loc_result = NULL;
+  unsigned int n = XVECLEN (concatn, 0);
+
+  for (i = 0; i < n; ++i)
+    {
+      dw_loc_descr_ref ref;
+      rtx x = XVECEXP (concatn, 0, i);
+
+      ref = loc_descriptor (x);
+      if (ref == NULL)
+       return NULL;
+
+      add_loc_descr (&cc_loc_result, ref);
+      add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
+    }
+
+  return cc_loc_result;
+}
+
 /* Output a proper Dwarf location descriptor for a variable or parameter
    which is either allocated in a register or in a memory location.  For a
    register, we just generate an OP_REG and the register number.  For a
@@ -8960,6 +9137,10 @@ loc_descriptor (rtx rtl)
       loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
       break;
 
+    case CONCATN:
+      loc_result = concatn_loc_descriptor (rtl);
+      break;
+
     case VAR_LOCATION:
       /* Single part.  */
       if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
@@ -9054,7 +9235,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
          rtx rtl;
 
          /* If this is not defined, we have no way to emit the data.  */
-         if (!targetm.asm_out.output_dwarf_dtprel)
+         if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
            return 0;
 
          /* The way DW_OP_GNU_push_tls_address is specified, we can only
@@ -9091,12 +9272,13 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
       /* FALLTHRU */
 
     case RESULT_DECL:
+    case FUNCTION_DECL:
       {
        rtx rtl = rtl_for_decl_location (loc);
 
        if (rtl == NULL_RTX)
          return 0;
-        else if (GET_CODE (rtl) == CONST_INT)
+       else if (GET_CODE (rtl) == CONST_INT)
          {
            HOST_WIDE_INT val = INTVAL (rtl);
            if (TYPE_UNSIGNED (TREE_TYPE (loc)))
@@ -9143,8 +9325,9 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
     case NON_LVALUE_EXPR:
     case VIEW_CONVERT_EXPR:
     case SAVE_EXPR:
-    case MODIFY_EXPR:
-      return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address);
+    case GIMPLE_MODIFY_STMT:
+      return loc_descriptor_from_tree_1 (GENERIC_TREE_OPERAND (loc, 0),
+                                        want_address);
 
     case COMPONENT_REF:
     case BIT_FIELD_REF:
@@ -9346,13 +9529,13 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
     case MIN_EXPR:
     case MAX_EXPR:
       {
-        const enum tree_code code =
-          TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
+       const enum tree_code code =
+         TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
 
-        loc = build3 (COND_EXPR, TREE_TYPE (loc),
+       loc = build3 (COND_EXPR, TREE_TYPE (loc),
                      build2 (code, integer_type_node,
                              TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
-                      TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
+                     TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
       }
 
       /* ... fall through ...  */
@@ -9389,16 +9572,13 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
       break;
 
     case FIX_TRUNC_EXPR:
-    case FIX_CEIL_EXPR:
-    case FIX_FLOOR_EXPR:
-    case FIX_ROUND_EXPR:
       return 0;
 
     default:
       /* Leave front-end specific codes as simply unknown.  This comes
         up, for instance, with the C STMT_EXPR.  */
       if ((unsigned int) TREE_CODE (loc)
-          >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
+         >= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
        return 0;
 
 #ifdef ENABLE_CHECKING
@@ -9485,6 +9665,24 @@ simple_decl_align_in_bits (tree decl)
   return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
 }
 
+/* Return the result of rounding T up to ALIGN.  */
+
+static inline HOST_WIDE_INT
+round_up_to_align (HOST_WIDE_INT t, unsigned int align)
+{
+  /* We must be careful if T is negative because HOST_WIDE_INT can be
+     either "above" or "below" unsigned int as per the C promotion
+     rules, depending on the host, thus making the signedness of the
+     direct multiplication and division unpredictable.  */
+  unsigned HOST_WIDE_INT u = (unsigned HOST_WIDE_INT) t;
+
+  u += align - 1;
+  u /= align;
+  u *= align;
+
+  return (HOST_WIDE_INT) u;
+}
+
 /* Given a pointer to a FIELD_DECL, compute and return the byte offset of the
    lowest addressed byte of the "containing object" for the given FIELD_DECL,
    or return 0 if we are unable to determine what that offset is, either
@@ -9584,9 +9782,8 @@ field_byte_offset (tree decl)
   object_offset_in_bits = deepest_bitpos - type_size_in_bits;
 
   /* Round up to type_align by default.  This works best for bitfields.  */
-  object_offset_in_bits += type_align_in_bits - 1;
-  object_offset_in_bits /= type_align_in_bits;
-  object_offset_in_bits *= type_align_in_bits;
+  object_offset_in_bits
+    = round_up_to_align (object_offset_in_bits, type_align_in_bits);
 
   if (object_offset_in_bits > bitpos_int)
     {
@@ -9594,9 +9791,8 @@ field_byte_offset (tree decl)
       object_offset_in_bits = deepest_bitpos - type_size_in_bits;
 
       /* Round up to decl_align instead.  */
-      object_offset_in_bits += decl_align_in_bits - 1;
-      object_offset_in_bits /= decl_align_in_bits;
-      object_offset_in_bits *= decl_align_in_bits;
+      object_offset_in_bits
+       = round_up_to_align (object_offset_in_bits, decl_align_in_bits);
     }
 
   return object_offset_in_bits / BITS_PER_UNIT;
@@ -9920,14 +10116,32 @@ static tree
 reference_to_unused (tree * tp, int * walk_subtrees,
                     void * data ATTRIBUTE_UNUSED)
 {
-  if (! EXPR_P (*tp) && ! CONSTANT_CLASS_P (*tp))
+  if (! EXPR_P (*tp) && ! GIMPLE_STMT_P (*tp) && ! CONSTANT_CLASS_P (*tp))
     *walk_subtrees = 0;
-  
+
   if (DECL_P (*tp) && ! TREE_PUBLIC (*tp) && ! TREE_USED (*tp)
       && ! TREE_ASM_WRITTEN (*tp))
     return *tp;
-  else
+  else if (!flag_unit_at_a_time)
     return NULL_TREE;
+  else if (!cgraph_global_info_ready
+          && (TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == FUNCTION_DECL))
+    gcc_unreachable ();
+  else if (DECL_P (*tp) && TREE_CODE (*tp) == VAR_DECL)
+    {
+      struct varpool_node *node = varpool_node (*tp);
+      if (!node->needed)
+       return *tp;
+    }
+  else if (DECL_P (*tp) && TREE_CODE (*tp) == FUNCTION_DECL
+          && (!DECL_EXTERNAL (*tp) || DECL_DECLARED_INLINE_P (*tp)))
+    {
+      struct cgraph_node *node = cgraph_node (*tp);
+      if (!node->output)
+       return *tp;
+    }
+
+  return NULL_TREE;
 }
 
 /* Generate an RTL constant from a decl initializer INIT with decl type TYPE,
@@ -9960,7 +10174,7 @@ rtl_for_decl_init (tree init, tree type)
      CONCAT: FIXME!  */
   else if (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
     ;
-  /* Vectors only work if their mode is supported by the target.  
+  /* Vectors only work if their mode is supported by the target.
      FIXME: generic vectors ought to work too.  */
   else if (TREE_CODE (type) == VECTOR_TYPE && TYPE_MODE (type) == BLKmode)
     ;
@@ -10235,7 +10449,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
 
   gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
              || TREE_CODE (decl) == RESULT_DECL);
-            
+
   /* See if we possibly have multiple locations for this variable.  */
   loc_list = lookup_decl_loc (decl);
 
@@ -10248,7 +10462,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
       rtx varloc;
 
       /* Now that we know what section we are using for a base,
-         actually construct the list of locations.
+        actually construct the list of locations.
         The first location information is what is passed to the
         function that creates the location list, and the remaining
         locations just get added on to that list.
@@ -10302,14 +10516,14 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
 
   /* Try to get some constant RTL for this decl, and use that as the value of
      the location.  */
-  
+
   rtl = rtl_for_decl_location (decl);
   if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
     {
       add_const_value_attribute (die, rtl);
       return;
     }
-  
+
   /* If we have tried to generate the location otherwise, and it
      didn't work out (we wouldn't be here if we did), and we have a one entry
      location list, try generating a location from that.  */
@@ -10791,7 +11005,7 @@ add_abstract_origin_attribute (dw_die_ref die, tree origin)
 
       if (TYPE_P (fn))
        fn = TYPE_STUB_DECL (fn);
-      
+
       fn = decl_function_context (fn);
       if (fn)
        dwarf2out_abstract_function (fn);
@@ -10843,9 +11057,8 @@ static void
 add_src_coords_attributes (dw_die_ref die, tree decl)
 {
   expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
-  unsigned file_index = lookup_filename (s.file);
 
-  add_AT_unsigned (die, DW_AT_decl_file, file_index);
+  add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
   add_AT_unsigned (die, DW_AT_decl_line, s.line);
 }
 
@@ -11059,10 +11272,17 @@ type_tag (tree type)
         involved.  */
       else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
               && ! DECL_IGNORED_P (TYPE_NAME (type)))
-       t = DECL_NAME (TYPE_NAME (type));
+       {
+         /* We want to be extra verbose.  Don't call dwarf_name if
+            DECL_NAME isn't set.  The default hook for decl_printable_name
+            doesn't like that, and in this context it's correct to return
+            0, instead of "<anonymous>" or the like.  */
+         if (DECL_NAME (TYPE_NAME (type)))
+           name = lang_hooks.dwarf_name (TYPE_NAME (type), 2);
+       }
 
       /* Now get the name as a string, or invent one.  */
-      if (t != 0)
+      if (!name && t != 0)
        name = IDENTIFIER_POINTER (t);
     }
 
@@ -11165,6 +11385,9 @@ gen_array_type_die (tree type, dw_die_ref context_die)
 #endif
 
   add_type_attribute (array_die, element_type, 0, 0, context_die);
+
+  if (get_AT (array_die, DW_AT_name))
+    add_pubtype (type, array_die);
 }
 
 #if 0
@@ -11300,6 +11523,9 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
   else
     add_AT_flag (type_die, DW_AT_declaration, 1);
 
+  if (get_AT (type_die, DW_AT_name))
+    add_pubtype (type, type_die);
+
   return type_die;
 }
 
@@ -11591,7 +11817,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
   else if (old_die)
     {
       expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
-      unsigned file_index = lookup_filename (s.file);
+      struct dwarf_file_data * file_index = lookup_filename (s.file);
 
       if (!get_AT_flag (old_die, DW_AT_declaration)
          /* We can have a normal definition following an inline one in the
@@ -11613,7 +11839,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
         apply; we just use the old DIE.  */
       if ((old_die->die_parent == comp_unit_die || context_die == NULL)
          && (DECL_ARTIFICIAL (decl)
-             || (get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
+             || (get_AT_file (old_die, DW_AT_decl_file) == file_index
                  && (get_AT_unsigned (old_die, DW_AT_decl_line)
                      == (unsigned) s.line))))
        {
@@ -11631,12 +11857,10 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
        {
          subr_die = new_die (DW_TAG_subprogram, context_die, decl);
          add_AT_specification (subr_die, old_die);
-         if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
-           add_AT_unsigned (subr_die, DW_AT_decl_file, file_index);
-         if (get_AT_unsigned (old_die, DW_AT_decl_line)
-             != (unsigned) s.line)
-           add_AT_unsigned
-             (subr_die, DW_AT_decl_line, s.line);
+         if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
+           add_AT_file (subr_die, DW_AT_decl_file, file_index);
+         if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
+           add_AT_unsigned (subr_die, DW_AT_decl_line, s.line);
        }
     }
   else
@@ -11684,7 +11908,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
     {
       if (DECL_DECLARED_INLINE_P (decl))
        {
-          if (cgraph_function_possibly_inlined_p (decl))
+         if (cgraph_function_possibly_inlined_p (decl))
            add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
          else
            add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
@@ -11692,9 +11916,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       else
        {
          if (cgraph_function_possibly_inlined_p (decl))
-            add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
          else
-            add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
+           add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_not_inlined);
        }
 
       equate_decl_number_to_die (decl, subr_die);
@@ -11714,7 +11938,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
          ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
                                       current_function_funcdef_no);
          add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
-         
+
          add_pubname (decl, subr_die);
          add_arange (decl, subr_die);
        }
@@ -11763,7 +11987,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 
       /* Compute a displacement from the "steady-state frame pointer" to
         the CFA.  The former is what all stack slots and argument slots
-        will reference in the rtl; the later is what we've told the 
+        will reference in the rtl; the later is what we've told the
         debugger about.  We'll need to adjust all frame_base references
         by this displacement.  */
       compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
@@ -11886,17 +12110,17 @@ gen_variable_die (tree decl, dw_die_ref context_die)
                        the program.  For example, consider the C++
                        test case:
 
-                          template <class T>
-                          struct S { static const int i = 7; };
+                         template <class T>
+                         struct S { static const int i = 7; };
 
-                          template <class T>
-                          const int S<T>::i;
+                         template <class T>
+                         const int S<T>::i;
+
+                         int f() { return S<int>::i; }
 
-                          int f() { return S<int>::i; }
-                         
                        Here, S<int>::i is not DECL_EXTERNAL, but no
                        definition is required, so the compiler will
-                       not emit a definition.  */  
+                       not emit a definition.  */
                     || (TREE_CODE (decl) == VAR_DECL
                         && DECL_COMDAT (decl) && !TREE_ASM_WRITTEN (decl))
                     || class_or_namespace_scope_p (context_die));
@@ -11925,14 +12149,12 @@ gen_variable_die (tree decl, dw_die_ref context_die)
       if (DECL_NAME (decl))
        {
          expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
-         unsigned file_index = lookup_filename (s.file);
-
-         if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
-           add_AT_unsigned (var_die, DW_AT_decl_file, file_index);
+         struct dwarf_file_data * file_index = lookup_filename (s.file);
 
-         if (get_AT_unsigned (old_die, DW_AT_decl_line)
-             != (unsigned) s.line)
+         if (get_AT_file (old_die, DW_AT_decl_file) != file_index)
+           add_AT_file (var_die, DW_AT_decl_file, file_index);
 
+         if (get_AT_unsigned (old_die, DW_AT_decl_line) != (unsigned) s.line)
            add_AT_unsigned (var_die, DW_AT_decl_line, s.line);
        }
     }
@@ -12019,12 +12241,41 @@ static inline void
 add_call_src_coords_attributes (tree stmt, dw_die_ref die)
 {
   expanded_location s = expand_location (BLOCK_SOURCE_LOCATION (stmt));
-  unsigned file_index = lookup_filename (s.file);
 
-  add_AT_unsigned (die, DW_AT_call_file, file_index);
+  add_AT_file (die, DW_AT_call_file, lookup_filename (s.file));
   add_AT_unsigned (die, DW_AT_call_line, s.line);
 }
 
+
+/* If STMT's abstract origin is a function declaration and STMT's
+   first subblock's abstract origin is the function's outermost block,
+   then we're looking at the main entry point.  */
+static bool
+is_inlined_entry_point (tree stmt)
+{
+  tree decl, block;
+
+  if (!stmt || TREE_CODE (stmt) != BLOCK)
+    return false;
+
+  decl = block_ultimate_origin (stmt);
+
+  if (!decl || TREE_CODE (decl) != FUNCTION_DECL)
+    return false;
+
+  block = BLOCK_SUBBLOCKS (stmt);
+
+  if (block)
+    {
+      if (TREE_CODE (block) != BLOCK)
+       return false;
+
+      block = block_ultimate_origin (block);
+    }
+
+  return block == DECL_INITIAL (decl);
+}
+
 /* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
    Add low_pc and high_pc attributes to the DIE for a block STMT.  */
 
@@ -12037,6 +12288,13 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
     {
       tree chain;
 
+      if (is_inlined_entry_point (stmt))
+       {
+         ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+                                      BLOCK_NUMBER (stmt));
+         add_AT_lbl_id (die, DW_AT_entry_pc, label);
+       }
+
       add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
 
       chain = BLOCK_FRAGMENT_CHAIN (stmt);
@@ -12216,7 +12474,7 @@ gen_compile_unit_die (const char *filename)
     {
       add_name_attribute (die, filename);
       /* Don't add cwd for <built-in>.  */
-      if (filename[0] != DIR_SEPARATOR && filename[0] != '<')
+      if (!IS_ABSOLUTE_PATH (filename) && filename[0] != '<')
        add_comp_dir_attribute (die);
     }
 
@@ -12422,6 +12680,9 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die)
          && ! decl_function_context (TYPE_STUB_DECL (type)))
        VEC_safe_push (tree, gc, incomplete_types, type);
     }
+
+  if (get_AT (type_die, DW_AT_name))
+    add_pubtype (type, type_die);
 }
 
 /* Generate a DIE for a subroutine _type_.  */
@@ -12438,6 +12699,9 @@ gen_subroutine_type_die (tree type, dw_die_ref context_die)
   add_prototyped_attribute (subr_die, type);
   add_type_attribute (subr_die, return_type, 0, 0, context_die);
   gen_formal_types_die (type, subr_die);
+
+  if (get_AT (subr_die, DW_AT_name))
+    add_pubtype (type, subr_die);
 }
 
 /* Generate a DIE for a type definition.  */
@@ -12477,6 +12741,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
 
   if (DECL_ABSTRACT (decl))
     equate_decl_number_to_die (decl, type_die);
+
+  if (get_AT (type_die, DW_AT_name))
+    add_pubtype (decl, type_die);
 }
 
 /* Generate a type description DIE.  */
@@ -12597,7 +12864,12 @@ gen_type_die (tree type, dw_die_ref context_die)
        }
 
       if (TREE_CODE (type) == ENUMERAL_TYPE)
-       gen_enumeration_type_die (type, context_die);
+       {
+         /* This might have been written out by the call to
+            declare_in_namespace.  */
+         if (!TREE_ASM_WRITTEN (type))
+           gen_enumeration_type_die (type, context_die);
+       }
       else
        gen_struct_or_union_type_die (type, context_die);
 
@@ -12726,8 +12998,8 @@ gen_block_die (tree stmt, dw_die_ref context_die, int depth)
          if (debug_info_level > DINFO_LEVEL_TERSE)
            /* We are not in terse mode so *any* local declaration counts
               as being a "significant" one.  */
-           must_output_die = (BLOCK_VARS (stmt) != NULL 
-                              && (TREE_USED (stmt) 
+           must_output_die = (BLOCK_VARS (stmt) != NULL
+                              && (TREE_USED (stmt)
                                   || TREE_ASM_WRITTEN (stmt)
                                   || BLOCK_ABSTRACT (stmt)));
          else
@@ -12784,19 +13056,19 @@ decls_for_scope (tree stmt, dw_die_ref context_die, int depth)
       for (decl = BLOCK_VARS (stmt); decl != NULL; decl = TREE_CHAIN (decl))
        {
          dw_die_ref die;
-         
+
          if (TREE_CODE (decl) == FUNCTION_DECL)
            die = lookup_decl_die (decl);
          else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
            die = lookup_type_die (TREE_TYPE (decl));
          else
            die = NULL;
-         
+
          if (die != NULL && die->die_parent == NULL)
            add_child_die (context_die, die);
          /* Do not produce debug information for static variables since
             these might be optimized out.  We are called for these later
-            in cgraph_varpool_analyze_pending_decls. */
+            in varpool_analyze_pending_decls. */
          if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
            ;
          else
@@ -12901,7 +13173,8 @@ force_decl_die (tree decl)
   return decl_die;
 }
 
-/* Returns the DIE for TYPE.  A DIE is always returned.  */
+/* Returns the DIE for TYPE, that must not be a base type.  A DIE is
+   always returned.  */
 
 static dw_die_ref
 force_type_die (tree type)
@@ -13207,7 +13480,6 @@ dwarf2out_imported_module_or_decl (tree decl, tree context)
 {
   dw_die_ref imported_die, at_import_die;
   dw_die_ref scope_die;
-  unsigned file_index;
   expanded_location xloc;
 
   if (debug_info_level <= DINFO_LEVEL_TERSE)
@@ -13230,7 +13502,12 @@ dwarf2out_imported_module_or_decl (tree decl, tree context)
 
   /* For TYPE_DECL or CONST_DECL, lookup TREE_TYPE.  */
   if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
-    at_import_die = force_type_die (TREE_TYPE (decl));
+    {
+      if (is_base_type (TREE_TYPE (decl)))
+       at_import_die = base_type_die (TREE_TYPE (decl));
+      else
+       at_import_die = force_type_die (TREE_TYPE (decl));
+    }
   else
     {
       at_import_die = lookup_decl_die (decl);
@@ -13263,8 +13540,7 @@ dwarf2out_imported_module_or_decl (tree decl, tree context)
     imported_die = new_die (DW_TAG_imported_declaration, scope_die, context);
 
   xloc = expand_location (input_location);
-  file_index = lookup_filename (xloc.file);
-  add_AT_unsigned (imported_die, DW_AT_decl_file, file_index);
+  add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
   add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
   add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
 }
@@ -13347,7 +13623,7 @@ dwarf2out_decl (tree decl)
       if (debug_info_level <= DINFO_LEVEL_TERSE)
        return;
       if (lookup_decl_die (decl) != NULL)
-        return;
+       return;
       break;
 
     case TYPE_DECL:
@@ -13428,6 +13704,23 @@ dwarf2out_ignore_block (tree block)
   return 1;
 }
 
+/* Hash table routines for file_hash.  */
+
+static int
+file_table_eq (const void *p1_p, const void *p2_p)
+{
+  const struct dwarf_file_data * p1 = p1_p;
+  const char * p2 = p2_p;
+  return strcmp (p1->filename, p2) == 0;
+}
+
+static hashval_t
+file_table_hash (const void *p_p)
+{
+  const struct dwarf_file_data * p = p_p;
+  return htab_hash_string (p->filename);
+}
+
 /* Lookup FILE_NAME (in the list of filenames that we know about here in
    dwarf2out.c) and return its "index".  The index of each (known) filename is
    just a unique number which is associated with only that one filename.  We
@@ -13439,46 +13732,30 @@ dwarf2out_ignore_block (tree block)
    the index of the filename was looked up last.  This handles the majority of
    all searches.  */
 
-static unsigned
+static struct dwarf_file_data *
 lookup_filename (const char *file_name)
 {
-  size_t i, n;
-  char *save_file_name;
+  void ** slot;
+  struct dwarf_file_data * created;
 
   /* Check to see if the file name that was searched on the previous
      call matches this file name.  If so, return the index.  */
-  if (file_table_last_lookup_index != 0)
-    {
-      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;
-    }
+  if (file_table_last_lookup
+      && (file_name == file_table_last_lookup->filename
+         || strcmp (file_table_last_lookup->filename, file_name) == 0))
+    return file_table_last_lookup;
 
   /* Didn't match the previous lookup, search the table.  */
-  n = VARRAY_ACTIVE_SIZE (file_table);
-  for (i = 1; i < n; i++)
-    if (strcmp (file_name, VARRAY_CHAR_PTR (file_table, i)) == 0)
-      {
-       file_table_last_lookup_index = i;
-       return i;
-      }
-
-  /* Add the new entry to the end of the filename table.  */
-  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);
+  slot = htab_find_slot_with_hash (file_table, file_name,
+                                  htab_hash_string (file_name), INSERT);
+  if (*slot)
+    return *slot;
 
-  /* If the assembler is emitting the file table, and we aren't eliminating
-     unused debug types, then we must emit .file here.  If we are eliminating
-     unused debug types, then this will be done by the maybe_emit_file call in
-     prune_unused_types_walk_attribs.  */
-
-  if (DWARF2_ASM_LINE_DEBUG_INFO && ! flag_eliminate_unused_debug_types)
-    return maybe_emit_file (i);
-
-  return i;
+  created = ggc_alloc (sizeof (struct dwarf_file_data));
+  created->filename = file_name;
+  created->emitted_number = 0;
+  *slot = created;
+  return created;
 }
 
 /* If the assembler will construct the file table, then translate the compiler
@@ -13488,38 +13765,25 @@ lookup_filename (const char *file_name)
    types, which may include filenames.  */
 
 static int
-maybe_emit_file (int fileno)
+maybe_emit_file (struct dwarf_file_data * fd)
 {
-  if (DWARF2_ASM_LINE_DEBUG_INFO && fileno > 0)
+  if (! fd->emitted_number)
     {
-      if (!VARRAY_UINT (file_table_emitted, fileno))
+      if (last_emitted_file)
+       fd->emitted_number = last_emitted_file->emitted_number + 1;
+      else
+       fd->emitted_number = 1;
+      last_emitted_file = fd;
+
+      if (DWARF2_ASM_LINE_DEBUG_INFO)
        {
-         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));
+         fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
+         output_quoted_string (asm_out_file, fd->filename);
          fputc ('\n', asm_out_file);
        }
-      return VARRAY_UINT (file_table_emitted, fileno);
     }
-  else
-    return fileno;
-}
-
-/* Initialize the compiler internal file table.  */
-
-static void
-init_file_table (void)
-{
-  /* 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;
+  return fd->emitted_number;
 }
 
 /* Called by the final INSN scan whenever we see a var location.  We
@@ -13581,7 +13845,7 @@ static void
 dwarf2out_begin_function (tree fun)
 {
   htab_empty (decl_loc_table);
-  
+
   if (function_section (fun) != text_section)
     have_multiple_function_sections = true;
 }
@@ -13596,6 +13860,8 @@ dwarf2out_source_line (unsigned int line, const char *filename)
   if (debug_info_level >= DINFO_LEVEL_NORMAL
       && line != 0)
     {
+      int file_num = maybe_emit_file (lookup_filename (filename));
+
       switch_to_section (current_function_section ());
 
       /* If requested, emit something human-readable.  */
@@ -13605,10 +13871,6 @@ dwarf2out_source_line (unsigned int line, const char *filename)
 
       if (DWARF2_ASM_LINE_DEBUG_INFO)
        {
-         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);
 
@@ -13618,8 +13880,9 @@ dwarf2out_source_line (unsigned int line, const char *filename)
       else if (function_section (current_function_decl) != text_section)
        {
          dw_separate_line_info_ref line_info;
-         targetm.asm_out.internal_label (asm_out_file, SEPARATE_LINE_CODE_LABEL,
-                                    separate_line_info_table_in_use);
+         targetm.asm_out.internal_label (asm_out_file,
+                                         SEPARATE_LINE_CODE_LABEL,
+                                         separate_line_info_table_in_use);
 
          /* Expand the line info table if necessary.  */
          if (separate_line_info_table_in_use
@@ -13640,7 +13903,7 @@ dwarf2out_source_line (unsigned int line, const char *filename)
          /* Add the new entry at the end of the line_info_table.  */
          line_info
            = &separate_line_info_table[separate_line_info_table_in_use++];
-         line_info->dw_file_num = lookup_filename (filename);
+         line_info->dw_file_num = file_num;
          line_info->dw_line_num = line;
          line_info->function = current_function_funcdef_no;
        }
@@ -13665,7 +13928,7 @@ dwarf2out_source_line (unsigned int line, const char *filename)
 
          /* Add the new entry at the end of the line_info_table.  */
          line_info = &line_info_table[line_info_table_in_use++];
-         line_info->dw_file_num = lookup_filename (filename);
+         line_info->dw_file_num = file_num;
          line_info->dw_line_num = line;
        }
     }
@@ -13687,15 +13950,14 @@ dwarf2out_start_source_file (unsigned int lineno, const char *filename)
 
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {
-      int fileno;
+      int file_num = maybe_emit_file (lookup_filename (filename));
 
       switch_to_section (debug_macinfo_section);
       dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
       dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
                                   lineno);
 
-      fileno = maybe_emit_file (lookup_filename (filename));
-      dw2_asm_output_data_uleb128 (fileno, "Filename we just started");
+      dw2_asm_output_data_uleb128 (file_num, "file %s", filename);
     }
 }
 
@@ -13754,7 +14016,9 @@ dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
 static void
 dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 {
-  init_file_table ();
+  /* Allocate the file_table.  */
+  file_table = htab_create_ggc (50, file_table_hash,
+                               file_table_eq, NULL);
 
   /* Allocate the decl_die_table.  */
   decl_die_table = htab_create_ggc (10, decl_die_table_hash,
@@ -13782,6 +14046,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
   /* Zero-th entry is allocated, but unused.  */
   line_info_table_in_use = 1;
 
+  /* Allocate the pubtypes and pubnames vectors.  */
+  pubname_table = VEC_alloc (pubname_entry, gc, 32);
+  pubtype_table = VEC_alloc (pubname_entry, gc, 32);
+
   /* Generate the initial DIE for the .debug section.  Note that the (string)
      value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE
      will (typically) be a relative pathname and that this pathname should be
@@ -13808,6 +14076,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
                                   SECTION_DEBUG, NULL);
   debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
                                        SECTION_DEBUG, NULL);
+#ifdef DEBUG_PUBTYPES_SECTION
+  debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
+                                       SECTION_DEBUG, NULL);
+#endif
   debug_str_section = get_section (DEBUG_STR_SECTION,
                                   DEBUG_STR_SECTION_FLAGS, NULL);
   debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
@@ -13819,7 +14091,7 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
   ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
                               DEBUG_ABBREV_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
-  ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label, 
+  ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
                               COLD_TEXT_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
 
@@ -13878,7 +14150,7 @@ static void
 verify_marks_clear (dw_die_ref die)
 {
   dw_die_ref c;
-  
+
   gcc_assert (! die->die_mark);
   FOR_EACH_CHILD (die, c, verify_marks_clear (c));
 }
@@ -13891,7 +14163,7 @@ static void
 prune_unmark_dies (dw_die_ref die)
 {
   dw_die_ref c;
-  
+
   if (die->die_mark)
     die->die_mark = 0;
   FOR_EACH_CHILD (die, c, prune_unmark_dies (c));
@@ -13914,12 +14186,6 @@ prune_unused_types_walk_attribs (dw_die_ref 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->dw_attr == DW_AT_call_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);
-       }
       /* Set the string's refcount to 0 so that prune_unused_types_mark
         accounts properly for it.  */
       if (AT_class (a) == dw_val_class_str)
@@ -13950,9 +14216,9 @@ prune_unused_types_mark (dw_die_ref die, int dokids)
       prune_unused_types_walk_attribs (die);
 
       /* If this node is a specification,
-         also mark the definition, if it exists.  */
+        also mark the definition, if it exists.  */
       if (get_AT_flag (die, DW_AT_declaration) && die->die_definition)
-        prune_unused_types_mark (die->die_definition, 1);
+       prune_unused_types_mark (die->die_definition, 1);
     }
 
   if (dokids && die->die_mark != 2)
@@ -13982,35 +14248,36 @@ prune_unused_types_walk (dw_die_ref die)
   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:
-    if (die->die_perennial_p)
-      break;
+  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:
+      if (die->die_perennial_p)
+       break;
 
-    /* It's a type node --- don't mark it.  */
-    return;
+      /* It's a type node --- don't mark it.  */
+      return;
 
-  default:
-    /* Mark everything else.  */
-    break;
+    default:
+      /* Mark everything else.  */
+      break;
   }
 
   die->die_mark = 1;
@@ -14063,7 +14330,7 @@ prune_unused_types_prune (dw_die_ref die)
 
   if (! die->die_child)
     return;
-  
+
   c = die->die_child;
   do {
     dw_die_ref prev = c;
@@ -14096,6 +14363,7 @@ prune_unused_types (void)
 {
   unsigned int i;
   limbo_die_node *node;
+  pubname_ref pub;
 
 #if ENABLE_ASSERT_CHECKING
   /* All the marks should already be clear.  */
@@ -14111,8 +14379,8 @@ prune_unused_types (void)
 
   /* 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; VEC_iterate (pubname_entry, pubname_table, i, pub); i++)
+    prune_unused_types_mark (pub->die, 1);
   for (i = 0; i < arange_table_in_use; i++)
     prune_unused_types_mark (arange_table[i], 1);
 
@@ -14129,6 +14397,21 @@ prune_unused_types (void)
     prune_unmark_dies (node->die);
 }
 
+/* Set the parameter to true if there are any relative pathnames in
+   the file table.  */
+static int
+file_table_relative_p (void ** slot, void *param)
+{
+  bool *p = param;
+  struct dwarf_file_data *d = *slot;
+  if (d->emitted_number && !IS_ABSOLUTE_PATH (d->filename))
+    {
+      *p = true;
+      return 0;
+    }
+  return 1;
+}
+
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
@@ -14141,19 +14424,14 @@ dwarf2out_finish (const char *filename)
   /* Add the name for the main input file now.  We delayed this from
      dwarf2out_init to avoid complications with PCH.  */
   add_name_attribute (comp_unit_die, filename);
-  if (filename[0] != DIR_SEPARATOR)
+  if (!IS_ABSOLUTE_PATH (filename))
     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
-           /* Don't add cwd for <built-in>.  */
-           && VARRAY_CHAR_PTR (file_table, i)[0] != '<')
-         {
-           add_comp_dir_attribute (comp_unit_die);
-           break;
-         }
+      bool p = false;
+      htab_traverse (file_table, file_table_relative_p, &p);
+      if (p)
+       add_comp_dir_attribute (comp_unit_die);
     }
 
   /* Traverse the limbo die list, and add parent/child links.  The only
@@ -14198,7 +14476,9 @@ dwarf2out_finish (const char *filename)
              else if (TYPE_P (node->created_for))
                context = TYPE_CONTEXT (node->created_for);
 
-             gcc_assert (context && TREE_CODE (context) == FUNCTION_DECL);
+             gcc_assert (context
+                         && (TREE_CODE (context) == FUNCTION_DECL
+                             || TREE_CODE (context) == NAMESPACE_DECL));
 
              origin = lookup_decl_die (context);
              if (origin)
@@ -14238,17 +14518,6 @@ dwarf2out_finish (const char *filename)
       targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0);
     }
 
-  /* Output the source line correspondence table.  We must do this
-     even if there is no line information.  Otherwise, on an empty
-     translation unit, we will generate a present, but empty,
-     .debug_info section.  IRIX 6.5 `nm' will then complain when
-     examining the file.  */
-  if (! DWARF2_ASM_LINE_DEBUG_INFO)
-    {
-      switch_to_section (debug_line_section);
-      output_line_info ();
-    }
-
   /* We can only use the low/high_pc attributes if all of the code was
      in .text.  */
   if (!have_multiple_function_sections)
@@ -14292,12 +14561,21 @@ dwarf2out_finish (const char *filename)
   output_abbrev_section ();
 
   /* Output public names table if necessary.  */
-  if (pubname_table_in_use)
+  if (!VEC_empty (pubname_entry, pubname_table))
     {
       switch_to_section (debug_pubnames_section);
-      output_pubnames ();
+      output_pubnames (pubname_table);
     }
 
+#ifdef DEBUG_PUBTYPES_SECTION
+  /* Output public types table if necessary.  */
+  if (!VEC_empty (pubname_entry, pubtype_table))
+    {
+      switch_to_section (debug_pubtypes_section);
+      output_pubnames (pubtype_table);
+    }
+#endif
+
   /* Output the address range information.  We only put functions in the arange
      table, so don't write it out if we don't have any.  */
   if (fde_table_in_use)
@@ -14314,6 +14592,18 @@ dwarf2out_finish (const char *filename)
       output_ranges ();
     }
 
+  /* Output the source line correspondence table.  We must do this
+     even if there is no line information.  Otherwise, on an empty
+     translation unit, we will generate a present, but empty,
+     .debug_info section.  IRIX 6.5 `nm' will then complain when
+     examining the file.  This is done late so that any filenames
+     used by the debug_info section are marked as 'used'.  */
+  if (! DWARF2_ASM_LINE_DEBUG_INFO)
+    {
+      switch_to_section (debug_line_section);
+      output_line_info ();
+    }
+
   /* Have to end the macro section.  */
   if (debug_info_level >= DINFO_LEVEL_VERBOSE)
     {