This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][RFC] Early debug + LTO, half-way dwarf2out refactoring


This is a sneak peek at early LTO debug, the patch as-is bootstraps
ok for all languages but testing is still riddled with ICEs
(mostly LTO due to now streaming DECL_ABSTRACT_ORIGIN but also
due to some global constructor/destructors not getting early dwarf).

The patch is somewhat large because it touches debug hooks and debug
assembler output routines.

The patch contains final refactoring of dwarf2out_late_global_decl
and initial refactoring of dwarf2out_function_decl, to make both
handle the late DIE annotation path only (as said, only partly
done for dwarf2out_function_decl which still does parameter and
scopes + vars the "fat" way).

LTO will give noisy "plugin needed to handle lto object" warnings
from the linker.  No good way to solve that without changing the
linker.  I've tested with GNU ld only but I think gold should work
as well.  We do not have the perfect I/O setup for the early debug
linking yet (needs linker and/or assembler changes), so we do
an incremental link combining all early debug and linking that
object in the final link.

Ignore all the #ifdef noise in lto-wrapper.c - I have to clean this up.

Bootstrapped on x86_64-unknown-linux-gnu.

At least you can play with it a bit.

Richard.

Index: trunk/gcc/dwarf2asm.c
===================================================================
*** trunk.orig/gcc/dwarf2asm.c	2015-08-27 16:29:15.254198472 +0200
--- trunk/gcc/dwarf2asm.c	2015-08-27 16:30:05.991665058 +0200
*************** along with GCC; see the file COPYING3.
*** 33,38 ****
--- 33,40 ----
  #include "dwarf2asm.h"
  #include "dwarf2.h"
  #include "tm_p.h"
+ #include "function.h"
+ #include "emit-rtl.h"
  
  
  /* Output an unaligned integer with the given value and size.  Prefer not
*************** dw2_asm_output_offset (int size, const c
*** 190,201 ****
    va_start (ap, comment);
  
  #ifdef ASM_OUTPUT_DWARF_OFFSET
!   ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, base);
  #else
    dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
  #endif
  
    if (flag_debug_asm && comment)
      {
        fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
        vfprintf (asm_out_file, comment, ap);
--- 192,230 ----
    va_start (ap, comment);
  
  #ifdef ASM_OUTPUT_DWARF_OFFSET
!   ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, 0, base);
  #else
    dw2_assemble_integer (size, gen_rtx_SYMBOL_REF (Pmode, label));
  #endif
  
    if (flag_debug_asm && comment)
+     {
+       fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+       vfprintf (asm_out_file, comment, ap);
+     }
+   fputc ('\n', asm_out_file);
+ 
+   va_end (ap);
+ }
+ 
+ void
+ dw2_asm_output_offset (int size, const char *label, HOST_WIDE_INT offset,
+ 		       section *base ATTRIBUTE_UNUSED,
+ 		       const char *comment, ...)
+ {
+   va_list ap;
+ 
+   va_start (ap, comment);
+ 
+ #ifdef ASM_OUTPUT_DWARF_OFFSET
+   ASM_OUTPUT_DWARF_OFFSET (asm_out_file, size, label, offset, base);
+ #else
+   dw2_assemble_integer (size, gen_rtx_PLUS (Pmode,
+ 					    gen_rtx_SYMBOL_REF (Pmode, label),
+ 					    gen_int_mode (offset, Pmode)));
+ #endif
+ 
+   if (flag_debug_asm && comment)
      {
        fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
        vfprintf (asm_out_file, comment, ap);
Index: trunk/gcc/dwarf2asm.h
===================================================================
*** trunk.orig/gcc/dwarf2asm.h	2015-08-27 16:29:15.255198481 +0200
--- trunk/gcc/dwarf2asm.h	2015-08-27 16:30:05.991665058 +0200
*************** extern void dw2_asm_output_offset (int,
*** 40,45 ****
--- 40,49 ----
  				   const char *, ...)
       ATTRIBUTE_NULL_PRINTF_4;
  
+ extern void dw2_asm_output_offset (int, const char *, HOST_WIDE_INT,
+ 				   section *, const char *, ...)
+      ATTRIBUTE_NULL_PRINTF_5;
+ 
  extern void dw2_asm_output_addr (int, const char *, const char *, ...)
       ATTRIBUTE_NULL_PRINTF_3;
  
Index: trunk/gcc/dwarf2out.c
===================================================================
*** trunk.orig/gcc/dwarf2out.c	2015-08-27 16:29:15.314199024 +0200
--- trunk/gcc/dwarf2out.c	2015-08-27 16:30:06.000665141 +0200
*************** along with GCC; see the file COPYING3.
*** 102,107 ****
--- 102,108 ----
  #include "tree-dfa.h"
  #include "gdb/gdb-index.h"
  #include "rtl-iter.h"
+ #include "lto-section-names.h"
  
  static void dwarf2out_source_line (unsigned int, const char *, int, bool);
  static rtx_insn *last_var_location_insn;
*************** build_cfa_aligned_loc (dw_cfa_location *
*** 2419,2425 ****
  
  static void dwarf2out_init (const char *);
  static void dwarf2out_finish (const char *);
! static void dwarf2out_early_finish (void);
  static void dwarf2out_assembly_start (void);
  static void dwarf2out_define (unsigned int, const char *);
  static void dwarf2out_undef (unsigned int, const char *);
--- 2420,2426 ----
  
  static void dwarf2out_init (const char *);
  static void dwarf2out_finish (const char *);
! static void dwarf2out_early_finish (const char *);
  static void dwarf2out_assembly_start (void);
  static void dwarf2out_define (unsigned int, const char *);
  static void dwarf2out_undef (unsigned int, const char *);
*************** static void dwarf2out_begin_function (tr
*** 2441,2446 ****
--- 2442,2451 ----
  static void dwarf2out_end_function (unsigned int);
  static void dwarf2out_register_main_translation_unit (tree unit);
  static void dwarf2out_set_name (tree, tree);
+ static void dwarf2out_register_external_die (tree decl, const char *sym,
+ 					     unsigned HOST_WIDE_INT off);
+ static bool dwarf2out_die_ref_for_decl (tree decl, const char **sym,
+ 					unsigned HOST_WIDE_INT *off);
  
  /* The debug hooks structure.  */
  
*************** const struct gcc_debug_hooks dwarf2_debu
*** 2475,2480 ****
--- 2480,2487 ----
    dwarf2out_late_global_decl,
    dwarf2out_type_decl,		/* type_decl */
    dwarf2out_imported_module_or_decl,
+   dwarf2out_die_ref_for_decl,
+   dwarf2out_register_external_die,
    debug_nothing_tree,		/* deferred_inline_function */
    /* The DWARF 2 backend tries to reduce debugging bloat by not
       emitting the abstract description of inline functions until
*************** const struct gcc_debug_hooks dwarf2_line
*** 2493,2499 ****
  {
    dwarf2out_init,
    debug_nothing_charstar,
!   debug_nothing_void,
    debug_nothing_void,
    debug_nothing_int_charstar,
    debug_nothing_int_charstar,
--- 2500,2506 ----
  {
    dwarf2out_init,
    debug_nothing_charstar,
!   debug_nothing_charstar,
    debug_nothing_void,
    debug_nothing_int_charstar,
    debug_nothing_int_charstar,
*************** const struct gcc_debug_hooks dwarf2_line
*** 2515,2520 ****
--- 2522,2529 ----
    debug_nothing_tree,		         /* late_global_decl */
    debug_nothing_tree_int,		 /* type_decl */
    debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
+   debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+   debug_nothing_tree_charstar_uhwi,	 /* register_external_die */
    debug_nothing_tree,		         /* deferred_inline_function */
    debug_nothing_tree,		         /* outlining_inline_function */
    debug_nothing_rtx_code_label,	         /* label */
*************** typedef struct GTY((chain_circular ("%h.
*** 2650,2655 ****
--- 2659,2671 ----
    /* Die is used and must not be pruned as unused.  */
    BOOL_BITFIELD die_perennial_p : 1;
    BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+   /* For an external ref to die_symbol if die_offset contains an extra
+      offset to that symbol.  */
+   BOOL_BITFIELD with_offset : 1;
+   /* Whether this DIE was removed from the DIE tree, for example via
+      prune_unused_types.  We don't consider those present from the
+      DIE lookup routines.  */
+   BOOL_BITFIELD removed : 1;
    /* Lots of spare bits.  */
  }
  die_node;
*************** remove_child_with_prev (dw_die_ref child
*** 4815,4820 ****
--- 4831,4837 ----
      prev->die_sib = child->die_sib;
    if (child->die_parent->die_child == child)
      child->die_parent->die_child = prev;
+   child->die_sib = NULL;
  }
  
  /* Replace OLD_CHILD with NEW_CHILD.  PREV must have the property that
*************** replace_child (dw_die_ref old_child, dw_
*** 4841,4846 ****
--- 4858,4864 ----
      }
    if (old_child->die_parent->die_child == old_child)
      old_child->die_parent->die_child = new_child;
+   old_child->die_sib = NULL;
  }
  
  /* Move all children from OLD_PARENT to NEW_PARENT.  */
*************** remove_child_TAG (dw_die_ref die, enum d
*** 4871,4879 ****
  	remove_child_with_prev (c, prev);
  	c->die_parent = NULL;
  	/* Might have removed every child.  */
! 	if (c == c->die_sib)
  	  return;
! 	c = c->die_sib;
        }
    } while (c != die->die_child);
  }
--- 4889,4897 ----
  	remove_child_with_prev (c, prev);
  	c->die_parent = NULL;
  	/* Might have removed every child.  */
! 	if (die->die_child == NULL)
  	  return;
! 	c = prev->die_sib;
        }
    } while (c != die->die_child);
  }
*************** new_die (enum dwarf_tag tag_value, dw_di
*** 5000,5006 ****
  static inline dw_die_ref
  lookup_type_die (tree type)
  {
!   return TYPE_SYMTAB_DIE (type);
  }
  
  /* Given a TYPE_DIE representing the type TYPE, if TYPE is an
--- 5018,5030 ----
  static inline dw_die_ref
  lookup_type_die (tree type)
  {
!   dw_die_ref die = TYPE_SYMTAB_DIE (type);
!   if (die && die->removed)
!     {
!       TYPE_SYMTAB_DIE (type) = NULL;
!       return NULL;
!     }
!   return die;
  }
  
  /* Given a TYPE_DIE representing the type TYPE, if TYPE is an
*************** decl_die_hasher::equal (die_node *x, tre
*** 5065,5071 ****
  static inline dw_die_ref
  lookup_decl_die (tree decl)
  {
!   return decl_die_table->find_with_hash (decl, DECL_UID (decl));
  }
  
  /* Returns a hash value for X (which really is a var_loc_list).  */
--- 5089,5265 ----
  static inline dw_die_ref
  lookup_decl_die (tree decl)
  {
!   dw_die_ref *die = decl_die_table->find_slot_with_hash (decl, DECL_UID (decl),
! 							 NO_INSERT);
!   if (!die)
!     return NULL;
!   if ((*die)->removed)
!     {
!       decl_die_table->clear_slot (die);
!       return NULL;
!     }
!   return *die;
! }
! 
! 
! /* For DECL which might have early dwarf output query a SYMBOL + OFFSET
!    style reference.  Return true if we found one refering to a DIE for
!    DECL, otherwise return false.  */
! 
! static bool
! dwarf2out_die_ref_for_decl (tree decl, const char **sym,
! 			    unsigned HOST_WIDE_INT *off)
! {
!   dw_die_ref die;
! 
!   if (flag_wpa && !decl_die_table)
!     return false;
! 
!   if (TREE_CODE (decl) == BLOCK)
!     die = BLOCK_DIE (decl);
!   else
!     die = lookup_decl_die (decl);
!   if (!die)
!     return false;
! 
!   /* During WPA stage we currently use DIEs to store the
!      decl <-> label + offset map.  That's quite inefficient but it
!      works for now.  */
!   if (flag_wpa)
!     {
!       dw_die_ref ref = get_AT_ref (die, DW_AT_abstract_origin);
!       if (!ref)
! 	{
! 	  gcc_assert (die == comp_unit_die ());
! 	  return false;
! 	}
!       *off = ref->die_offset;
!       *sym = ref->die_id.die_symbol;
!       return true;
!     }
! 
!   /* Similar to get_ref_die_offset_label, but using the "correct"
!      label.  */
!   *off = die->die_offset;
!   while (die->die_parent)
!     die = die->die_parent;
!   /* For the containing CU DIE we compute a die_symbol in
!      compute_section_prefix.  */
!   gcc_assert (die->die_tag == DW_TAG_compile_unit
! 	      && die->die_id.die_symbol != NULL);
!   *sym = die->die_id.die_symbol;
!   return true;
! }
! 
! /* Add a reference of kind ATTR_KIND to a DIE at SYMBOL + OFFSET to DIE.  */
! 
! static void
! add_AT_external_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind,
! 			 const char *symbol, HOST_WIDE_INT offset)
! {
!   /* Create a fake DIE that contains the reference.  Don't use
!      new_die because we don't want to end up in the limbo list.  */
!   dw_die_ref ref = ggc_cleared_alloc<die_node> ();
!   ref->die_tag = die->die_tag;
!   ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
!   ref->die_offset = offset;
!   ref->with_offset = 1;
!   add_AT_die_ref (die, attr_kind, ref);
! }
! 
! /* Create a DIE for DECL if required and add a reference to a DIE
!    at SYMBOL + OFFSET which contains attributes dumped early.  */
! 
! static void
! dwarf2out_register_external_die (tree decl, const char *sym,
! 				 unsigned HOST_WIDE_INT off)
! {
!   if (debug_info_level == DINFO_LEVEL_NONE)
!     return;
! 
!   if (flag_wpa && !decl_die_table)
!     decl_die_table = hash_table<decl_die_hasher>::create_ggc (1000);
! 
!   dw_die_ref die
!     = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
!   gcc_assert (!die);
!   if (!die)
!     {
!       tree ctx;
!       dw_die_ref parent = NULL;
!       /* Need to lookup a DIE for the decls context - the containing
!          function or translation unit.  */
!       if (TREE_CODE (decl) == BLOCK)
! 	ctx = BLOCK_SUPERCONTEXT (decl);
!       else
! 	ctx = DECL_CONTEXT (decl);
!       while (ctx && TYPE_P (ctx))
! 	ctx = TYPE_CONTEXT (ctx);
!       if (ctx)
! 	{
! 	  if (TREE_CODE (ctx) == BLOCK)
! 	    parent = BLOCK_DIE (ctx);
! 	  else if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL
! 		   /* Keep the 1:1 association during WPA.  */
! 		   && !flag_wpa)
! 	    /* Otherwise all late annotations go to the main CU which
! 	       imports the original CUs.  */
! 	    parent = comp_unit_die ();
! 	  else
! 	    parent = lookup_decl_die (ctx);
! 	}
!       /* Create a DIE "stub".  */
!       switch (TREE_CODE (decl))
! 	{
! 	case TRANSLATION_UNIT_DECL:
! 	  if (flag_wpa)
! 	    {
! 	      /* Keep the 1:1 association during WPA.  */
! 	      die = new_die (DW_TAG_compile_unit, NULL, decl);
! 	      break;
! 	    }
! 	  {
! 	    die = comp_unit_die ();
! 	    dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
! 	    add_AT_external_die_ref (import, DW_AT_import, sym, off);
! 	    /* We re-target all CU decls to the LTRANS CU DIE, so no need
! 	       to create a DIE for the original CUs.  */
! 	    return;
! 	  }
! 	case NAMESPACE_DECL:
! 	  /* ???  LANG issue - DW_TAG_module for fortran.  Either look
! 	     at the input language (if we have enough DECL_CONTEXT to follow)
! 	     or use a bit in tree_decl_with_vis to record the distinction.  */
! 	  die = new_die (DW_TAG_namespace, parent, decl);
! 	  break;
! 	case FUNCTION_DECL:
! 	  die = new_die (DW_TAG_subprogram, parent, decl);
! 	  break;
! 	case VAR_DECL:
! 	case RESULT_DECL:
! 	  die = new_die (DW_TAG_variable, parent, decl);
! 	  break;
! 	case PARM_DECL:
! 	  die = new_die (DW_TAG_formal_parameter, parent, decl);
! 	  break;
! 	case LABEL_DECL:
! 	  die = new_die (DW_TAG_label, parent, decl);
! 	  break;
! 	case BLOCK:
! 	  die = new_die (DW_TAG_lexical_block, parent, decl);
! 	  break;
! 	default:
! 	  gcc_unreachable ();
! 	}
! //      die->dumped_early = true;
!       if (TREE_CODE (decl) == BLOCK)
! 	BLOCK_DIE (decl) = die;
!       else
! 	equate_decl_number_to_die (decl, die);
!     }
! 
!   /* Add a reference to the DIE providing early debug at $sym + off.  */
!   add_AT_external_die_ref (die, DW_AT_abstract_origin, sym, off);
  }
  
  /* Returns a hash value for X (which really is a var_loc_list).  */
*************** print_dw_val (dw_val_node *val, bool rec
*** 5544,5550 ****
  			       die->die_id.die_type_node->signature);
  	    }
  	  else if (die->die_id.die_symbol)
! 	    fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
  	  else
  	    fprintf (outfile, "die -> %ld", die->die_offset);
  	  fprintf (outfile, " (%p)", (void *) die);
--- 5738,5748 ----
  			       die->die_id.die_type_node->signature);
  	    }
  	  else if (die->die_id.die_symbol)
! 	    {
! 	      fprintf (outfile, "die -> label: %s", die->die_id.die_symbol);
! 	      if (die->with_offset)
! 		fprintf (outfile, " + %ld", die->die_offset);
! 	    }
  	  else
  	    fprintf (outfile, "die -> %ld", die->die_offset);
  	  fprintf (outfile, " (%p)", (void *) die);
*************** debug_dwarf (void)
*** 5717,5722 ****
--- 5915,5943 ----
    print_die (comp_unit_die (), stderr);
  }
  
+ DEBUG_FUNCTION void
+ verify_die (dw_die_ref die)
+ {
+   if (die->die_parent == NULL
+       && die->die_sib == NULL)
+     return;
+   dw_die_ref x = die;
+   do
+     {
+       x->die_mark = 1;
+       x = x->die_sib;
+     }
+   while (x && !x->die_mark);
+   gcc_assert (x == die);
+   x = die;
+   do
+     {
+       x->die_mark = 0;
+       x = x->die_sib;
+     }
+   while (x && x->die_mark);
+ }
+ 
  #ifdef ENABLE_CHECKING
  /* Sanity checks on DIEs.  */
  
*************** static unsigned int comdat_symbol_number
*** 6774,6780 ****
     children, and set comdat_symbol_id accordingly.  */
  
  static void
! compute_section_prefix (dw_die_ref unit_die)
  {
    const char *die_name = get_AT_string (unit_die, DW_AT_name);
    const char *base = die_name ? lbasename (die_name) : "anonymous";
--- 6995,7001 ----
     children, and set comdat_symbol_id accordingly.  */
  
  static void
! compute_section_prefix_1 (dw_die_ref unit_die, bool comdat_p)
  {
    const char *die_name = get_AT_string (unit_die, DW_AT_name);
    const char *base = die_name ? lbasename (die_name) : "anonymous";
*************** compute_section_prefix (dw_die_ref unit_
*** 6793,6799 ****
    unmark_all_dies (unit_die);
    md5_finish_ctx (&ctx, checksum);
  
!   sprintf (name, "%s.", base);
    clean_symbol_name (name);
  
    p = name + strlen (name);
--- 7014,7024 ----
    unmark_all_dies (unit_die);
    md5_finish_ctx (&ctx, checksum);
  
!   /* ???  Now that we compute this for comp_unit_die () we have a
!      DW_AT_name that might not start with a letter but with anything
!      valid for filenames - clean_symbol_name doesn't fix that up.
!      Thus unconditionally append 'g' for now (can we use isalpha?).  */
!   sprintf (name, "g%s.", base);
    clean_symbol_name (name);
  
    p = name + strlen (name);
*************** compute_section_prefix (dw_die_ref unit_
*** 6803,6809 ****
        p += 2;
      }
  
!   comdat_symbol_id = unit_die->die_id.die_symbol = xstrdup (name);
    comdat_symbol_number = 0;
  }
  
--- 7028,7042 ----
        p += 2;
      }
  
!   unit_die->die_id.die_symbol = xstrdup (name);
!   unit_die->comdat_type_p = comdat_p;
! }
! 
! static void
! compute_section_prefix (dw_die_ref unit_die)
! {
!   compute_section_prefix_1 (unit_die, true);
!   comdat_symbol_id = unit_die->die_id.die_symbol;
    comdat_symbol_number = 0;
  }
  
*************** output_die (dw_die_ref die)
*** 8921,8927 ****
  
    /* If someone in another CU might refer to us, set up a symbol for
       them to point to.  */
!   if (! die->comdat_type_p && die->die_id.die_symbol)
      output_die_symbol (die);
  
    dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
--- 9154,9164 ----
  
    /* If someone in another CU might refer to us, set up a symbol for
       them to point to.  */
!   if (! die->comdat_type_p && die->die_id.die_symbol
!       /* Don't output the symbol twice.  For LTO we want the label
!          on the section beginning, not on the actual DIE.  */
!       && (!flag_generate_lto
! 	  || die->die_tag != DW_TAG_compile_unit))
      output_die_symbol (die);
  
    dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
*************** output_die (dw_die_ref die)
*** 9100,9107 ****
  		    size = DWARF2_ADDR_SIZE;
  		  else
  		    size = DWARF_OFFSET_SIZE;
! 		  dw2_asm_output_offset (size, sym, debug_info_section, "%s",
! 					 name);
  		}
  	    }
  	  else
--- 9337,9358 ----
  		    size = DWARF2_ADDR_SIZE;
  		  else
  		    size = DWARF_OFFSET_SIZE;
! 		  /* ???  We cannot unconditionally output die_offset if
! 		     non-zero - at least -feliminate-dwarf2-dups will
! 		     create references to those DIEs via symbols.  And we
! 		     do not clear its DIE offset after outputting it
! 		     (and the label refers to the actual DIEs, not the
! 		     DWARF CU unit header which is when using label + offset
! 		     would be the correct thing to do).
! 		     ???  It could use the section name and go w/o a
! 		     new symbol even?
! 		     ???  This is the reason for the with_offset flag.  */
! 		  if (AT_ref (a)->with_offset)
! 		    dw2_asm_output_offset (size, sym, AT_ref (a)->die_offset,
! 					   debug_info_section, "%s", name);
! 		  else
! 		    dw2_asm_output_offset (size, sym, debug_info_section, "%s",
! 					   name);
  		}
  	    }
  	  else
*************** output_comp_unit (dw_die_ref die, int ou
*** 9252,9258 ****
    calc_die_sizes (die);
  
    oldsym = die->die_id.die_symbol;
!   if (oldsym)
      {
        tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
  
--- 9503,9509 ----
    calc_die_sizes (die);
  
    oldsym = die->die_id.die_symbol;
!   if (oldsym && die->comdat_type_p)
      {
        tmp = XALLOCAVEC (char, strlen (oldsym) + 24);
  
*************** output_comp_unit (dw_die_ref die, int ou
*** 9268,9273 ****
--- 9519,9543 ----
        info_section_emitted = true;
      }
  
+   /* For LTO cross unit DIE refs we want a symbol on the start of the
+      debuginfo section, not on the CU DIE.
+      ???  We could simply use the symbol output by output_die and account
+      for the extra offset produced by the CU heade (which has fixed size?).  */
+   if (flag_generate_lto && oldsym)
+     {
+       /* ???  No way to get visibility assembled without a decl.  */
+       tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ 			      get_identifier (oldsym), char_type_node);
+       TREE_PUBLIC (decl) = true;
+       TREE_STATIC (decl) = true;
+       DECL_ARTIFICIAL (decl) = true;
+       DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+       DECL_VISIBILITY_SPECIFIED (decl) = true;
+       targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+       targetm.asm_out.globalize_label (asm_out_file, oldsym);
+       ASM_OUTPUT_LABEL (asm_out_file, oldsym);
+     }
+ 
    /* Output debugging information.  */
    output_compilation_unit_header ();
    output_die (die);
*************** add_location_or_const_value_attribute (d
*** 16160,16166 ****
    if (TREE_CODE (decl) == ERROR_MARK)
      return false;
  
!   if (get_AT (die, attr))
      return true;
  
    gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
--- 16430,16442 ----
    if (TREE_CODE (decl) == ERROR_MARK)
      return false;
  
!   if (get_AT (die, attr)
!       /* If we genrated DW_AT_const_value early we're done.
!          ???  We prefer a location to an DW_AT_const_value so remove
! 	 a DW_AT_const_value added early in favor of a location.
! 	 ???  Some locations end up as DW_AT_const_value anyway...
! 	 (those generated via rtl_for_decl_location).  */
!       || get_AT (die, DW_AT_const_value))
      return true;
  
    gcc_assert (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL
*************** add_scalar_info (dw_die_ref die, enum dw
*** 16779,16784 ****
--- 17055,17073 ----
        if (decl != NULL_TREE)
  	{
  	  dw_die_ref decl_die = lookup_decl_die (decl);
+ 	  /* ???  Force a DIE for the decl - this is probably
+ 	     artificially generated by gimplifying type sizes and thus
+ 	     early debug wouldn't have created a DIE for it because
+ 	     the decl is not associated with any block.  */
+ 	  /* ???  This doesn't work as type sizes are not always gimplified
+ 	     like for
+ 	       void fred () { int n = 10; double (*x)[n]; }
+ 	     and thus we fail to clear DECL_IGNORED_P for those.  But
+ 	     we don't have debug-info for the above case anyway.  */
+ 	  if (! decl_die
+ 	      && ! DECL_IGNORED_P (decl)
+ 	      && DECL_ARTIFICIAL (decl))
+ 	    decl_die = force_decl_die (decl);
  
  	  /* ??? Can this happen, or should the variable have been bound
  	     first?  Probably it can, since I imagine that we try to create
*************** gen_formal_parameter_die (tree node, tre
*** 18038,18044 ****
  	 thing.  */
        if (parm_die && parm_die->die_parent != context_die)
  	{
! 	  if (!DECL_ABSTRACT_P (node))
  	    {
  	      /* This can happen when creating an inlined instance, in
  		 which case we need to create a new DIE that will get
--- 18327,18335 ----
  	 thing.  */
        if (parm_die && parm_die->die_parent != context_die)
  	{
! 	  /* ???  The DIE parent is the "abstract" copy and the context_die
! 	     is the specification "copy".  */
! 	  if (!DECL_ABSTRACT_P (node) && !in_lto_p)
  	    {
  	      /* This can happen when creating an inlined instance, in
  		 which case we need to create a new DIE that will get
*************** gen_type_die_for_member (tree type, tree
*** 18307,18313 ****
  /* Forward declare these functions, because they are mutually recursive
    with their set_block_* pairing functions.  */
  static void set_decl_origin_self (tree);
- static void set_decl_abstract_flags (tree, vec<tree> &);
  
  /* Given a pointer to some BLOCK node, if the BLOCK_ABSTRACT_ORIGIN for the
     given BLOCK node is NULL, set the BLOCK_ABSTRACT_ORIGIN for the node so
--- 18598,18603 ----
*************** set_decl_origin_self (tree decl)
*** 18380,18530 ****
      }
  }
  
! /* Given a pointer to some BLOCK node, set the BLOCK_ABSTRACT flag to 1
!    and if it wasn't 1 before, push it to abstract_vec vector.
!    For all local decls and all local sub-blocks (recursively) do it
!    too.  */
! 
! static void
! set_block_abstract_flags (tree stmt, vec<tree> &abstract_vec)
! {
!   tree local_decl;
!   tree subblock;
!   unsigned int i;
! 
!   if (!BLOCK_ABSTRACT (stmt))
!     {
!       abstract_vec.safe_push (stmt);
!       BLOCK_ABSTRACT (stmt) = 1;
!     }
! 
!   for (local_decl = BLOCK_VARS (stmt);
!        local_decl != NULL_TREE;
!        local_decl = DECL_CHAIN (local_decl))
!     if (! DECL_EXTERNAL (local_decl))
!       set_decl_abstract_flags (local_decl, abstract_vec);
! 
!   for (i = 0; i < BLOCK_NUM_NONLOCALIZED_VARS (stmt); i++)
!     {
!       local_decl = BLOCK_NONLOCALIZED_VAR (stmt, i);
!       if ((TREE_CODE (local_decl) == VAR_DECL && !TREE_STATIC (local_decl))
! 	  || TREE_CODE (local_decl) == PARM_DECL)
! 	set_decl_abstract_flags (local_decl, abstract_vec);
!     }
! 
!   for (subblock = BLOCK_SUBBLOCKS (stmt);
!        subblock != NULL_TREE;
!        subblock = BLOCK_CHAIN (subblock))
!     set_block_abstract_flags (subblock, abstract_vec);
! }
! 
! /* Given a pointer to some ..._DECL node, set DECL_ABSTRACT_P flag on it
!    to 1 and if it wasn't 1 before, push to abstract_vec vector.
!    In the case where the decl is a FUNCTION_DECL also set the abstract
!    flags for all of the parameters, local vars, local
!    blocks and sub-blocks (recursively).  */
! 
! static void
! set_decl_abstract_flags (tree decl, vec<tree> &abstract_vec)
! {
!   if (!DECL_ABSTRACT_P (decl))
!     {
!       abstract_vec.safe_push (decl);
!       DECL_ABSTRACT_P (decl) = 1;
!     }
! 
!   if (TREE_CODE (decl) == FUNCTION_DECL)
!     {
!       tree arg;
! 
!       for (arg = DECL_ARGUMENTS (decl); arg; arg = DECL_CHAIN (arg))
! 	if (!DECL_ABSTRACT_P (arg))
! 	  {
! 	    abstract_vec.safe_push (arg);
! 	    DECL_ABSTRACT_P (arg) = 1;
! 	  }
!       if (DECL_INITIAL (decl) != NULL_TREE
! 	  && DECL_INITIAL (decl) != error_mark_node)
! 	set_block_abstract_flags (DECL_INITIAL (decl), abstract_vec);
!     }
! }
! 
! /* Generate the DWARF2 info for the "abstract" instance of a function which we
!    may later generate inlined and/or out-of-line instances of.
! 
!    FIXME: In the early-dwarf world, this function, and most of the
!           DECL_ABSTRACT code should be obsoleted.  The early DIE _is_
!           the abstract instance.  All we would need to do is annotate
!           the early DIE with the appropriate DW_AT_inline in late
!           dwarf (perhaps in gen_inlined_subroutine_die).
! 
! 	  However, we can't do this yet, because LTO streaming of DIEs
! 	  has not been implemented yet.  */
  
  static void
  dwarf2out_abstract_function (tree decl)
  {
    dw_die_ref old_die;
-   tree save_fn;
-   tree context;
-   hash_table<decl_loc_hasher> *old_decl_loc_table;
-   hash_table<dw_loc_list_hasher> *old_cached_dw_loc_list_table;
-   int old_call_site_count, old_tail_call_site_count;
-   struct call_arg_loc_node *old_call_arg_locations;
  
    /* Make sure we have the actual abstract inline, not a clone.  */
    decl = DECL_ORIGIN (decl);
  
    old_die = lookup_decl_die (decl);
!   if (old_die && get_AT (old_die, DW_AT_inline))
      /* We've already generated the abstract instance.  */
      return;
  
!   /* We can be called while recursively when seeing block defining inlined subroutine
!      DIE.  Be sure to not clobber the outer location table nor use it or we would
!      get locations in abstract instantces.  */
!   old_decl_loc_table = decl_loc_table;
!   decl_loc_table = NULL;
!   old_cached_dw_loc_list_table = cached_dw_loc_list_table;
!   cached_dw_loc_list_table = NULL;
!   old_call_arg_locations = call_arg_locations;
!   call_arg_locations = NULL;
!   old_call_site_count = call_site_count;
!   call_site_count = -1;
!   old_tail_call_site_count = tail_call_site_count;
!   tail_call_site_count = -1;
  
!   /* Be sure we've emitted the in-class declaration DIE (if any) first, so
!      we don't get confused by DECL_ABSTRACT_P.  */
!   if (debug_info_level > DINFO_LEVEL_TERSE)
      {
!       context = decl_class_context (decl);
!       if (context)
! 	gen_type_die_for_member
! 	  (context, decl, decl_function_context (decl) ? NULL : comp_unit_die ());
      }
  
!   /* Pretend we've just finished compiling this function.  */
!   save_fn = current_function_decl;
!   current_function_decl = decl;
! 
!   auto_vec<tree, 64> abstract_vec;
!   set_decl_abstract_flags (decl, abstract_vec);
!   dwarf2out_decl (decl);
!   unsigned int i;
!   tree t;
!   FOR_EACH_VEC_ELT (abstract_vec, i, t)
!     if (TREE_CODE (t) == BLOCK)
!       BLOCK_ABSTRACT (t) = 0;
!     else
!       DECL_ABSTRACT_P (t) = 0;
! 
!   current_function_decl = save_fn;
!   decl_loc_table = old_decl_loc_table;
!   cached_dw_loc_list_table = old_cached_dw_loc_list_table;
!   call_arg_locations = old_call_arg_locations;
!   call_site_count = old_call_site_count;
!   tail_call_site_count = old_tail_call_site_count;
  }
  
  /* Helper function of premark_used_types() which gets called through
--- 18670,18728 ----
      }
  }
  
! /* Mark the early DIE for DECL as the abstract instance.  */
  
  static void
  dwarf2out_abstract_function (tree decl)
  {
    dw_die_ref old_die;
  
    /* Make sure we have the actual abstract inline, not a clone.  */
    decl = DECL_ORIGIN (decl);
  
+   if (DECL_IGNORED_P (decl))
+     return;
+ 
    old_die = lookup_decl_die (decl);
!   /* With early debug we always have an old DIE.  */
!   gcc_assert (old_die != NULL);
!   if (get_AT (old_die, DW_AT_inline))
      /* We've already generated the abstract instance.  */
      return;
  
! #if 0
!   /* For LTO we end up with a stub DIE here refering to the early
!      dwarf.  We can't put DW_AT_inline there (nor can we check if
!      it is there) and we don't want to clone another "abstract"
!      instance just to be able to do that.
!      So simply do nothing(?).
!      ???  We have to fix code refering to the abstract instance
!      to refer to the stub DIE (which becomes the concrete instance)
!      to refer to the stub DIEs target.  Otherwise we generate
!      wrong debug.  */
!   if (in_lto_p)
!     return;
! #endif
  
!   /* Go ahead and put DW_AT_inline on the DIE.  */
!   if (DECL_DECLARED_INLINE_P (decl))
      {
!       if (cgraph_function_possibly_inlined_p (decl))
! 	add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_inlined);
!       else
! 	add_AT_unsigned (old_die, DW_AT_inline, DW_INL_declared_not_inlined);
!     }
!   else
!     {
!       if (cgraph_function_possibly_inlined_p (decl))
! 	add_AT_unsigned (old_die, DW_AT_inline, DW_INL_inlined);
!       else
! 	add_AT_unsigned (old_die, DW_AT_inline, DW_INL_not_inlined);
      }
  
!   if (DECL_DECLARED_INLINE_P (decl)
!       && lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
!     add_AT_flag (old_die, DW_AT_artificial, 1);
  }
  
  /* Helper function of premark_used_types() which gets called through
*************** gen_subprogram_die (tree decl, dw_die_re
*** 18747,18753 ****
--- 18945,18960 ----
        if (old_die && old_die->die_parent == NULL)
  	add_child_die (context_die, old_die);
  
+ #if 1
+       dw_die_ref c;
+       if (old_die
+ 	  && (c = get_AT_ref (old_die, DW_AT_abstract_origin))
+ 	  /* ???  In LTO all origin DIEs still refer to the early
+ 	     debug copy.  Detect that.  */
+ 	  && get_AT (c, DW_AT_inline))
+ #else
        if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+ #endif
  	{
  	  /* If we have a DW_AT_abstract_origin we have a working
  	     cached version.  */
*************** gen_subprogram_die (tree decl, dw_die_re
*** 18771,18776 ****
--- 18978,18986 ----
      {
        /* A declaration that has been previously dumped needs no
  	 additional information.  */
+       /* ???  In LTO an existing DIE always means an early generated DIE.
+          We should really refactor the entry points to dwarf generation
+ 	 so we have the separate stages completely separated.  */
        if (declaration)
  	return;
  
*************** gen_subprogram_die (tree decl, dw_die_re
*** 19211,19219 ****
    tree outer_scope = DECL_INITIAL (decl);
    if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
      {
-       int call_site_note_count = 0;
-       int tail_call_site_note_count = 0;
- 
        /* Emit a DW_TAG_variable DIE for a named return value.  */
        if (DECL_NAME (DECL_RESULT (decl)))
  	gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
--- 19421,19426 ----
*************** gen_subprogram_die (tree decl, dw_die_re
*** 19222,19376 ****
  	 DIEs for the locals.  The second time, we fill in the
  	 location info.  */
        decls_for_scope (outer_scope, subr_die);
- 
-       if (call_arg_locations && !dwarf_strict)
- 	{
- 	  struct call_arg_loc_node *ca_loc;
- 	  for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
- 	    {
- 	      dw_die_ref die = NULL;
- 	      rtx tloc = NULL_RTX, tlocc = NULL_RTX;
- 	      rtx arg, next_arg;
- 
- 	      for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
- 		   arg; arg = next_arg)
- 		{
- 		  dw_loc_descr_ref reg, val;
- 		  machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
- 		  dw_die_ref cdie, tdie = NULL;
- 
- 		  next_arg = XEXP (arg, 1);
- 		  if (REG_P (XEXP (XEXP (arg, 0), 0))
- 		      && next_arg
- 		      && MEM_P (XEXP (XEXP (next_arg, 0), 0))
- 		      && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))
- 		      && REGNO (XEXP (XEXP (arg, 0), 0))
- 			 == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)))
- 		    next_arg = XEXP (next_arg, 1);
- 		  if (mode == VOIDmode)
- 		    {
- 		      mode = GET_MODE (XEXP (XEXP (arg, 0), 0));
- 		      if (mode == VOIDmode)
- 			mode = GET_MODE (XEXP (arg, 0));
- 		    }
- 		  if (mode == VOIDmode || mode == BLKmode)
- 		    continue;
- 		  if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
- 		    {
- 		      gcc_assert (ca_loc->symbol_ref == NULL_RTX);
- 		      tloc = XEXP (XEXP (arg, 0), 1);
- 		      continue;
- 		    }
- 		  else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
- 			   && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
- 		    {
- 		      gcc_assert (ca_loc->symbol_ref == NULL_RTX);
- 		      tlocc = XEXP (XEXP (arg, 0), 1);
- 		      continue;
- 		    }
- 		  reg = NULL;
- 		  if (REG_P (XEXP (XEXP (arg, 0), 0)))
- 		    reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
- 					      VAR_INIT_STATUS_INITIALIZED);
- 		  else if (MEM_P (XEXP (XEXP (arg, 0), 0)))
- 		    {
- 		      rtx mem = XEXP (XEXP (arg, 0), 0);
- 		      reg = mem_loc_descriptor (XEXP (mem, 0),
- 						get_address_mode (mem),
- 						GET_MODE (mem),
- 						VAR_INIT_STATUS_INITIALIZED);
- 		    }
- 		  else if (GET_CODE (XEXP (XEXP (arg, 0), 0))
- 			   == DEBUG_PARAMETER_REF)
- 		    {
- 		      tree tdecl
- 			= DEBUG_PARAMETER_REF_DECL (XEXP (XEXP (arg, 0), 0));
- 		      tdie = lookup_decl_die (tdecl);
- 		      if (tdie == NULL)
- 			continue;
- 		    }
- 		  else
- 		    continue;
- 		  if (reg == NULL
- 		      && GET_CODE (XEXP (XEXP (arg, 0), 0))
- 			 != DEBUG_PARAMETER_REF)
- 		    continue;
- 		  val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode,
- 					    VOIDmode,
- 					    VAR_INIT_STATUS_INITIALIZED);
- 		  if (val == NULL)
- 		    continue;
- 		  if (die == NULL)
- 		    die = gen_call_site_die (decl, subr_die, ca_loc);
- 		  cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
- 				  NULL_TREE);
- 		  if (reg != NULL)
- 		    add_AT_loc (cdie, DW_AT_location, reg);
- 		  else if (tdie != NULL)
- 		    add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie);
- 		  add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
- 		  if (next_arg != XEXP (arg, 1))
- 		    {
- 		      mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 1));
- 		      if (mode == VOIDmode)
- 			mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 0));
- 		      val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1),
- 							    0), 1),
- 						mode, VOIDmode,
- 						VAR_INIT_STATUS_INITIALIZED);
- 		      if (val != NULL)
- 			add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
- 		    }
- 		}
- 	      if (die == NULL
- 		  && (ca_loc->symbol_ref || tloc))
- 		die = gen_call_site_die (decl, subr_die, ca_loc);
- 	      if (die != NULL && (tloc != NULL_RTX || tlocc != NULL_RTX))
- 		{
- 		  dw_loc_descr_ref tval = NULL;
- 
- 		  if (tloc != NULL_RTX)
- 		    tval = mem_loc_descriptor (tloc,
- 					       GET_MODE (tloc) == VOIDmode
- 					       ? Pmode : GET_MODE (tloc),
- 					       VOIDmode,
- 					       VAR_INIT_STATUS_INITIALIZED);
- 		  if (tval)
- 		    add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
- 		  else if (tlocc != NULL_RTX)
- 		    {
- 		      tval = mem_loc_descriptor (tlocc,
- 						 GET_MODE (tlocc) == VOIDmode
- 						 ? Pmode : GET_MODE (tlocc),
- 						 VOIDmode,
- 						 VAR_INIT_STATUS_INITIALIZED);
- 		      if (tval)
- 			add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered,
- 				    tval);
- 		    }
- 		}
- 	      if (die != NULL)
- 		{
- 		  call_site_note_count++;
- 		  if (ca_loc->tail_call_p)
- 		    tail_call_site_note_count++;
- 		}
- 	    }
- 	}
-       call_arg_locations = NULL;
-       call_arg_loc_last = NULL;
-       if (tail_call_site_count >= 0
- 	  && tail_call_site_count == tail_call_site_note_count
- 	  && !dwarf_strict)
- 	{
- 	  if (call_site_count >= 0
- 	      && call_site_count == call_site_note_count)
- 	    add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
- 	  else
- 	    add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
- 	}
-       call_site_count = -1;
-       tail_call_site_count = -1;
      }
  }
  
--- 19429,19434 ----
*************** gen_variable_die (tree decl, tree origin
*** 19669,19675 ****
        && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
      {
        if (early_dwarf)
! 	add_pubname (decl_or_origin, var_die);
        else
  	add_location_or_const_value_attribute (var_die, decl_or_origin,
  					       decl == NULL, DW_AT_location);
--- 19727,19752 ----
        && (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
      {
        if (early_dwarf)
! 	{
! 	  add_pubname (decl_or_origin, var_die);
! 	  /* We use the early dwarf of a function as abstract instance,
! 	     so make sure to add DW_AT_const_value attributes to it.  */
! 	  /* ???  This can end up adding a 4MB DW_AT_const_value even
! 	     if we later output the initializer into .data.  Now such
! 	     a DW_AT_const_value is wasteful even for optimized out
! 	     decls, so the following is fine but we really have to limit
! 	     the size of DW_AT_const_values we output (a DW_AT_constant_value
! 	     might be even smaller than the DW_OP_addr we generate to
! 	     point to the in-memory location).  */
! 	  int sz;
! 	  if (DECL_INITIAL (decl_or_origin)
! 	      && (sz = int_size_in_bytes
! 		         (TREE_TYPE (DECL_INITIAL (decl_or_origin)))) != -1
! 	      /* So for now allow DW_AT_const_value of size less or equal to
! 	         that what is required for the reference to emitted data.  */
! 	      && sz <= (PTR_SIZE + 2))
! 	    tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
! 	}
        else
  	add_location_or_const_value_attribute (var_die, decl_or_origin,
  					       decl == NULL, DW_AT_location);
*************** gen_lexical_block_die (tree stmt, dw_die
*** 19905,19910 ****
--- 19982,20001 ----
      {
        /* If this is an inlined instance, create a new lexical die for
  	 anything below to attach DW_AT_abstract_origin to.  */
+       /* ???  Between early and late dwarf we get confused here
+ 	 by set_block_origin_self () called by dwarf2out_function_decl
+ 	 via gen_decl_die
+ 
+ 	   If we're emitting an out-of-line copy of an inline function,
+ 	   emit info for the abstract instance and set up to refer to it.
+ 
+ 	 which ends up calling dwarf2out_abstract_function (late)
+ 	 and then set_decl_origin_self.  This should have been discovered
+ 	 early already.  Or rather we do have the abstract instance
+ 	 output early already, no need to do that again.  So
+ 	 dwarf2out_abstract_function should take the early output
+ 	 DIEs and create a duplicate that just refers back to the
+ 	 "abstract" early instance?  */
        if (old_die)
  	{
  	  stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
*************** gen_block_die (tree stmt, dw_die_ref con
*** 21008,21013 ****
--- 21099,21129 ----
      decls_for_scope (stmt, context_die);
  }
  
+ static tree
+ process_vla_type (tree *tp, int *walk_subtrees, void *ctx)
+ {
+   /* ???  walk_type_fields doesn't walk TYPE_SIZE and friends and
+      while it walks TYPE_DOMAIN for arrays it doesn't walk
+      TYPE_MIN/MAX_VALUE.  Just special-case the ARRAY_TYPE domain
+      type case here for now.  */
+   if (TREE_CODE (*tp) == INTEGER_TYPE)
+     {
+       if (TREE_CODE (TYPE_MIN_VALUE (*tp)) == VAR_DECL
+ 	  && DECL_ARTIFICIAL (TYPE_MIN_VALUE (*tp))
+ 	  && !DECL_IGNORED_P (TYPE_MIN_VALUE (*tp)))
+ 	gen_decl_die (TYPE_MIN_VALUE (*tp), NULL_TREE, (dw_die_ref) ctx);
+       if (TREE_CODE (TYPE_MAX_VALUE (*tp)) == VAR_DECL
+ 	  && DECL_ARTIFICIAL (TYPE_MAX_VALUE (*tp))
+ 	  && !DECL_IGNORED_P (TYPE_MAX_VALUE (*tp)))
+ 	gen_decl_die (TYPE_MAX_VALUE (*tp), NULL_TREE, (dw_die_ref) ctx);
+     }
+ 
+   if (!TYPE_P (*tp))
+     *walk_subtrees = 0;
+ 
+   return NULL_TREE;
+ }
+ 
  /* Process variable DECL (or variable with origin ORIGIN) within
     block STMT and add it to CONTEXT_DIE.  */
  static void
*************** process_scope_var (tree stmt, tree decl,
*** 21020,21026 ****
      die = lookup_decl_die (decl_or_origin);
    else if (TREE_CODE (decl_or_origin) == TYPE_DECL
             && TYPE_DECL_IS_STUB (decl_or_origin))
!     die = lookup_type_die (TREE_TYPE (decl_or_origin));
    else
      die = NULL;
  
--- 21136,21159 ----
      die = lookup_decl_die (decl_or_origin);
    else if (TREE_CODE (decl_or_origin) == TYPE_DECL
             && TYPE_DECL_IS_STUB (decl_or_origin))
!     {
!       /* ???  Ada has those in BLOCK scope but with types that have
! 	 the a scope of other types (that's already odd).  OTOH for
! 	 these decls process_scope_var isn't the correct place to
! 	 generate a DIE for the type (we won't generate one for the
! 	 decl).  Instead it looks like we may have this code only
! 	 to eventually set the context of a limbo type DIE already
! 	 created?!  */
!       /* ???  Note the issue is we try to re-create the DIE late
!          if it was optimized as unused early (this BLOCK reference
! 	 does not count as "use").  So refactoring dwarf2out_function_decl
! 	 more to only include late parts should "fix" this as well
! 	 (we'd simply never call gen_decl_die there but only its
! 	 annotation part for existing dies).  */
!       die = lookup_type_die (TREE_TYPE (decl_or_origin));
!       if (!die)
! 	return;
!     }
    else
      die = NULL;
  
*************** process_scope_var (tree stmt, tree decl,
*** 21033,21039 ****
  					     stmt, context_die);
      }
    else
!     gen_decl_die (decl, origin, context_die);
  }
  
  /* Generate all of the decls declared within a given scope and (recursively)
--- 21166,21210 ----
  					     stmt, context_die);
      }
    else
!     {
!       if (decl && DECL_P (decl))
! 	die = lookup_decl_die (decl);
! 
!       if (in_lto_p
! 	  && die && die->die_parent != context_die)
! 	{
! 	  /* ???  For non-LTO operation we do not want to get here via
! 	     dwarf2out_abstract_function / set_decl_origin_self which
! 	     ends up modifying the tree rep in some odd way instead
! 	     of just playing with the DIEs.  */
! 	  /* We associate vars with their DECL_CONTEXT first which misses
! 	     their BLOCK association.  Move them.  */
! 	  gcc_assert (die->die_parent != NULL);
! 	  /* ???  Moving is expensive.  Better fix DECL_CONTEXT?  */
! 	  dw_die_ref prev = die->die_parent->die_child;
! 	  while (prev->die_sib != die)
! 	    prev = prev->die_sib;
! 	  remove_child_with_prev (die, prev);
! 	  add_child_die (context_die, die);
! 	}
! 
!       if (in_lto_p && decl
! 	  && TREE_CODE (decl) == VAR_DECL
! 	  && variably_modified_type_p (TREE_TYPE (decl),
! 				       cfun ? cfun->decl : NULL_TREE))
! 	{
! 	  /* We need to add location attributes to decls refered to
! 	     from the decls type but we don't have DIEs for the type
! 	     itself materialized.  The decls are also not part of the
! 	     functions BLOCK tree (because they are artificial).  */
! 	  walk_tree (&TREE_TYPE (decl), process_vla_type, NULL, NULL);
! 	}
! 
!       /* ???  The following gets stray type DIEs created even for decls
! 	 that were created early.  */
! 
!       gen_decl_die (decl, origin, context_die);
!     }
  }
  
  /* Generate all of the decls declared within a given scope and (recursively)
*************** gen_decl_die (tree decl, tree origin, dw
*** 21436,21441 ****
--- 21607,21615 ----
  
        /* If we're emitting an out-of-line copy of an inline function,
  	 emit info for the abstract instance and set up to refer to it.  */
+       /* ???  We have output an abstract instance early already and
+          could just re-use that.  This is how LTO treats all functions
+ 	 for example.  */
        else if (cgraph_function_possibly_inlined_p (decl)
  	       && ! DECL_ABSTRACT_P (decl)
  	       && ! class_or_namespace_scope_p (context_die)
*************** gen_decl_die (tree decl, tree origin, dw
*** 21449,21455 ****
  	}
  
        /* Otherwise we're emitting the primary DIE for this decl.  */
!       else if (debug_info_level > DINFO_LEVEL_TERSE)
  	{
  	  /* Before we describe the FUNCTION_DECL itself, make sure that we
  	     have its containing type.  */
--- 21623,21633 ----
  	}
  
        /* Otherwise we're emitting the primary DIE for this decl.  */
!       else if (debug_info_level > DINFO_LEVEL_TERSE
! 	       /* Do not generate stray type DIEs in late LTO dumping.  */
! 	       && !early_dwarf) /*(decl
! 		    && lookup_decl_die (decl)))
! 		    // && lookup_decl_die (decl)->dumped_early))*/
  	{
  	  /* Before we describe the FUNCTION_DECL itself, make sure that we
  	     have its containing type.  */
*************** gen_decl_die (tree decl, tree origin, dw
*** 21516,21521 ****
--- 21694,21705 ----
        if (debug_info_level <= DINFO_LEVEL_TERSE)
  	break;
  
+ 	{
+       /* ???  Avoid generating stray type DIEs during late LTO dwarf dumping.
+          All types have been dumped early.  */
+       dw_die_ref die = decl ? lookup_decl_die (decl) : NULL;
+       if (!die) // || !die->dumped_early)
+ 	{
        /* Output any DIEs that are needed to specify the type of this data
  	 object.  */
        if (decl_by_reference_p (decl_or_origin))
*************** gen_decl_die (tree decl, tree origin, dw
*** 21527,21532 ****
--- 21711,21718 ----
        class_origin = decl_class_context (decl_or_origin);
        if (class_origin != NULL_TREE)
  	gen_type_die_for_member (class_origin, decl_or_origin, context_die);
+ 	}
+ 	}
  
        /* And its containing namespace.  */
        context_die = declare_in_namespace (decl_or_origin, context_die);
*************** dwarf2out_early_global_decl (tree decl)
*** 21624,21629 ****
--- 21810,21825 ----
  	  if (!DECL_STRUCT_FUNCTION (decl))
  	    goto early_decl_exit;
  
+ 	  /* Emit an abstract origin of a function first.  This happens
+ 	     with C++ constructor clones for example and makes
+ 	     dwarf2out_abstract_function happy which requires the early
+ 	     DIE of the abstract instance to be present.  */
+ 	  if (DECL_ABSTRACT_ORIGIN (decl))
+ 	    {
+ 	      current_function_decl = DECL_ABSTRACT_ORIGIN (decl);
+ 	      dwarf2out_decl (DECL_ABSTRACT_ORIGIN (decl));
+ 	    }
+ 
  	  current_function_decl = decl;
  	}
        dwarf2out_decl (decl);
*************** dwarf2out_early_global_decl (tree decl)
*** 21640,21653 ****
  static void
  dwarf2out_late_global_decl (tree decl)
  {
!   /* Output any global decls we missed or fill-in any location
!      information we were unable to determine on the first pass.
! 
!      Skip over functions because they were handled by the
!      debug_hooks->function_decl() call in rest_of_handle_final.  */
!   if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
        && !POINTER_BOUNDS_P (decl))
!     dwarf2out_decl (decl);
  }
  
  /* Output debug information for type decl DECL.  Called from toplev.c
--- 21836,21851 ----
  static void
  dwarf2out_late_global_decl (tree decl)
  {
!   /* Fill-in any location information we were unable to determine
!      on the first pass.  */
!   if (TREE_CODE (decl) == VAR_DECL
        && !POINTER_BOUNDS_P (decl))
!     {
!       dw_die_ref die = lookup_decl_die (decl);
!       if (die)
! 	add_location_or_const_value_attribute (die, decl, false,
! 					       DW_AT_location);
!     }
  }
  
  /* Output debug information for type decl DECL.  Called from toplev.c
*************** dwarf2out_decl (tree decl)
*** 21962,21998 ****
  static void
  dwarf2out_function_decl (tree decl)
  {
!   dwarf2out_decl (decl);
!   call_arg_locations = NULL;
!   call_arg_loc_last = NULL;
!   call_site_count = -1;
!   tail_call_site_count = -1;
!   decl_loc_table->empty ();
!   cached_dw_loc_list_table->empty ();
! }
  
! /* Output a marker (i.e. a label) for the beginning of the generated code for
!    a lexical block.  */
  
! static void
! dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
! 		       unsigned int blocknum)
! {
!   switch_to_section (current_function_section ());
!   ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
! }
  
! /* Output a marker (i.e. a label) for the end of the generated code for a
!    lexical block.  */
  
! static void
! dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
! {
!   switch_to_section (current_function_section ());
!   ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
! }
  
! /* Returns nonzero if it is appropriate not to emit any debugging
     information for BLOCK, because it doesn't contain any instructions.
  
     Don't allow this for blocks with nested functions or local classes
--- 22160,22763 ----
  static void
  dwarf2out_function_decl (tree decl)
  {
!   dw_die_ref context_die = comp_unit_die ();
  
!   /* If we're a nested function, initially use a parent of NULL; if we're
!      a plain function, this will be fixed up in decls_for_scope.  If
!      we're a method, it will be ignored, since we already have a DIE.  */
!   if (decl_function_context (decl)
!       /* But if we're in terse mode, we don't care about scope.  */
!       && debug_info_level > DINFO_LEVEL_TERSE)
!     context_die = NULL;
  
!   if (DECL_IGNORED_P (decl))
!     return;
  
!   /* ???  Use the early die and check for DW_AT_inline.  */
!   bool inlined_instance_p = false;
!   if (DECL_ORIGIN (decl) == decl
!       && cgraph_function_possibly_inlined_p (decl))
!     {
!       set_decl_origin_self (decl);
!       inlined_instance_p = true;
!     }
  
!   /* ???  context_die shouldn't really matter, if then take it from
!      the early DIE.  */
! #if 0
!   gen_subprogram_die (decl, context_die);
  
! #else
!   /* The following is gen_subprogram_die refactored so it only contains
!      the "late" phase.
!      ???  Well, mostly.  */
! 
!   dw_die_ref old_die = lookup_decl_die (decl);
! 
!   /* An inlined instance, tag a new DIE with DW_AT_abstract_origin.  */
!   dw_die_ref subr_die;
!   if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE)
!     {
!       /* Fixup die_parent for the abstract instance of a nested
! 	 inline function.  */
!       /* ???  necessary?  */
!       if (old_die && old_die->die_parent == NULL)
! 	add_child_die (context_die, old_die);
! 
!       if (! inlined_instance_p && old_die)
! 	{
! 	  /* If we have a DW_AT_abstract_origin we have a working
! 	     cached version.  */
! 	  subr_die = old_die;
! 	}
!       else
! 	{
! 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
! 	  add_abstract_origin_attribute (subr_die, DECL_ORIGIN (decl));
! 	  /*  This is where the actual code for a cloned function is.
! 	      Let's emit linkage name attribute for it.  This helps
! 	      debuggers to e.g, set breakpoints into
! 	      constructors/destructors when the user asks "break
! 	      K::K".  */
! 	  add_linkage_name (subr_die, decl);
! 	}
!     }
!   else
!     {
!       /* ???  Prune the following bits.  */
!       /* If the definition comes from the same place as the declaration,
! 	 maybe use the old DIE.  We always want the DIE for this function
! 	 that has the *_pc attributes to be under comp_unit_die so the
! 	 debugger can find it.  We also need to do this for abstract
! 	 instances of inlines, since the spec requires the out-of-line copy
! 	 to have the same parent.  For local class methods, this doesn't
! 	 apply; we just use the old DIE.  */
!       expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
!       struct dwarf_file_data * file_index = lookup_filename (s.file);
!       if ((is_cu_die (old_die->die_parent)
! 	   /* This condition fixes the inconsistency/ICE with the
! 	      following Fortran test (or some derivative thereof) while
! 	      building libgfortran:
! 
! 		 module some_m
! 		 contains
! 		    logical function funky (FLAG)
! 		      funky = .true.
! 		   end function
! 		 end module
! 	   */
! 	   || (old_die->die_parent
! 	       && old_die->die_parent->die_tag == DW_TAG_module)
! 	   || context_die == NULL)
! 	   && ((DECL_ARTIFICIAL (decl) || in_lto_p)
! 	       || (get_AT_file (old_die, DW_AT_decl_file) == file_index
! 		   && (get_AT_unsigned (old_die, DW_AT_decl_line)
! 		       == (unsigned) s.line))))
! 	{
! 	  subr_die = old_die;
! 
! 	  /* Clear out the declaration attribute, but leave the
! 	     parameters so they can be augmented with location
! 	     information later.  Unless this was a declaration, in
! 	     which case, wipe out the nameless parameters and recreate
! 	     them further down.  */
! 	  if (remove_AT (subr_die, DW_AT_declaration))
! 	    {
! 
! 	      remove_AT (subr_die, DW_AT_object_pointer);
! 	      remove_child_TAG (subr_die, DW_TAG_formal_parameter);
! 	    }
! 	}
!       /* Make a specification pointing to the previously built
! 	 declaration.  */
!       else
! 	{
! 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
! 	  add_AT_specification (subr_die, old_die);
!           add_pubname (decl, subr_die);
! 	  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);
! 
! 	  /* If the prototype had an 'auto' or 'decltype(auto)' return type,
! 	     emit the real type on the definition die.  */
! 	  if (is_cxx() && debug_info_level > DINFO_LEVEL_TERSE)
! 	    {
! 	      dw_die_ref die = get_AT_ref (old_die, DW_AT_type);
! 	      if (die == auto_die || die == decltype_auto_die)
! 		add_type_attribute (subr_die, TREE_TYPE (TREE_TYPE (decl)),
! 				    TYPE_UNQUALIFIED, context_die);
! 	    }
! 	}
!     }
! 
!   /* Unless we have an existing non-declaration DIE, equate the new
!      DIE.  */
!   /* ???  The is_declaration_die check doesn't work in_lto_p.
!      We rather always want to equate if we generated a new DIE(?!).  */
!   if (!old_die || is_declaration_die (old_die))
!     equate_decl_number_to_die (decl, subr_die);
! 
!   /* For non DECL_EXTERNALs, if range information is available, fill
!      the DIE with it.  */
!     {
!       HOST_WIDE_INT cfa_fb_offset;
! 
!       struct function *fun = DECL_STRUCT_FUNCTION (decl);
! 
!       if (!flag_reorder_blocks_and_partition)
! 	{
! 	  dw_fde_ref fde = fun->fde;
! 	  if (fde->dw_fde_begin)
! 	    {
! 	      /* We have already generated the labels.  */
!              add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
!                                  fde->dw_fde_end, false);
! 	    }
! 	  else
! 	    {
! 	      /* Create start/end labels and add the range.  */
! 	      char label_id_low[MAX_ARTIFICIAL_LABEL_BYTES];
! 	      char label_id_high[MAX_ARTIFICIAL_LABEL_BYTES];
! 	      ASM_GENERATE_INTERNAL_LABEL (label_id_low, FUNC_BEGIN_LABEL,
! 					   current_function_funcdef_no);
! 	      ASM_GENERATE_INTERNAL_LABEL (label_id_high, FUNC_END_LABEL,
! 					   current_function_funcdef_no);
!              add_AT_low_high_pc (subr_die, label_id_low, label_id_high,
!                                  false);
! 	    }
! 
! #if VMS_DEBUGGING_INFO
!       /* HP OpenVMS Industry Standard 64: DWARF Extensions
! 	 Section 2.3 Prologue and Epilogue Attributes:
! 	 When a breakpoint is set on entry to a function, it is generally
! 	 desirable for execution to be suspended, not on the very first
! 	 instruction of the function, but rather at a point after the
! 	 function's frame has been set up, after any language defined local
! 	 declaration processing has been completed, and before execution of
! 	 the first statement of the function begins. Debuggers generally
! 	 cannot properly determine where this point is.  Similarly for a
! 	 breakpoint set on exit from a function. The prologue and epilogue
! 	 attributes allow a compiler to communicate the location(s) to use.  */
! 
!       {
!         if (fde->dw_fde_vms_end_prologue)
!           add_AT_vms_delta (subr_die, DW_AT_HP_prologue,
! 	    fde->dw_fde_begin, fde->dw_fde_vms_end_prologue);
! 
!         if (fde->dw_fde_vms_begin_epilogue)
!           add_AT_vms_delta (subr_die, DW_AT_HP_epilogue,
! 	    fde->dw_fde_begin, fde->dw_fde_vms_begin_epilogue);
!       }
! #endif
! 
! 	}
!       else
! 	{
! 	  /* Generate pubnames entries for the split function code ranges.  */
! 	  dw_fde_ref fde = fun->fde;
! 
! 	  if (fde->dw_fde_second_begin)
! 	    {
! 	      if (dwarf_version >= 3 || !dwarf_strict)
! 		{
! 		  /* We should use ranges for non-contiguous code section
! 		     addresses.  Use the actual code range for the initial
! 		     section, since the HOT/COLD labels might precede an
! 		     alignment offset.  */
! 		  bool range_list_added = false;
! 		  add_ranges_by_labels (subr_die, fde->dw_fde_begin,
!                                         fde->dw_fde_end, &range_list_added,
!                                         false);
! 		  add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
! 					fde->dw_fde_second_end,
!                                        &range_list_added, false);
! 		  if (range_list_added)
! 		    add_ranges (NULL);
! 		}
! 	      else
! 		{
! 		  /* There is no real support in DW2 for this .. so we make
! 		     a work-around.  First, emit the pub name for the segment
! 		     containing the function label.  Then make and emit a
! 		     simplified subprogram DIE for the second segment with the
! 		     name pre-fixed by __hot/cold_sect_of_.  We use the same
! 		     linkage name for the second die so that gdb will find both
! 		     sections when given "b foo".  */
! 		  const char *name = NULL;
! 		  tree decl_name = DECL_NAME (decl);
! 		  dw_die_ref seg_die;
! 
! 		  /* Do the 'primary' section.   */
! 		  add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
!                                       fde->dw_fde_end, false);
! 
! 		  /* Build a minimal DIE for the secondary section.  */
! 		  seg_die = new_die (DW_TAG_subprogram,
! 				     subr_die->die_parent, decl);
! 
! 		  if (TREE_PUBLIC (decl))
! 		    add_AT_flag (seg_die, DW_AT_external, 1);
! 
! 		  if (decl_name != NULL
! 		      && IDENTIFIER_POINTER (decl_name) != NULL)
! 		    {
! 		      name = dwarf2_name (decl, 1);
! 		      if (! DECL_ARTIFICIAL (decl))
! 			add_src_coords_attributes (seg_die, decl);
! 
! 		      add_linkage_name (seg_die, decl);
! 		    }
! 		  gcc_assert (name != NULL);
! 		  add_pure_or_virtual_attribute (seg_die, decl);
! 		  if (DECL_ARTIFICIAL (decl))
! 		    add_AT_flag (seg_die, DW_AT_artificial, 1);
! 
! 		  name = concat ("__second_sect_of_", name, NULL);
! 		  add_AT_low_high_pc (seg_die, fde->dw_fde_second_begin,
!                                       fde->dw_fde_second_end, false);
! 		  add_name_attribute (seg_die, name);
! 		  if (want_pubnames ())
! 		    add_pubname_string (name, seg_die);
! 		}
! 	    }
! 	  else
!            add_AT_low_high_pc (subr_die, fde->dw_fde_begin, fde->dw_fde_end,
!                                false);
! 	}
! 
!       cfa_fb_offset = CFA_FRAME_BASE_OFFSET (decl);
! 
!       /* We define the "frame base" as the function's CFA.  This is more
! 	 convenient for several reasons: (1) It's stable across the prologue
! 	 and epilogue, which makes it better than just a frame pointer,
! 	 (2) With dwarf3, there exists a one-byte encoding that allows us
! 	 to reference the .debug_frame data by proxy, but failing that,
! 	 (3) We can at least reuse the code inspection and interpretation
! 	 code that determines the CFA position at various points in the
! 	 function.  */
!       if (dwarf_version >= 3 && targetm.debug_unwind_info () == UI_DWARF2)
! 	{
! 	  dw_loc_descr_ref op = new_loc_descr (DW_OP_call_frame_cfa, 0, 0);
! 	  add_AT_loc (subr_die, DW_AT_frame_base, op);
! 	}
!       else
! 	{
! 	  dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset);
! 	  if (list->dw_loc_next)
! 	    add_AT_loc_list (subr_die, DW_AT_frame_base, list);
! 	  else
! 	    add_AT_loc (subr_die, DW_AT_frame_base, list->expr);
! 	}
! 
!       /* 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 latter 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);
! 
!       if (fun->static_chain_decl)
! 	add_AT_location_description
! 	  (subr_die, DW_AT_static_link,
! 	   loc_list_from_tree (fun->static_chain_decl, 2, NULL));
!     }
! 
!   /* Now output descriptions of the arguments for this function. This gets
!      (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
!      for a FUNCTION_DECL doesn't indicate cases where there was a trailing
!      `...' at the end of the formal parameter list.  In order to find out if
!      there was a trailing ellipsis or not, we must instead look at the type
!      associated with the FUNCTION_DECL.  This will be a node of type
!      FUNCTION_TYPE. If the chain of type nodes hanging off of this
!      FUNCTION_TYPE node ends with a void_type_node then there should *not* be
!      an ellipsis at the end.  */
! 
!   if (debug_info_level <= DINFO_LEVEL_TERSE)
!     ;
!   else
!     {
!       /* ???  Prune for late phase.  */
!       /* Generate DIEs to represent all known formal parameters.  */
!       tree parm = DECL_ARGUMENTS (decl);
!       tree generic_decl = early_dwarf
! 	? lang_hooks.decls.get_generic_function_decl (decl) : NULL;
!       tree generic_decl_parm = generic_decl
! 				? DECL_ARGUMENTS (generic_decl)
! 				: NULL;
! 
!       /* Now we want to walk the list of parameters of the function and
! 	 emit their relevant DIEs.
! 
! 	 We consider the case of DECL being an instance of a generic function
! 	 as well as it being a normal function.
! 
! 	 If DECL is an instance of a generic function we walk the
! 	 parameters of the generic function declaration _and_ the parameters of
! 	 DECL itself. This is useful because we want to emit specific DIEs for
! 	 function parameter packs and those are declared as part of the
! 	 generic function declaration. In that particular case,
! 	 the parameter pack yields a DW_TAG_GNU_formal_parameter_pack DIE.
! 	 That DIE has children DIEs representing the set of arguments
! 	 of the pack. Note that the set of pack arguments can be empty.
! 	 In that case, the DW_TAG_GNU_formal_parameter_pack DIE will not have any
! 	 children DIE.
! 
! 	 Otherwise, we just consider the parameters of DECL.  */
!       while (generic_decl_parm || parm)
! 	{
! 	  if (generic_decl_parm
! 	      && lang_hooks.function_parameter_pack_p (generic_decl_parm))
! 	    gen_formal_parameter_pack_die (generic_decl_parm,
! 					   parm, subr_die,
! 					   &parm);
! 	  else if (parm && !POINTER_BOUNDS_P (parm))
! 	    {
! 	      dw_die_ref parm_die = gen_decl_die (parm, NULL, subr_die);
! 
! 	      if (parm == DECL_ARGUMENTS (decl)
! 		  && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
! 		  && parm_die
! 		  && (dwarf_version >= 3 || !dwarf_strict))
! 		add_AT_die_ref (subr_die, DW_AT_object_pointer, parm_die);
! 
! 	      parm = DECL_CHAIN (parm);
! 	    }
! 	  else if (parm)
! 	    parm = DECL_CHAIN (parm);
! 
! 	  if (generic_decl_parm)
! 	    generic_decl_parm = DECL_CHAIN (generic_decl_parm);
! 	}
! 
!       /* Decide whether we need an unspecified_parameters DIE at the end.
! 	 There are 2 more cases to do this for: 1) the ansi ... declaration -
! 	 this is detectable when the end of the arg list is not a
! 	 void_type_node 2) an unprototyped function declaration (not a
! 	 definition).  This just means that we have no info about the
! 	 parameters at all.  */
!       if (prototype_p (TREE_TYPE (decl)))
! 	{
! 	  /* This is the prototyped case, check for....  */
! 	  if (stdarg_p (TREE_TYPE (decl)))
! 	    gen_unspecified_parameters_die (decl, subr_die);
! 	}
!       else if (DECL_INITIAL (decl) == NULL_TREE)
! 	gen_unspecified_parameters_die (decl, subr_die);
!     }
! 
!   if (subr_die != old_die)
!     /* Add the calling convention attribute if requested.  */
!     add_calling_convention_attribute (subr_die, decl);
! 
!   /* Output Dwarf info for all of the stuff within the body of the function
!      (if it has one - it may be just a declaration).
! 
!      OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
!      a function.  This BLOCK actually represents the outermost binding contour
!      for the function, i.e. the contour in which the function's formal
!      parameters and labels get declared. Curiously, it appears that the front
!      end doesn't actually put the PARM_DECL nodes for the current function onto
!      the BLOCK_VARS list for this outer scope, but are strung off of the
!      DECL_ARGUMENTS list for the function instead.
! 
!      The BLOCK_VARS list for the `outer_scope' does provide us with a list of
!      the LABEL_DECL nodes for the function however, and we output DWARF info
!      for those in decls_for_scope.  Just within the `outer_scope' there will be
!      a BLOCK node representing the function's outermost pair of curly braces,
!      and any blocks used for the base and member initializers of a C++
!      constructor function.  */
!     {
!       /* ???  Prune this for late phase.  */
!       /* Emit a DW_TAG_variable DIE for a named return value.  */
!       if (DECL_NAME (DECL_RESULT (decl)))
! 	gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
! 
!       /* The first time through decls_for_scope we will generate the
! 	 DIEs for the locals.  The second time, we fill in the
! 	 location info.  */
!       decls_for_scope (DECL_INITIAL (decl), subr_die);
!     }
! #endif
! 
!   int call_site_note_count = 0;
!   int tail_call_site_note_count = 0;
!   if (call_arg_locations && !dwarf_strict)
!     {
!       struct call_arg_loc_node *ca_loc;
!       for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
! 	{
! 	  dw_die_ref die = NULL;
! 	  rtx tloc = NULL_RTX, tlocc = NULL_RTX;
! 	  rtx arg, next_arg;
! 
! 	  for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
! 	       arg; arg = next_arg)
! 	    {
! 	      dw_loc_descr_ref reg, val;
! 	      machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
! 	      dw_die_ref cdie, tdie = NULL;
! 
! 	      next_arg = XEXP (arg, 1);
! 	      if (REG_P (XEXP (XEXP (arg, 0), 0))
! 		  && next_arg
! 		  && MEM_P (XEXP (XEXP (next_arg, 0), 0))
! 		  && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))
! 		  && REGNO (XEXP (XEXP (arg, 0), 0))
! 		  == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)))
! 		next_arg = XEXP (next_arg, 1);
! 	      if (mode == VOIDmode)
! 		{
! 		  mode = GET_MODE (XEXP (XEXP (arg, 0), 0));
! 		  if (mode == VOIDmode)
! 		    mode = GET_MODE (XEXP (arg, 0));
! 		}
! 	      if (mode == VOIDmode || mode == BLKmode)
! 		continue;
! 	      if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
! 		{
! 		  gcc_assert (ca_loc->symbol_ref == NULL_RTX);
! 		  tloc = XEXP (XEXP (arg, 0), 1);
! 		  continue;
! 		}
! 	      else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
! 		       && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
! 		{
! 		  gcc_assert (ca_loc->symbol_ref == NULL_RTX);
! 		  tlocc = XEXP (XEXP (arg, 0), 1);
! 		  continue;
! 		}
! 	      reg = NULL;
! 	      if (REG_P (XEXP (XEXP (arg, 0), 0)))
! 		reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
! 					  VAR_INIT_STATUS_INITIALIZED);
! 	      else if (MEM_P (XEXP (XEXP (arg, 0), 0)))
! 		{
! 		  rtx mem = XEXP (XEXP (arg, 0), 0);
! 		  reg = mem_loc_descriptor (XEXP (mem, 0),
! 					    get_address_mode (mem),
! 					    GET_MODE (mem),
! 					    VAR_INIT_STATUS_INITIALIZED);
! 		}
! 	      else if (GET_CODE (XEXP (XEXP (arg, 0), 0))
! 		       == DEBUG_PARAMETER_REF)
! 		{
! 		  tree tdecl
! 		      = DEBUG_PARAMETER_REF_DECL (XEXP (XEXP (arg, 0), 0));
! 		  tdie = lookup_decl_die (tdecl);
! 		  if (tdie == NULL)
! 		    continue;
! 		}
! 	      else
! 		continue;
! 	      if (reg == NULL
! 		  && GET_CODE (XEXP (XEXP (arg, 0), 0))
! 		  != DEBUG_PARAMETER_REF)
! 		continue;
! 	      val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode,
! 					VOIDmode,
! 					VAR_INIT_STATUS_INITIALIZED);
! 	      if (val == NULL)
! 		continue;
! 	      if (die == NULL)
! 		die = gen_call_site_die (decl, subr_die, ca_loc);
! 	      cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
! 			      NULL_TREE);
! 	      if (reg != NULL)
! 		add_AT_loc (cdie, DW_AT_location, reg);
! 	      else if (tdie != NULL)
! 		add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie);
! 	      add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
! 	      if (next_arg != XEXP (arg, 1))
! 		{
! 		  mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 1));
! 		  if (mode == VOIDmode)
! 		    mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 0));
! 		  val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1),
! 							0), 1),
! 					    mode, VOIDmode,
! 					    VAR_INIT_STATUS_INITIALIZED);
! 		  if (val != NULL)
! 		    add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
! 		}
! 	    }
! 	  if (die == NULL
! 	      && (ca_loc->symbol_ref || tloc))
! 	    die = gen_call_site_die (decl, subr_die, ca_loc);
! 	  if (die != NULL && (tloc != NULL_RTX || tlocc != NULL_RTX))
! 	    {
! 	      dw_loc_descr_ref tval = NULL;
! 
! 	      if (tloc != NULL_RTX)
! 		tval = mem_loc_descriptor (tloc,
! 					   GET_MODE (tloc) == VOIDmode
! 					   ? Pmode : GET_MODE (tloc),
! 					   VOIDmode,
! 					   VAR_INIT_STATUS_INITIALIZED);
! 	      if (tval)
! 		add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
! 	      else if (tlocc != NULL_RTX)
! 		{
! 		  tval = mem_loc_descriptor (tlocc,
! 					     GET_MODE (tlocc) == VOIDmode
! 					     ? Pmode : GET_MODE (tlocc),
! 					     VOIDmode,
! 					     VAR_INIT_STATUS_INITIALIZED);
! 		  if (tval)
! 		    add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered,
! 				tval);
! 		}
! 	    }
! 	  if (die != NULL)
! 	    {
! 	      call_site_note_count++;
! 	      if (ca_loc->tail_call_p)
! 		tail_call_site_note_count++;
! 	    }
! 	}
!     }
!   call_arg_locations = NULL;
!   call_arg_loc_last = NULL;
!   if (tail_call_site_count >= 0
!       && tail_call_site_count == tail_call_site_note_count
!       && !dwarf_strict)
!     {
!       if (call_site_count >= 0
! 	  && call_site_count == call_site_note_count)
! 	add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
!       else
! 	add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
!     }
!   call_site_count = -1;
!   tail_call_site_count = -1;
! 
!   decl_loc_table->empty ();
!   cached_dw_loc_list_table->empty ();
! }
! 
! /* Output a marker (i.e. a label) for the beginning of the generated code for
!    a lexical block.  */
! 
! static void
! dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
! 		       unsigned int blocknum)
! {
!   switch_to_section (current_function_section ());
!   ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
! }
! 
! /* Output a marker (i.e. a label) for the end of the generated code for a
!    lexical block.  */
! 
! static void
! dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
! {
!   switch_to_section (current_function_section ());
!   ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
! }
! 
! /* Returns nonzero if it is appropriate not to emit any debugging
     information for BLOCK, because it doesn't contain any instructions.
  
     Don't allow this for blocks with nested functions or local classes
*************** append_entry_to_tmpl_value_parm_die_tabl
*** 22105,22110 ****
--- 22870,22877 ----
    if (!die || !arg)
      return;
  
+   gcc_assert (early_dwarf);
+ 
    if (!tmpl_value_parm_die_table)
      vec_alloc (tmpl_value_parm_die_table, 32);
  
*************** schedule_generic_params_dies_gen (tree t
*** 22134,22139 ****
--- 22901,22908 ----
    if (!generic_type_p (t))
      return;
  
+   gcc_assert (early_dwarf);
+ 
    if (!generic_type_instances)
      vec_alloc (generic_type_instances, 256);
  
*************** gen_remaining_tmpl_value_param_die_attri
*** 22149,22159 ****
  {
    if (tmpl_value_parm_die_table)
      {
!       unsigned i;
        die_arg_entry *e;
  
        FOR_EACH_VEC_ELT (*tmpl_value_parm_die_table, i, e)
! 	tree_add_const_value_attribute (e->die, e->arg);
      }
  }
  
--- 22918,22938 ----
  {
    if (tmpl_value_parm_die_table)
      {
!       unsigned i, j;
        die_arg_entry *e;
  
+       /* We do this in two phases - first get the cases we can
+ 	 handle during early-finish, preserving those we cannot
+ 	 (containing symbolic constants where we don't yet know
+ 	 whether we are going to output the referenced symbols).
+ 	 For those we try again at late-finish.  */
+       j = 0;
        FOR_EACH_VEC_ELT (*tmpl_value_parm_die_table, i, e)
! 	{
! 	  if (!tree_add_const_value_attribute (e->die, e->arg))
! 	    (*tmpl_value_parm_die_table)[j++] = *e;
! 	}
!       tmpl_value_parm_die_table->truncate (j);
      }
  }
  
*************** gen_scheduled_generic_parms_dies (void)
*** 22171,22179 ****
--- 22950,22964 ----
    if (!generic_type_instances)
      return;
    
+   /* We end up "recursing" into schedule_generic_params_dies_gen, so
+      pretend this generation is part of "early dwarf" as well.  */
+   set_early_dwarf s;
+ 
    FOR_EACH_VEC_ELT (*generic_type_instances, i, t)
      if (COMPLETE_TYPE_P (t))
        gen_generic_params_dies (t);
+ 
+   generic_type_instances = NULL;
  }
  
  
*************** output_macinfo (void)
*** 23203,23276 ****
        }
  }
  
! /* Set up for Dwarf output at the start of compilation.  */
  
! static void
! dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
  {
!   /* This option is currently broken, see (PR53118 and PR46102).  */
!   if (flag_eliminate_dwarf2_dups
!       && strstr (lang_hooks.name, "C++"))
!     {
!       warning (0, "-feliminate-dwarf2-dups is broken for C++, ignoring");
!       flag_eliminate_dwarf2_dups = 0;
!     }
! 
!   /* Allocate the file_table.  */
!   file_table = hash_table<dwarf_file_hasher>::create_ggc (50);
! 
! #ifndef DWARF2_LINENO_DEBUGGING_INFO
!   /* Allocate the decl_die_table.  */
!   decl_die_table = hash_table<decl_die_hasher>::create_ggc (10);
! 
!   /* Allocate the decl_loc_table.  */
!   decl_loc_table = hash_table<decl_loc_hasher>::create_ggc (10);
! 
!   /* Allocate the cached_dw_loc_list_table.  */
!   cached_dw_loc_list_table = hash_table<dw_loc_list_hasher>::create_ggc (10);
! 
!   /* Allocate the initial hunk of the decl_scope_table.  */
!   vec_alloc (decl_scope_table, 256);
! 
!   /* Allocate the initial hunk of the abbrev_die_table.  */
!   abbrev_die_table = ggc_cleared_vec_alloc<dw_die_ref>
!     (ABBREV_DIE_TABLE_INCREMENT);
!   abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
!   /* Zero-th entry is allocated, but unused.  */
!   abbrev_die_table_in_use = 1;
! 
!   /* Allocate the pubtypes and pubnames vectors.  */
!   vec_alloc (pubname_table, 32);
!   vec_alloc (pubtype_table, 32);
  
!   vec_alloc (incomplete_types, 64);
  
!   vec_alloc (used_rtx_array, 32);
  
    if (!dwarf_split_debug_info)
      {
!       debug_info_section = get_section (DEBUG_INFO_SECTION,
                                          SECTION_DEBUG, NULL);
!       debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
                                            SECTION_DEBUG, NULL);
!       debug_loc_section = get_section (DEBUG_LOC_SECTION,
                                         SECTION_DEBUG, NULL);
      }
    else
      {
!       debug_info_section = get_section (DEBUG_DWO_INFO_SECTION,
                                          SECTION_DEBUG | SECTION_EXCLUDE, NULL);
!       debug_abbrev_section = get_section (DEBUG_DWO_ABBREV_SECTION,
                                            SECTION_DEBUG | SECTION_EXCLUDE,
                                            NULL);
!       debug_addr_section = get_section (DEBUG_ADDR_SECTION,
                                          SECTION_DEBUG, NULL);
!       debug_skeleton_info_section = get_section (DEBUG_INFO_SECTION,
                                                   SECTION_DEBUG, NULL);
!       debug_skeleton_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
                                                     SECTION_DEBUG, NULL);
        ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
!                                   DEBUG_SKELETON_ABBREV_SECTION_LABEL, 0);
  
        /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
           the main .o, but the skeleton_line goes into the split off dwo.  */
--- 23988,24057 ----
        }
  }
  
! /* Return NAME prefixed with PREFIX if non-NULL in a buffer that is
!    valid until the next call to temp_prefixed_name.  */
  
! static const char *
! temp_prefixed_name (const char *prefix, const char *name, const char *postfix)
  {
!   static char buffer[1024];
!   if (!prefix && !postfix)
!     return name;
!   snprintf (buffer, 1024, "%s%s%s",
! 	    prefix ? prefix : "", name, postfix ? postfix : "");
!   return buffer;
! }
  
! /* Initialize the various sections and labels for dwarf output and prefix
!    them with PREFIX if non-NULL.  */
  
! static void
! init_sections_and_labels (const char *prefix, const char *postfix)
! {
!   static unsigned generation = 0;
  
    if (!dwarf_split_debug_info)
      {
!       debug_info_section = get_section (temp_prefixed_name
! 					  (prefix, DEBUG_INFO_SECTION,
! 					   postfix),
                                          SECTION_DEBUG, NULL);
!       debug_abbrev_section = get_section (temp_prefixed_name
! 					    (prefix, DEBUG_ABBREV_SECTION,
! 					     postfix),
                                            SECTION_DEBUG, NULL);
!       debug_loc_section = get_section (temp_prefixed_name
! 				         (prefix, DEBUG_LOC_SECTION,
! 					  postfix),
                                         SECTION_DEBUG, NULL);
      }
    else
      {
!       debug_info_section = get_section (temp_prefixed_name
! 					  (prefix, DEBUG_DWO_INFO_SECTION,
! 					   postfix),
                                          SECTION_DEBUG | SECTION_EXCLUDE, NULL);
!       debug_abbrev_section = get_section (temp_prefixed_name
! 					    (prefix, DEBUG_DWO_ABBREV_SECTION,
! 					     postfix),
                                            SECTION_DEBUG | SECTION_EXCLUDE,
                                            NULL);
!       debug_addr_section = get_section (temp_prefixed_name
! 					  (prefix, DEBUG_ADDR_SECTION,
! 					   postfix),
                                          SECTION_DEBUG, NULL);
!       debug_skeleton_info_section = get_section (temp_prefixed_name
! 						   (prefix, DEBUG_INFO_SECTION,
! 						    postfix),
                                                   SECTION_DEBUG, NULL);
!       debug_skeleton_abbrev_section = get_section (temp_prefixed_name
! 						     (prefix,
! 						      DEBUG_ABBREV_SECTION,
! 						      postfix),
                                                     SECTION_DEBUG, NULL);
        ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
!                                   DEBUG_SKELETON_ABBREV_SECTION_LABEL,
! 				  generation);
  
        /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
           the main .o, but the skeleton_line goes into the split off dwo.  */
*************** dwarf2out_init (const char *filename ATT
*** 23278,23334 ****
            = get_section (DEBUG_DWO_LINE_SECTION,
                           SECTION_DEBUG | SECTION_EXCLUDE, NULL);
        ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
!                                    DEBUG_SKELETON_LINE_SECTION_LABEL, 0);
        debug_str_offsets_section = get_section (DEBUG_STR_OFFSETS_SECTION,
                                                 SECTION_DEBUG | SECTION_EXCLUDE,
                                                 NULL);
        ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
!                                    DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
        debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
                                         SECTION_DEBUG | SECTION_EXCLUDE, NULL);
        debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
                                             DEBUG_STR_DWO_SECTION_FLAGS, NULL);
      }
!   debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
  				       SECTION_DEBUG, NULL);
!   debug_macinfo_section = get_section (dwarf_strict
! 				       ? DEBUG_MACINFO_SECTION
! 				       : DEBUG_MACRO_SECTION,
                                         DEBUG_MACRO_SECTION_FLAGS, NULL);
!   debug_line_section = get_section (DEBUG_LINE_SECTION,
  				    SECTION_DEBUG, NULL);
!   debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION,
  					SECTION_DEBUG, NULL);
!   debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION,
  					SECTION_DEBUG, NULL);
!   debug_str_section = get_section (DEBUG_STR_SECTION,
  				   DEBUG_STR_SECTION_FLAGS, NULL);
!   debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
  				      SECTION_DEBUG, NULL);
!   debug_frame_section = get_section (DEBUG_FRAME_SECTION,
  				     SECTION_DEBUG, NULL);
  
-   ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
    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,
! 			       COLD_TEXT_SECTION_LABEL, 0);
!   ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
! 
    ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
! 			       DEBUG_INFO_SECTION_LABEL, 0);
    ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
! 			       DEBUG_LINE_SECTION_LABEL, 0);
    ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
! 			       DEBUG_RANGES_SECTION_LABEL, 0);
    ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
!                                DEBUG_ADDR_SECTION_LABEL, 0);
    ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
  			       dwarf_strict
  			       ? DEBUG_MACINFO_SECTION_LABEL
! 			       : DEBUG_MACRO_SECTION_LABEL, 0);
!   ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
  
    if (debug_info_level >= DINFO_LEVEL_VERBOSE)
      vec_alloc (macinfo_table, 64);
--- 24059,24181 ----
            = get_section (DEBUG_DWO_LINE_SECTION,
                           SECTION_DEBUG | SECTION_EXCLUDE, NULL);
        ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_line_section_label,
!                                    DEBUG_SKELETON_LINE_SECTION_LABEL,
! 				   generation);
        debug_str_offsets_section = get_section (DEBUG_STR_OFFSETS_SECTION,
                                                 SECTION_DEBUG | SECTION_EXCLUDE,
                                                 NULL);
        ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
!                                    DEBUG_SKELETON_INFO_SECTION_LABEL,
! 				   generation);
        debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
                                         SECTION_DEBUG | SECTION_EXCLUDE, NULL);
        debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
                                             DEBUG_STR_DWO_SECTION_FLAGS, NULL);
      }
!   debug_aranges_section = get_section (temp_prefixed_name
! 				         (prefix, DEBUG_ARANGES_SECTION,
! 					  postfix),
  				       SECTION_DEBUG, NULL);
!   debug_macinfo_section = get_section (temp_prefixed_name
! 				         (prefix,
! 					  dwarf_strict
! 					  ? DEBUG_MACINFO_SECTION
! 					  : DEBUG_MACRO_SECTION,
! 					  postfix),
                                         DEBUG_MACRO_SECTION_FLAGS, NULL);
!   debug_line_section = get_section (temp_prefixed_name
! 				      (prefix, DEBUG_LINE_SECTION, postfix),
  				    SECTION_DEBUG, NULL);
!   debug_pubnames_section = get_section (temp_prefixed_name
! 					  (prefix, DEBUG_PUBNAMES_SECTION,
! 					   postfix),
  					SECTION_DEBUG, NULL);
!   debug_pubtypes_section = get_section (temp_prefixed_name
! 					  (prefix, DEBUG_PUBTYPES_SECTION,
! 					   postfix),
  					SECTION_DEBUG, NULL);
!   debug_str_section = get_section (temp_prefixed_name
! 				     (prefix, DEBUG_STR_SECTION, postfix),
  				   DEBUG_STR_SECTION_FLAGS, NULL);
!   debug_ranges_section = get_section (temp_prefixed_name
! 				        (prefix, DEBUG_RANGES_SECTION, postfix),
  				      SECTION_DEBUG, NULL);
!   debug_frame_section = get_section (temp_prefixed_name
! 				       (prefix, DEBUG_FRAME_SECTION, postfix),
  				     SECTION_DEBUG, NULL);
  
    ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
! 			       DEBUG_ABBREV_SECTION_LABEL, generation);
    ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
! 			       DEBUG_INFO_SECTION_LABEL, generation);
    ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
! 			       DEBUG_LINE_SECTION_LABEL, generation);
    ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
! 			       DEBUG_RANGES_SECTION_LABEL, generation);
    ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
!                                DEBUG_ADDR_SECTION_LABEL, generation);
    ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
  			       dwarf_strict
  			       ? DEBUG_MACINFO_SECTION_LABEL
! 			       : DEBUG_MACRO_SECTION_LABEL, generation);
!   ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL,
! 			       generation);
! 
!   ++generation;
! }
! 
! /* Set up for Dwarf output at the start of compilation.  */
! 
! static void
! dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
! {
!   /* This option is currently broken, see (PR53118 and PR46102).  */
!   if (flag_eliminate_dwarf2_dups
!       && strstr (lang_hooks.name, "C++"))
!     {
!       warning (0, "-feliminate-dwarf2-dups is broken for C++, ignoring");
!       flag_eliminate_dwarf2_dups = 0;
!     }
! 
!   /* Allocate the file_table.  */
!   file_table = hash_table<dwarf_file_hasher>::create_ggc (50);
! 
! #ifndef DWARF2_LINENO_DEBUGGING_INFO
!   /* Allocate the decl_die_table.  */
!   decl_die_table = hash_table<decl_die_hasher>::create_ggc (10);
! 
!   /* Allocate the decl_loc_table.  */
!   decl_loc_table = hash_table<decl_loc_hasher>::create_ggc (10);
! 
!   /* Allocate the cached_dw_loc_list_table.  */
!   cached_dw_loc_list_table = hash_table<dw_loc_list_hasher>::create_ggc (10);
! 
!   /* Allocate the initial hunk of the decl_scope_table.  */
!   vec_alloc (decl_scope_table, 256);
! 
!   /* Allocate the initial hunk of the abbrev_die_table.  */
!   abbrev_die_table = ggc_cleared_vec_alloc<dw_die_ref>
!     (ABBREV_DIE_TABLE_INCREMENT);
!   abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
!   /* Zero-th entry is allocated, but unused.  */
!   abbrev_die_table_in_use = 1;
! 
!   /* Allocate the pubtypes and pubnames vectors.  */
!   vec_alloc (pubname_table, 32);
!   vec_alloc (pubtype_table, 32);
! 
!   vec_alloc (incomplete_types, 64);
! 
!   vec_alloc (used_rtx_array, 32);
! 
!   /* ???  Can't we defer this to dwarf2out_early_finish()?  */
!   init_sections_and_labels (NULL, NULL);
! 
!   ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
!   ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
!   ASM_GENERATE_INTERNAL_LABEL (cold_text_section_label,
! 			       COLD_TEXT_SECTION_LABEL, 0);
!   ASM_GENERATE_INTERNAL_LABEL (cold_end_label, COLD_END_LABEL, 0);
  
    if (debug_info_level >= DINFO_LEVEL_VERBOSE)
      vec_alloc (macinfo_table, 64);
*************** prune_unused_types_update_strings (dw_di
*** 23784,23789 ****
--- 24631,24646 ----
        }
  }
  
+ /* Mark DIE and its children as removed.  */
+ 
+ static void
+ mark_removed (dw_die_ref die)
+ {
+   dw_die_ref c;
+   die->removed = true;
+   FOR_EACH_CHILD (die, c, mark_removed (c));
+ }
+ 
  /* Remove from the tree DIE any dies that aren't marked.  */
  
  static void
*************** prune_unused_types_prune (dw_die_ref die
*** 23799,23806 ****
  
    c = die->die_child;
    do {
!     dw_die_ref prev = c;
!     for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
        if (c == die->die_child)
  	{
  	  /* No marked children between 'prev' and the end of the list.  */
--- 24656,24663 ----
  
    c = die->die_child;
    do {
!     dw_die_ref prev = c, next;
!     for (c = c->die_sib; ! c->die_mark; c = next)
        if (c == die->die_child)
  	{
  	  /* No marked children between 'prev' and the end of the list.  */
*************** prune_unused_types_prune (dw_die_ref die
*** 23812,23819 ****
--- 24669,24684 ----
  	      prev->die_sib = c->die_sib;
  	      die->die_child = prev;
  	    }
+ 	  c->die_sib = NULL;
+ 	  mark_removed (c);
  	  return;
  	}
+       else
+ 	{
+ 	  next = c->die_sib;
+ 	  c->die_sib = NULL;
+ 	  mark_removed (c);
+ 	}
  
      if (c != prev->die_sib)
        prev->die_sib = c;
*************** move_marked_base_types (void)
*** 24058,24065 ****
  	  remove_child_with_prev (c, prev);
  	  /* As base types got marked, there must be at least
  	     one node other than DW_TAG_base_type.  */
! 	  gcc_assert (c != c->die_sib);
! 	  c = c->die_sib;
  	}
      }
    while (c != die->die_child);
--- 24923,24930 ----
  	  remove_child_with_prev (c, prev);
  	  /* As base types got marked, there must be at least
  	     one node other than DW_TAG_base_type.  */
! 	  gcc_assert (die->die_child != NULL);
! 	  c = prev->die_sib;
  	}
      }
    while (c != die->die_child);
*************** optimize_location_lists (dw_die_ref die)
*** 25127,25171 ****
    optimize_location_lists_1 (die, &htab);
  }
  
  /* Output stuff that dwarf requires at the end of every file,
     and generate the DWARF-2 debugging info.  */
  
  static void
! dwarf2out_finish (const char *filename)
  {
    comdat_type_node *ctnode;
    dw_die_ref main_comp_unit_die;
  
    /* Flush out any latecomers to the limbo party.  */
!   dwarf2out_early_finish ();
  
!   /* PCH might result in DW_AT_producer string being restored from the
!      header compilation, so always fill it with empty string initially
!      and overwrite only here.  */
!   dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
!   producer_string = gen_producer_string ();
!   producer->dw_attr_val.v.val_str->refcount--;
!   producer->dw_attr_val.v.val_str = find_AT_string (producer_string);
  
-   gen_scheduled_generic_parms_dies ();
    gen_remaining_tmpl_value_param_die_attribute ();
  
!   /* Add the name for the main input file now.  We delayed this from
!      dwarf2out_init to avoid complications with PCH.
!      For LTO produced units use a fixed artificial name to avoid
!      leaking tempfile names into the dwarf.  */
!   if (!in_lto_p)
!     add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
!   else
!     add_name_attribute (comp_unit_die (), "<artificial>");
!   if (!IS_ABSOLUTE_PATH (filename) || targetm.force_at_comp_dir)
!     add_comp_dir_attribute (comp_unit_die ());
!   else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
      {
!       bool p = false;
!       file_table->traverse<bool *, file_table_relative_p> (&p);
!       if (p)
! 	add_comp_dir_attribute (comp_unit_die ());
      }
  
  #if ENABLE_ASSERT_CHECKING
--- 25992,26183 ----
    optimize_location_lists_1 (die, &htab);
  }
  
+ /* Traverse the limbo die list, and add parent/child links.  The only
+    dies without parents that should be here are concrete instances of
+    inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
+    For concrete instances, we can get the parent die from the abstract
+    instance.  */
+ 
+ static void
+ flush_limbo_die_list (void)
+ {
+   limbo_die_node *node, *next_node;
+ 
+   for (node = limbo_die_list; node; node = next_node)
+     {
+       dw_die_ref die = node->die;
+       next_node = node->next;
+ 
+       if (die->die_parent == NULL)
+ 	{
+ 	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+ 
+ 	  if (origin && origin->die_parent)
+ 	    add_child_die (origin->die_parent, die);
+ 	  else if (is_cu_die (die))
+ 	    ;
+ 	  else if (seen_error ())
+ 	    /* It's OK to be confused by errors in the input.  */
+ 	    add_child_die (comp_unit_die (), die);
+ 	  else
+ 	    {
+ 	      /* In certain situations, the lexical block containing a
+ 		 nested function can be optimized away, which results
+ 		 in the nested function die being orphaned.  Likewise
+ 		 with the return type of that nested function.  Force
+ 		 this to be a child of the containing function.
+ 
+ 		 It may happen that even the containing function got fully
+ 		 inlined and optimized out.  In that case we are lost and
+ 		 assign the empty child.  This should not be big issue as
+ 		 the function is likely unreachable too.  */
+ 	      gcc_assert (node->created_for);
+ 
+ 	      if (DECL_P (node->created_for))
+ 		origin = get_context_die (DECL_CONTEXT (node->created_for));
+ 	      else if (TYPE_P (node->created_for))
+ 		origin = scope_die_for (node->created_for, comp_unit_die ());
+ 	      else
+ 		origin = comp_unit_die ();
+ 
+ 	      add_child_die (origin, die);
+ 	    }
+ 	}
+     }
+ 
+   limbo_die_list = NULL;
+ }
+ 
+ /* Reset DIEs so we can output them again.  */
+ 
+ static void
+ reset_dies (dw_die_ref die)
+ {
+   dw_die_ref c;
+ 
+   /* Remove stuff we re-generate.  */
+   die->die_mark = 0;
+   die->die_offset = 0;
+   die->die_abbrev = 0;
+   remove_AT (die, DW_AT_sibling);
+ 
+   FOR_EACH_CHILD (die, c, reset_dies (c));
+ }
+ 
  /* Output stuff that dwarf requires at the end of every file,
     and generate the DWARF-2 debugging info.  */
  
  static void
! dwarf2out_finish (const char *)
  {
    comdat_type_node *ctnode;
    dw_die_ref main_comp_unit_die;
  
    /* Flush out any latecomers to the limbo party.  */
!   flush_limbo_die_list ();
  
!   /* We shouldn't have any symbols with delayed asm names for
!      DIEs generated after early finish.  */
!   gcc_assert (deferred_asm_name == NULL);
  
    gen_remaining_tmpl_value_param_die_attribute ();
  
!   if (flag_generate_lto)
!     {
!       gcc_assert (flag_fat_lto_objects);
! 
!       /* Switch back to regular section names and labels for the fat object
! 	 part.
! 	 ???  Do this in dwarf2out_finish ()?  */
!       init_sections_and_labels (NULL, NULL);
! 
!       /* ???  Prune stuff so that dwarf2out_finish runs successfully
! 	 for the fat part of the object.  */
!       if (flag_fat_lto_objects)
! 	{
! 	  reset_dies (comp_unit_die ());
! 	  for (limbo_die_node *node = limbo_die_list; node; node = node->next)
! 	    reset_dies (node->die);
! 	}
! 
!       /* Reset die CU symbol so we don't output it twice.  */
!       comp_unit_die ()->die_id.die_symbol = NULL;
!     }
! 
!   /* Create parent - child relationship if we streamed in DIE reference
!      stubs.  */
!   if (in_lto_p)
      {
!       bool changed;
!       do
! 	{
! 	  changed = false;
! 	  for (limbo_die_node **node = &limbo_die_list;
! 	       *node; )
! 	    {
! 	      if ((*node)->die->die_tag == DW_TAG_compile_unit)
! 		{
! 		  if ((*node)->die == comp_unit_die ())
! 		    *node = (*node)->next;
! 		  else
! 		    node = &(*node)->next;
! 		  continue;
! 		}
! 
! 	      tree t = (*node)->created_for;
! 	      tree context = NULL_TREE;
! 	      if (DECL_P (t))
! 		context = DECL_CONTEXT (t);
! 	      else if (TREE_CODE (t) == BLOCK)
! 		context = BLOCK_SUPERCONTEXT (t);
! 	      /* ???  We don't output DIEs for wrapping scopes.  Skip
! 		 as many DIEs as needed.  */
! 	      if (context)
! 		while (TREE_CODE (context) == BLOCK
! 		       && !BLOCK_DIE (context))
! 		  context = BLOCK_SUPERCONTEXT (context);
! 	      /* ???  We fail to re-parent BLOCK scope variables as
! 		 dependent on frontend their DECL_CONTEXT is not the
! 		 containing scope but the containing function.  */
! 	      if (context && DECL_P (context))
! 		{
! 		  dw_die_ref ctx = lookup_decl_die (context);
! 		  if (ctx)
! 		    {
! 		      add_child_die (ctx, (*node)->die);
! 		      *node = (*node)->next;
! 		      changed = true;
! 		      continue;
! 		    }
! 		}
! 	      else if (context && TREE_CODE (context) == BLOCK)
! 		{
! 		  dw_die_ref ctx = BLOCK_DIE (context);
! 		  if (ctx)
! 		    {
! 		      add_child_die (ctx, (*node)->die);
! 		      *node = (*node)->next;
! 		      changed = true;
! 		      continue;
! 		    }
! 		}
! 	      else if (!context)
! 		{
! 		  /* ???  In some cases the C++ FE (at least) fails to
! 		     set DECL_CONTEXT properly.  Simply globalize stuff
! 		     in this case.  For example
! 		     __dso_handle created via iostream line 74 col 25.  */
! 		  // gcc_assert ((*node)->die->dumped_early);
! 		  add_child_die (comp_unit_die (), (*node)->die);
! 		  *node = (*node)->next;
! 		  changed = true;
! 		  continue;
! 		}
! 
! 	      node = &(*node)->next;
! 	    }
! 	}
!       while (changed);
      }
  
  #if ENABLE_ASSERT_CHECKING
*************** dwarf2out_finish (const char *filename)
*** 25175,25217 ****
    }
  #endif
    resolve_addr (comp_unit_die ());
    move_marked_base_types ();
  
-   /* Walk through the list of incomplete types again, trying once more to
-      emit full debugging info for them.  */
-   retry_incomplete_types ();
- 
-   if (flag_eliminate_unused_debug_types)
-     prune_unused_types ();
- 
-   /* Generate separate COMDAT sections for type DIEs. */
-   if (use_debug_types)
-     {
-       break_out_comdat_types (comp_unit_die ());
- 
-       /* Each new type_unit DIE was added to the limbo die list when created.
-          Since these have all been added to comdat_type_list, clear the
-          limbo die list.  */
-       limbo_die_list = NULL;
- 
-       /* For each new comdat type unit, copy declarations for incomplete
-          types to make the new unit self-contained (i.e., no direct
-          references to the main compile unit).  */
-       for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
-         copy_decls_for_unworthy_types (ctnode->root_die);
-       copy_decls_for_unworthy_types (comp_unit_die ());
- 
-       /* In the process of copying declarations from one unit to another,
-          we may have left some declarations behind that are no longer
-          referenced.  Prune them.  */
-       prune_unused_types ();
-     }
- 
-   /* Generate separate CUs for each of the include files we've seen.
-      They will go into limbo_die_list.  */
-   if (flag_eliminate_dwarf2_dups)
-     break_out_includes (comp_unit_die ());
- 
    /* Traverse the DIE's and add sibling attributes to those DIE's that
       have children.  */
    add_sibling_attributes (comp_unit_die ());
--- 26187,26198 ----
    }
  #endif
    resolve_addr (comp_unit_die ());
+   /* ???  The following should be part of early dwarf but currently
+      base-types are marked in resolve_addr (taking advantage of
+      doing this only on the dwarf that remains after resolve_addr
+      which eventually prunes some DIEs).  */
    move_marked_base_types ();
  
    /* Traverse the DIE's and add sibling attributes to those DIE's that
       have children.  */
    add_sibling_attributes (comp_unit_die ());
*************** dwarf2out_finish (const char *filename)
*** 25481,25489 ****
     has run.  */
  
  static void
! dwarf2out_early_finish (void)
  {
!   limbo_die_node *node, *next_node;
  
    /* Add DW_AT_linkage_name for all deferred DIEs.  */
    for (node = deferred_asm_name; node; node = node->next)
--- 26462,26485 ----
     has run.  */
  
  static void
! dwarf2out_early_finish (const char *filename)
  {
!   comdat_type_node *ctnode;
! 
!   /* Pick the first TRANSLATION_UNIT_DECL we didn't create a DIE for
!      and equate it with our default CU DIE.  LTO output needs to be
!      able to lookup DIEs for translation unit decls.  */
!   unsigned i;
!   tree decl;
!   FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, decl)
!     if (!lookup_decl_die (decl))
!       {
! 	// A gcc_unreachable () should work here after the main CU
! 	// hook got added?
! 	equate_decl_number_to_die (decl, comp_unit_die ());
!       }
! 
!   limbo_die_node *node;
  
    /* Add DW_AT_linkage_name for all deferred DIEs.  */
    for (node = deferred_asm_name; node; node = node->next)
*************** dwarf2out_early_finish (void)
*** 25501,25557 ****
      }
    deferred_asm_name = NULL;
  
!   /* Traverse the limbo die list, and add parent/child links.  The only
!      dies without parents that should be here are concrete instances of
!      inline functions, and the comp_unit_die.  We can ignore the comp_unit_die.
!      For concrete instances, we can get the parent die from the abstract
!      instance.
! 
!      The point here is to flush out the limbo list so that it is empty
       and we don't need to stream it for LTO.  */
!   for (node = limbo_die_list; node; node = next_node)
      {
!       dw_die_ref die = node->die;
!       next_node = node->next;
  
!       if (die->die_parent == NULL)
! 	{
! 	  dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
  
! 	  if (origin && origin->die_parent)
! 	    add_child_die (origin->die_parent, die);
! 	  else if (is_cu_die (die))
! 	    ;
! 	  else if (seen_error ())
! 	    /* It's OK to be confused by errors in the input.  */
! 	    add_child_die (comp_unit_die (), die);
! 	  else
! 	    {
! 	      /* In certain situations, the lexical block containing a
! 		 nested function can be optimized away, which results
! 		 in the nested function die being orphaned.  Likewise
! 		 with the return type of that nested function.  Force
! 		 this to be a child of the containing function.
  
! 		 It may happen that even the containing function got fully
! 		 inlined and optimized out.  In that case we are lost and
! 		 assign the empty child.  This should not be big issue as
! 		 the function is likely unreachable too.  */
! 	      gcc_assert (node->created_for);
  
! 	      if (DECL_P (node->created_for))
! 		origin = get_context_die (DECL_CONTEXT (node->created_for));
! 	      else if (TYPE_P (node->created_for))
! 		origin = scope_die_for (node->created_for, comp_unit_die ());
! 	      else
! 		origin = comp_unit_die ();
  
! 	      add_child_die (origin, die);
! 	    }
! 	}
      }
  
!   limbo_die_list = NULL;
  }
  
  /* Reset all state within dwarf2out.c so that we can rerun the compiler
--- 26497,26706 ----
      }
    deferred_asm_name = NULL;
  
!   /* The point here is to flush out the limbo list so that it is empty
       and we don't need to stream it for LTO.  */
!   flush_limbo_die_list ();
! 
!   /* PCH might result in DW_AT_producer string being restored from the
!      header compilation, so always fill it with empty string initially
!      and overwrite only here.  */
!   dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
!   producer_string = gen_producer_string ();
!   producer->dw_attr_val.v.val_str->refcount--;
!   producer->dw_attr_val.v.val_str = find_AT_string (producer_string);
! 
!   gen_scheduled_generic_parms_dies ();
!   gen_remaining_tmpl_value_param_die_attribute ();
! 
!   /* Add the name for the main input file now.  We delayed this from
!      dwarf2out_init to avoid complications with PCH.
!      For LTO produced units use a fixed artificial name to avoid
!      leaking tempfile names into the dwarf.  */
!   if (!in_lto_p)
!     add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
!   else
!     add_name_attribute (comp_unit_die (), "<artificial>");
!   if (!IS_ABSOLUTE_PATH (filename) || targetm.force_at_comp_dir)
!     add_comp_dir_attribute (comp_unit_die ());
!   else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
      {
!       bool p = false;
!       file_table->traverse<bool *, file_table_relative_p> (&p);
!       if (p)
! 	add_comp_dir_attribute (comp_unit_die ());
!     }
  
!   /* Walk through the list of incomplete types again, trying once more to
!      emit full debugging info for them.  */
!   retry_incomplete_types ();
  
!   if (flag_eliminate_unused_debug_types)
!     /* ???  Doing prune_unused_types early means we need to restrict
!        pruning somewhat otherwise we for example run into late code
!        generating DIEs refering to callee decl DIEs failing or using
!        less efficient symbol references.
!        One way to improve things is to use the early cgraph we have
!        and mark DIEs of all symbols as used.  */
!     prune_unused_types ();
  
!   /* FIXME debug-early: Prune DIEs for unused decls.  */
  
!   /* Generate separate COMDAT sections for type DIEs. */
!   if (use_debug_types)
!     {
!       break_out_comdat_types (comp_unit_die ());
  
!       /* Each new type_unit DIE was added to the limbo die list when created.
!          Since these have all been added to comdat_type_list, clear the
!          limbo die list.  */
!       limbo_die_list = NULL;
! 
!       /* For each new comdat type unit, copy declarations for incomplete
!          types to make the new unit self-contained (i.e., no direct
!          references to the main compile unit).  */
!       for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
!         copy_decls_for_unworthy_types (ctnode->root_die);
!       copy_decls_for_unworthy_types (comp_unit_die ());
! 
!       /* In the process of copying declarations from one unit to another,
!          we may have left some declarations behind that are no longer
!          referenced.  Prune them.  */
!       prune_unused_types ();
      }
  
!   /* Generate separate CUs for each of the include files we've seen.
!      They will go into limbo_die_list.  */
!   if (flag_eliminate_dwarf2_dups)
!     break_out_includes (comp_unit_die ());
! 
! 
!   /* Do not generate DWARF assembler now when not producing LTO bytecode.
!      ???  The following code in principle handles split DWARF producing but
!      it has some issues (and it's likely not desired).  */
!   if (!flag_generate_lto)
!     return;
! 
!   /* Now as we are going to output for LTO switch sections and labels
!      to the _gnu.lto prefixed variants.  */
!   char postfix[20];
!   /* ???  The LTO input machinery doesn't like the ID directly after
!      the prefix, but unless the linker scripting can handle a postfix
!      and we can bear the ugliness of having both a prefix and a suffix...  */
!   sprintf (postfix, "." HOST_WIDE_INT_PRINT_HEX_PURE, get_random_seed (false));
!   /* ???  Can't use .gnu.lto_ as prefix here as GAS sets 'E'xclude on
!      those sections and that causes unrecoverable pain down the machinery.
!      ???  Of course this means the sections stay in a FAT non-LTO link.  */
!   init_sections_and_labels (".gnu.debuglto_"/*section_name_prefix*/, postfix);
! 
!   /* ???  Duplicated from dwarf2out_finish.  */
! 
!   /* Traverse the DIE's and add add sibling attributes to those DIE's
!      that have children.  */
!   add_sibling_attributes (comp_unit_die ());
!   for (node = limbo_die_list; node; node = node->next)
!     add_sibling_attributes (node->die);
!   for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
!     add_sibling_attributes (ctnode->root_die);
! 
!   if (have_macinfo)
!     add_AT_macptr (comp_unit_die (),
! 		   dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
! 		   macinfo_section_label);
! 
!   save_macinfo_strings ();
! 
!   /* Output all of the compilation units.  We put the main one last so that
!      the offsets are available to output_pubnames.  */
!   for (node = limbo_die_list; node; node = node->next)
!     output_comp_unit (node->die, 0);
! 
!   hash_table<comdat_type_hasher> comdat_type_table (100);
!   for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
!     {
!       comdat_type_node **slot = comdat_type_table.find_slot (ctnode, INSERT);
! 
!       /* Don't output duplicate types.  */
!       if (*slot != HTAB_EMPTY_ENTRY)
!         continue;
! 
!       /* Add a pointer to the line table for the main compilation unit
!          so that the debugger can make sense of DW_AT_decl_file
!          attributes.  */
!       if (debug_info_level >= DINFO_LEVEL_TERSE)
!         add_AT_lineptr (ctnode->root_die, DW_AT_stmt_list,
!                         (!dwarf_split_debug_info
!                          ? debug_line_section_label
!                          : debug_skeleton_line_section_label));
! 
!       output_comdat_type_unit (ctnode);
!       *slot = ctnode;
!     }
! 
!   /* The AT_pubnames attribute needs to go in all skeleton dies, including
!      both the main_cu and all skeleton TUs.  Making this call unconditional
!      would end up either adding a second copy of the AT_pubnames attribute, or
!      requiring a special case in add_top_level_skeleton_die_attrs.  */
!   if (!dwarf_split_debug_info)
!     add_AT_pubnames (comp_unit_die ());
! 
!   /* Stick a unique symbol to the main debuginfo section.  */
!   compute_section_prefix_1 (comp_unit_die (), false);
! 
!   /* Output the main compilation unit if non-empty or if .debug_macinfo
!      or .debug_macro will be emitted.  */
!   output_comp_unit (comp_unit_die (), have_macinfo);
! 
!   /* Output the abbreviation table.  */
!   if (abbrev_die_table_in_use != 1)
!     {
!       switch_to_section (debug_abbrev_section);
!       ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
!       output_abbrev_section ();
!     }
! 
!   /* Have to end the macro section.  */
!   if (have_macinfo)
!     {
!       switch_to_section (debug_macinfo_section);
!       ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
!       output_macinfo ();
!       dw2_asm_output_data (1, 0, "End compilation unit");
!     }
! 
! 
!   /* If we emitted any indirect strings, output the string table too.  */
!   if (debug_str_hash || skeleton_debug_str_hash)
!     output_indirect_strings ();
! 
! #if 0
!   /* ???  Not needed, copying full .symtab just works - though we
!      need to avoid clashes with FAT object symbols of course.  */
!   /* Output a symbol mapping, section -> symbol for the LTO part.  */
!   char symsecname[256];
!   sprintf (symsecname, ".gnu.debuglto_.debug_sym." HOST_WIDE_INT_PRINT_HEX_PURE,
! 	   /*section_name_prefix,*/ get_random_seed (false));
!   section *syms = get_section (symsecname, SECTION_DEBUG, NULL);
!   switch_to_section (syms);
! 
!   char buf[1024];
!   sprintf (buf, ".debug_info=%s", comp_unit_die ()->die_id.die_symbol);
!   dw2_asm_output_nstring (buf, -1, NULL);
! #if 0
!   /* ???  What about other created sections?  What's their section name?
!      That gets dropped in output_comp_unit () ... so add to .debug_sym
!      in there?  */
!   for (node = limbo_die_list; node; node = node->next)
!     {
!       sprintf (buf, "??? = %s", comp_unit_die ()->die_id.die_symbol);
!       dw2_asm_output_nstring (buf, -1, NULL);
!     }
! #endif
! #endif
! 
!   /* Switch back to the text section.  */
!   switch_to_section (text_section);
! 
!   debug_str_hash = NULL;  /* Contents are GCed.  */
  }
  
  /* Reset all state within dwarf2out.c so that we can rerun the compiler
Index: trunk/gcc/gimplify.c
===================================================================
*** trunk.orig/gcc/gimplify.c	2015-08-27 16:29:15.316199042 +0200
--- trunk/gcc/gimplify.c	2015-08-27 16:30:06.002665159 +0200
*************** gimplify_one_sizepos (tree *expr_p, gimp
*** 9149,9154 ****
--- 9149,9160 ----
    *expr_p = unshare_expr (expr);
  
    gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
+ 
+   /* The possibly generated temporary is interesting for debug information
+      to complete the VLA type sizes and bounds.  Clear DECL_IGNORED_P.  */
+   if (TREE_CODE (*expr_p) == VAR_DECL
+       && DECL_ARTIFICIAL (*expr_p))
+     DECL_IGNORED_P (*expr_p) = false;
  }
  
  /* Gimplify the body of statements of FNDECL and return a GIMPLE_BIND node
Index: trunk/gcc/lto-streamer-in.c
===================================================================
*** trunk.orig/gcc/lto-streamer-in.c	2015-08-27 16:29:15.317199052 +0200
--- trunk/gcc/lto-streamer-in.c	2015-08-27 16:30:06.002665159 +0200
*************** along with GCC; see the file COPYING3.
*** 58,63 ****
--- 58,64 ----
  #include "target.h"
  #include "gimple-streamer.h"
  #include "cfgloop.h"
+ #include "debug.h"
  
  
  struct freeing_string_slot_hasher : string_slot_hasher
*************** lto_input_variable_constructor (struct l
*** 1282,1287 ****
--- 1283,1290 ----
  }
  
  
+ vec<dref_entry> dref_queue;
+ 
  /* Read the physical representation of a tree node EXPR from
     input block IB using the per-file context in DATA_IN.  */
  
*************** lto_read_tree_1 (struct lto_input_block
*** 1302,1307 ****
--- 1305,1327 ----
        && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
      DECL_INITIAL (expr) = stream_read_tree (ib, data_in);
  
+   /* Stream references to early generated DIEs.  Keep in sync with the
+      trees handled in dwarf2out_register_external_die.  */
+   if ((DECL_P (expr)
+        && TREE_CODE (expr) != FIELD_DECL
+        && TREE_CODE (expr) != DEBUG_EXPR_DECL
+        && TREE_CODE (expr) != TYPE_DECL)
+       || TREE_CODE (expr) == BLOCK)
+     {
+       const char *str = streamer_read_string (data_in, ib);
+       if (str)
+ 	{
+ 	  unsigned HOST_WIDE_INT off = streamer_read_uhwi (ib);
+ 	  dref_entry e = { expr, str, off };
+ 	  dref_queue.safe_push (e);
+ 	}
+     }
+ 
    /* We should never try to instantiate an MD or NORMAL builtin here.  */
    if (TREE_CODE (expr) == FUNCTION_DECL)
      gcc_assert (!streamer_handle_as_builtin_p (expr));
*************** lto_input_tree (struct lto_input_block *
*** 1463,1468 ****
--- 1483,1495 ----
      {
        unsigned len, entry_len;
        lto_input_scc (ib, data_in, &len, &entry_len);
+ 
+       /* Register DECLs with the debuginfo machinery.  */
+       while (!dref_queue.is_empty ())
+ 	{
+ 	  dref_entry e = dref_queue.pop ();
+ 	  debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ 	}
      }
    return lto_input_tree_1 (ib, data_in, tag, 0);
  }
Index: trunk/gcc/lto-streamer-out.c
===================================================================
*** trunk.orig/gcc/lto-streamer-out.c	2015-08-27 16:29:15.318199061 +0200
--- trunk/gcc/lto-streamer-out.c	2015-08-27 16:30:06.003665168 +0200
*************** along with GCC; see the file COPYING3.
*** 54,59 ****
--- 54,60 ----
  #include "cfgloop.h"
  #include "builtins.h"
  #include "gomp-constants.h"
+ #include "debug.h"
  
  
  static void lto_write_tree (struct output_block*, tree, bool);
*************** lto_write_tree_1 (struct output_block *o
*** 373,378 ****
--- 374,399 ----
  			 (ob->decl_state->symtab_node_encoder, expr);
        stream_write_tree (ob, initial, ref_p);
      }
+ 
+   /* Stream references to early generated DIEs.  Keep in sync with the
+      trees handled in dwarf2out_die_ref_for_decl.  */
+   if ((DECL_P (expr)
+        && TREE_CODE (expr) != FIELD_DECL
+        && TREE_CODE (expr) != DEBUG_EXPR_DECL
+        && TREE_CODE (expr) != TYPE_DECL)
+       || TREE_CODE (expr) == BLOCK)
+     {
+       const char *sym;
+       unsigned HOST_WIDE_INT off;
+       if (debug_info_level > DINFO_LEVEL_NONE
+ 	  && debug_hooks->die_ref_for_decl (expr, &sym, &off))
+ 	{
+ 	  streamer_write_string (ob, ob->main_stream, sym, true);
+ 	  streamer_write_uhwi (ob, off);
+ 	}
+       else
+ 	streamer_write_string (ob, ob->main_stream, NULL, true);
+     }
  }
  
  /* Write a physical representation of tree node EXPR to output block
*************** DFS::DFS_write_tree_body (struct output_
*** 746,751 ****
--- 767,773 ----
        /* Do not follow DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
  	 for early inlining so drop it on the floor instead of ICEing in
  	 dwarf2out.c.  */
+       DFS_follow_tree_edge (DECL_ABSTRACT_ORIGIN (expr));
  
        if ((TREE_CODE (expr) == VAR_DECL
  	   || TREE_CODE (expr) == PARM_DECL)
Index: trunk/gcc/lto-streamer.h
===================================================================
*** trunk.orig/gcc/lto-streamer.h	2015-08-27 16:29:15.318199061 +0200
--- trunk/gcc/lto-streamer.h	2015-08-27 16:30:06.003665168 +0200
*************** DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, typ
*** 1217,1220 ****
--- 1217,1229 ----
  DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
  DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
  
+ struct dref_entry {
+     tree decl;
+     const char *sym;
+     unsigned HOST_WIDE_INT off;
+ };
+ 
+ extern vec<dref_entry> dref_queue;
+ 
+ 
  #endif /* GCC_LTO_STREAMER_H  */
Index: trunk/gcc/lto-wrapper.c
===================================================================
*** trunk.orig/gcc/lto-wrapper.c	2015-08-27 16:29:15.319199070 +0200
--- trunk/gcc/lto-wrapper.c	2015-08-27 16:30:06.004665177 +0200
*************** static char **output_names;
*** 70,75 ****
--- 70,77 ----
  static char **offload_names;
  static const char *offloadbegin, *offloadend;
  static char *makefile;
+ static char *linker_script;
+ static char *debug_obj;
  
  const char tool_name[] = "lto-wrapper";
  
*************** tool_cleanup (bool)
*** 86,91 ****
--- 88,97 ----
      maybe_unlink (flto_out);
    if (makefile)
      maybe_unlink (makefile);
+   if (linker_script)
+     maybe_unlink (linker_script);
+   if (debug_obj)
+     maybe_unlink (debug_obj);
    for (i = 0; i < nr; ++i)
      {
        maybe_unlink (input_names[i]);
*************** find_and_merge_options (int fd, off_t fi
*** 870,875 ****
--- 876,960 ----
    return true;
  }
  
+ struct wls_data
+ {
+   FILE *script;
+   const char *fname;
+   simple_object_read *sobj;
+   int fd;
+ };
+ 
+ #if 0
+ /* Use simple_object to iterate over all sections, generating
+    .debug_info : { symbol-for-object.o = .; object.o(.gnu.lto_.debug_info.ID) }
+    .others : { object.o(.gnu.lto_.others.ID) }
+    /DISCARD/ : { object.o(*) } */
+ 
+ static int
+ write_linker_script (void *data, const char *secname, off_t, off_t)
+ {
+   wls_data *d = (wls_data *)data;
+ 
+ #if 0
+   /* We are looking after .gnu.lto_.debug_*[.ID]  */
+   unsigned int pfxlen = sizeof (LTO_SECTION_NAME_PREFIX) - 1;
+   if (strncmp (secname, LTO_SECTION_NAME_PREFIX, pfxlen) != 0)
+     return 1;
+ #endif
+   /* We are looking after .gnu.debuglto_.debug_*[.ID]  */
+   unsigned int pfxlen = sizeof (".gnu.debuglto_") - 1;
+   if (strncmp (secname, ".gnu.debuglto_", pfxlen) != 0)
+     return 1;
+   if (strncmp (secname + pfxlen, ".debug_", sizeof (".debug_") - 1) != 0)
+     return 1;
+ 
+   const char *id = strrchr (secname, '.');
+   unsigned idlen = 0;
+   if (id != secname + pfxlen)
+     idlen = strlen (id);
+ 
+   char stripped_secname[128];
+   strncpy (stripped_secname, secname + pfxlen,
+ 	   strlen (secname) - pfxlen - idlen);
+   stripped_secname[strlen (secname) - pfxlen - idlen] = '\0';
+ 
+   /* .debug_sym contains just symbols names we need to add to be able to
+      refer to beginnings of the sections we copy.  */
+   if (strcmp (stripped_secname, ".debug_sym") == 0)
+     return 1;
+ 
+   fprintf (d->script, "  %s : { ", stripped_secname);
+   if (strcmp (stripped_secname, ".debug_info") == 0)
+     {
+       /* ???  The linker script as written seems to copy symbols.  */
+ #if 0
+       char symsecname[1024];
+       sprintf (symsecname, ".gnu.debuglto_.debug_sym%s",
+ 	       id ? id : "");
+       off_t offset, length;
+       const char *errmsg;
+       int err;
+       if (!simple_object_find_section (d->sobj, symsecname, &offset, &length,
+ 				       &errmsg, &err))
+ 	fatal_error (input_location, errmsg);
+       char symname[1024];
+       pread (d->fd, symname, length + 1 - sizeof (".debug_info="),
+ 	     offset + sizeof (".debug_info=") - 1);
+       /* For the .debug_info section we need to emit a symbol to its
+          beginning as well.  */
+       fprintf (d->script, "%s = .;", symname);
+ #endif
+     }
+   fprintf (d->script, "  %s(%s) }\n", d->fname, secname);
+ 
+   /* ???  What about .rela.gnu.lto_.debug_info.663b3fd04427bbd3  */
+   /* ???  Can that even work with multiple .IDs around, that is
+      someone partially linking LTO objects?  One need to experiment... */
+ 
+   return 1;
+ }
+ #endif
+ 
  /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
  
  static void
*************** run_gcc (unsigned argc, char *argv[])
*** 894,901 ****
    int new_head_argc;
    bool have_lto = false;
    bool have_offload = false;
!   unsigned lto_argc = 0, offload_argc = 0;
!   char **lto_argv, **offload_argv;
  
    /* Get the driver and options.  */
    collect_gcc = getenv ("COLLECT_GCC");
--- 979,986 ----
    int new_head_argc;
    bool have_lto = false;
    bool have_offload = false;
!   unsigned lto_argc = 0, ltoobj_argc = 0, offload_argc = 0;
!   char **lto_argv, **ltoobj_argv, **offload_argv;
  
    /* Get the driver and options.  */
    collect_gcc = getenv ("COLLECT_GCC");
*************** run_gcc (unsigned argc, char *argv[])
*** 914,919 ****
--- 999,1005 ----
    /* Allocate arrays for input object files with LTO or offload IL,
       and for possible preceding arguments.  */
    lto_argv = XNEWVEC (char *, argc);
+   ltoobj_argv = XNEWVEC (char *, argc);
    offload_argv = XNEWVEC (char *, argc);
  
    /* Look at saved options in the IL files.  */
*************** run_gcc (unsigned argc, char *argv[])
*** 948,954 ****
  				  collect_gcc))
  	{
  	  have_lto = true;
! 	  lto_argv[lto_argc++] = argv[i];
  	}
  
        if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
--- 1034,1040 ----
  				  collect_gcc))
  	{
  	  have_lto = true;
! 	  ltoobj_argv[ltoobj_argc++] = argv[i];
  	}
  
        if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
*************** run_gcc (unsigned argc, char *argv[])
*** 1149,1168 ****
          obstack_ptr_grow (&argv_obstack, "-fwpa");
      }
  
!   /* Append the input objects and possible preceding arguments.  */
    for (i = 0; i < lto_argc; ++i)
      obstack_ptr_grow (&argv_obstack, lto_argv[i]);
    obstack_ptr_grow (&argv_obstack, NULL);
  
    new_argv = XOBFINISH (&argv_obstack, const char **);
    argv_ptr = &new_argv[new_head_argc];
    fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
  
    if (lto_mode == LTO_MODE_LTO)
      {
        printf ("%s\n", flto_out);
        free (flto_out);
        flto_out = NULL;
      }
    else
      {
--- 1235,1376 ----
          obstack_ptr_grow (&argv_obstack, "-fwpa");
      }
  
!   /* Append input arguments.  */
    for (i = 0; i < lto_argc; ++i)
      obstack_ptr_grow (&argv_obstack, lto_argv[i]);
+   /* Append the input objects.  */
+   for (i = 0; i < ltoobj_argc; ++i)
+     obstack_ptr_grow (&argv_obstack, ltoobj_argv[i]);
    obstack_ptr_grow (&argv_obstack, NULL);
  
    new_argv = XOBFINISH (&argv_obstack, const char **);
    argv_ptr = &new_argv[new_head_argc];
    fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
  
+     {
+   /* Produce an object with all debuginfo sections from the LTO input
+      objects.  Write a linker script for this and do a partial link.
+      Eventually we can feed the linker with an output .o file that
+      is a linker script itself...(?)  */
+   /* First generate the linker script.  */
+   linker_script = make_temp_file ("script");
+   FILE *script = fopen (linker_script, "w");
+ #if 1
+   for (i = 0; i < ltoobj_argc; ++i)
+     fprintf (script, "INPUT(%s)\n", ltoobj_argv[i]);
+ #endif
+   fprintf (script, "SECTIONS {\n");
+ #if 0
+   for (i = 0; i < ltoobj_argc; ++i)
+     {
+       int fd = open (ltoobj_argv[i], O_RDONLY);
+       int err;
+       const char *errmsg;
+       simple_object_read *s;
+       s = simple_object_start_read (fd, 0, LTO_SEGMENT_NAME, &errmsg, &err);
+       if (!s)
+ 	{
+ 	  close (fd);
+ 	  continue;
+ 	}
+       wls_data d;
+       d.fname = ltoobj_argv[i];
+       d.script = script;
+       d.sobj = s;
+       d.fd = fd;
+       simple_object_find_sections (s, write_linker_script, &d, &err);
+       /* ???  We need to perform a partial link so the inputs don't get
+          their .gnu.lto sections stripped before we have a chance to
+ 	 assign them to output.  Interestingly this doesn't happen to
+ 	 .gnu.lto_.debug_str...
+ 	 This is because GNU as marks all .gnu.lto_ sections 'Exclude'.
+ 	 ???  So for the partial link discard any other sections in the
+ 	 input.  */
+       fprintf (script, "  /DISCARD/ : { %s(*) }\n", ltoobj_argv[i]);
+       /* The link will also copy all symbols, including __gnu_lto_slim
+          and __gnu_lto_v1 which will cause the final link to complain.
+ 	 Using a version script may make dropping them possible?  But
+ 	 not in a partial link I suppose.  GNU ld has a --retain-symbols-file
+ 	 option as well.  In fact even if explicitely discarding COMMON
+ 	 the symtab entries will remain.  */
+       simple_object_release_read (s);
+       close (fd);
+     }
+ #else
+   fprintf (script,
+ 	   "  .debug_info 0 : { *(.gnu.debuglto_.debug_info*) }\n"
+ 	   "  .debug_abbrev 0 : { *(.gnu.debuglto_.debug_abbrev*) }\n"
+ 	   "  .debug_str 0 : { *(.gnu.debuglto_.debug_str*) }\n"
+ 	   "  .debug_pubnames 0 : { *(.gnu.debuglto_.debug_pubnames*) }\n"
+ 	   "  .debug_pubtypes 0 : { *(.gnu.debuglto_.debug_pubtypes*) }\n"
+ 	   "  .debug_macinfo 0 : { *(.gnu.debuglto_.debug_macro*) }\n"
+ 	   /* The following is to workaround a bug in GOLD which has
+ 	      the /DISCARD/ prevent it from creating the relocation
+ 	      sections ultimatively causing it to crash.  */
+ 	   "  .rela.debug_info : { *(.rela.debug_info) }\n"
+ 	   "  /DISCARD/ : { *(*) }\n");
+ #endif
+   fprintf (script, "}\n");
+   fclose (script);
+     }
+ 
+ #if 1
+     {
+   /* For now invoke a partial link to gather the compile-time generated
+      debug-info into an input for the final link.  */
+   obstack_ptr_grow (&argv_obstack, collect_gcc);
+   for (i = 1; i < decoded_options_count; ++i)
+     {
+       if (decoded_options[i].opt_index == OPT_B)
+ 	{
+ 	  append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ 	  break;
+ 	}
+     }
+   /* ???  Using collect_gcc recurses because it passes -plugin to the
+      linker which in turn sees all inputs having LTO bytecode.  So
+      pass -fno-use-linker-plugin.  Probably still breaks with plugin
+      auto-loading?!  */
+   obstack_ptr_grow (&argv_obstack, "-fno-use-linker-plugin");
+   obstack_ptr_grow (&argv_obstack, "-o");
+   debug_obj = make_temp_file ("debugobj");
+   obstack_ptr_grow (&argv_obstack, debug_obj);
+   obstack_ptr_grow (&argv_obstack, "-r");
+   obstack_ptr_grow (&argv_obstack, "-nostdlib");
+   obstack_ptr_grow (&argv_obstack, "-Wl,-T");
+   obstack_ptr_grow (&argv_obstack, linker_script);
+   obstack_ptr_grow (&argv_obstack, NULL);
+   const char **debug_link_argv = XOBFINISH (&argv_obstack, const char **);
+   fork_execute (debug_link_argv[0],
+ 		CONST_CAST (char **, debug_link_argv), false);
+ #if 0
+   /* ???  The partially linked result contains __gnu_lto_slim which the
+      linker seems to ignore when we feed that in as plugin output :(  */
+   obstack_ptr_grow (&argv_obstack, "objcopy");
+   obstack_ptr_grow (&argv_obstack, "--strip-symbol=__gnu_lto_slim");
+   obstack_ptr_grow (&argv_obstack, debug_obj);
+   obstack_ptr_grow (&argv_obstack, NULL);
+   debug_link_argv = XOBFINISH (&argv_obstack, const char **);
+   fork_execute (debug_link_argv[0],
+ 		CONST_CAST (char **, debug_link_argv), true);
+ #endif
+     }
+ #endif
+ 
    if (lto_mode == LTO_MODE_LTO)
      {
+ #if 0
+       printf ("%s\n", linker_script);
+ #else
+       printf ("%s\n", debug_obj);
+ #endif
        printf ("%s\n", flto_out);
        free (flto_out);
        flto_out = NULL;
+       free (debug_obj);
+       debug_obj = NULL;
+       free (linker_script);
+       linker_script = NULL;
      }
    else
      {
*************** cont:
*** 1309,1318 ****
  	  for (i = 0; i < nr; ++i)
  	    maybe_unlink (input_names[i]);
  	}
        for (i = 0; i < nr; ++i)
  	{
! 	  fputs (output_names[i], stdout);
! 	  putc ('\n', stdout);
  	  free (input_names[i]);
  	}
        nr = 0;
--- 1517,1535 ----
  	  for (i = 0; i < nr; ++i)
  	    maybe_unlink (input_names[i]);
  	}
+ #if 0
+       printf ("%s\n", linker_script);
+       free (linker_script);
+       linker_script = NULL;
+ #else
+       /* ???  Invoke partial link for now.  */
+       printf ("%s\n", debug_obj);
+       free (debug_obj);
+       debug_obj = NULL;
+ #endif
        for (i = 0; i < nr; ++i)
  	{
! 	  printf ("%s\n", output_names[i]);
  	  free (input_names[i]);
  	}
        nr = 0;
Index: trunk/gcc/lto/lto.c
===================================================================
*** trunk.orig/gcc/lto/lto.c	2015-08-27 16:29:15.320199079 +0200
--- trunk/gcc/lto/lto.c	2015-08-27 16:30:06.004665177 +0200
*************** compare_tree_sccs_1 (tree t1, tree t2, t
*** 1303,1308 ****
--- 1303,1309 ----
        compare_tree_edges (DECL_SIZE (t1), DECL_SIZE (t2));
        compare_tree_edges (DECL_SIZE_UNIT (t1), DECL_SIZE_UNIT (t2));
        compare_tree_edges (DECL_ATTRIBUTES (t1), DECL_ATTRIBUTES (t2));
+       compare_tree_edges (DECL_ABSTRACT_ORIGIN (t1), DECL_ABSTRACT_ORIGIN (t2));
        if ((code == VAR_DECL
  	   || code == PARM_DECL)
  	  && DECL_HAS_VALUE_EXPR_P (t1))
*************** unify_scc (struct data_in *data_in, unsi
*** 1626,1631 ****
--- 1627,1635 ----
  	      ggc_free (scc->entries[i]);
  	    }
  
+ 	  /* Drop DIE references.  */
+ 	  dref_queue.truncate (0);
+ 
  	  break;
  	}
  
*************** lto_read_decls (struct lto_file_decl_dat
*** 1702,1708 ****
  	  if (len == 1
  	      && (TREE_CODE (first) == IDENTIFIER_NODE
  		  || TREE_CODE (first) == INTEGER_CST
- 		  || TREE_CODE (first) == TRANSLATION_UNIT_DECL
  		  || streamer_handle_as_builtin_p (first)))
  	    continue;
  
--- 1706,1711 ----
*************** lto_read_decls (struct lto_file_decl_dat
*** 1742,1757 ****
  	      if (TREE_CODE (t) == INTEGER_CST
  		  && !TREE_OVERFLOW (t))
  		cache_integer_cst (t);
- 	      /* Register TYPE_DECLs with the debuginfo machinery.  */
- 	      if (!flag_wpa
- 		  && TREE_CODE (t) == TYPE_DECL)
- 		{
- 		  /* Dwarf2out needs location information.
- 		     TODO: Moving this out of the streamer loop may noticealy
- 		     improve ltrans linemap memory use.  */
- 		  data_in->location_cache.apply_location_cache ();
- 		  debug_hooks->type_decl (t, !DECL_FILE_SCOPE_P (t));
- 		}
  	      if (!flag_ltrans)
  		{
  		  /* Register variables and functions with the
--- 1745,1750 ----
*************** lto_read_decls (struct lto_file_decl_dat
*** 1767,1772 ****
--- 1760,1773 ----
  		    vec_safe_push (tree_with_vars, t);
  		}
  	    }
+ 
+ 	  /* Register DECLs with the debuginfo machinery.  */
+ 	  while (!dref_queue.is_empty ())
+ 	    {
+ 	      dref_entry e = dref_queue.pop ();
+ 	      debug_hooks->register_external_die (e.decl, e.sym, e.off);
+ 	    }
+ 
  	  if (seen_type)
  	    num_type_scc_trees += len;
  	}
Index: trunk/gcc/config/darwin.c
===================================================================
*** trunk.orig/gcc/config/darwin.c	2015-08-27 16:29:15.321199088 +0200
--- trunk/gcc/config/darwin.c	2015-08-27 16:30:06.005665186 +0200
*************** static int darwin_dwarf_label_counter;
*** 2814,2820 ****
  
  void
  darwin_asm_output_dwarf_delta (FILE *file, int size,
! 			       const char *lab1, const char *lab2)
  {
    int islocaldiff = (lab1[0] == '*' && lab1[1] == 'L'
  		     && lab2[0] == '*' && lab2[1] == 'L');
--- 2814,2821 ----
  
  void
  darwin_asm_output_dwarf_delta (FILE *file, int size,
! 			       const char *lab1, const char *lab2,
! 			       HOST_WIDE_INT offset)
  {
    int islocaldiff = (lab1[0] == '*' && lab1[1] == 'L'
  		     && lab2[0] == '*' && lab2[1] == 'L');
*************** darwin_asm_output_dwarf_delta (FILE *fil
*** 2828,2833 ****
--- 2829,2836 ----
    assemble_name_raw (file, lab1);
    fprintf (file, "-");
    assemble_name_raw (file, lab2);
+   if (offset != 0)
+     fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
    if (islocaldiff)
      fprintf (file, "\n\t%s L$set$%d", directive, darwin_dwarf_label_counter++);
  }
*************** darwin_asm_output_dwarf_delta (FILE *fil
*** 2839,2845 ****
  
  void
  darwin_asm_output_dwarf_offset (FILE *file, int size, const char * lab,
! 				section *base)
  {
    char sname[64];
    int namelen;
--- 2842,2848 ----
  
  void
  darwin_asm_output_dwarf_offset (FILE *file, int size, const char * lab,
! 				HOST_WIDE_INT offset, section *base)
  {
    char sname[64];
    int namelen;
*************** darwin_asm_output_dwarf_offset (FILE *fi
*** 2850,2856 ****
  
    namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
    sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
!   darwin_asm_output_dwarf_delta (file, size, lab, sname);
  }
  
  /* Called from the within the TARGET_ASM_FILE_START for each target.  */
--- 2853,2859 ----
  
    namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
    sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
!   darwin_asm_output_dwarf_delta (file, size, lab, sname, offset);
  }
  
  /* Called from the within the TARGET_ASM_FILE_START for each target.  */
Index: trunk/gcc/config/darwin.h
===================================================================
*** trunk.orig/gcc/config/darwin.h	2015-08-27 16:29:15.322199097 +0200
--- trunk/gcc/config/darwin.h	2015-08-27 16:30:06.006665195 +0200
*************** enum machopic_addr_class {
*** 826,835 ****
       ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr)
  
  #define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2)  \
!   darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2)
  
! #define ASM_OUTPUT_DWARF_OFFSET(FILE,SIZE,LABEL,BASE)  \
!   darwin_asm_output_dwarf_offset (FILE, SIZE, LABEL, BASE)
  
  #define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(ASM_OUT_FILE, ENCODING, SIZE, ADDR, DONE)	\
        if (ENCODING == ASM_PREFERRED_EH_DATA_FORMAT (2, 1)) {				\
--- 826,835 ----
       ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr)
  
  #define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2)  \
!   darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2, 0)
  
! #define ASM_OUTPUT_DWARF_OFFSET(FILE,SIZE,LABEL,OFFSET,BASE)  \
!   darwin_asm_output_dwarf_offset (FILE, SIZE, LABEL, OFFSET, BASE)
  
  #define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(ASM_OUT_FILE, ENCODING, SIZE, ADDR, DONE)	\
        if (ENCODING == ASM_PREFERRED_EH_DATA_FORMAT (2, 1)) {				\
Index: trunk/gcc/config/ia64/ia64.h
===================================================================
*** trunk.orig/gcc/config/ia64/ia64.h	2015-08-27 16:29:15.322199097 +0200
--- trunk/gcc/config/ia64/ia64.h	2015-08-27 16:30:06.006665195 +0200
*************** do {									\
*** 1583,1593 ****
  /* Use section-relative relocations for debugging offsets.  Unlike other
     targets that fake this by putting the section VMA at 0, IA-64 has
     proper relocations for them.  */
! #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL, SECTION)	\
    do {								\
      fputs (integer_asm_op (SIZE, FALSE), FILE);			\
      fputs ("@secrel(", FILE);					\
      assemble_name (FILE, LABEL);				\
      fputc (')', FILE);						\
    } while (0)
  
--- 1583,1595 ----
  /* Use section-relative relocations for debugging offsets.  Unlike other
     targets that fake this by putting the section VMA at 0, IA-64 has
     proper relocations for them.  */
! #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL, OFFSET, SECTION) \
    do {								\
      fputs (integer_asm_op (SIZE, FALSE), FILE);			\
      fputs ("@secrel(", FILE);					\
      assemble_name (FILE, LABEL);				\
+     if (offset != 0)						\
+       fprintf (FILE, "+" HOST_WIDE_INT_PRINT_DEC, OFFSET);	\
      fputc (')', FILE);						\
    } while (0)
  
Index: trunk/gcc/doc/tm.texi.in
===================================================================
*** trunk.orig/gcc/doc/tm.texi.in	2015-08-27 16:29:15.323199107 +0200
--- trunk/gcc/doc/tm.texi.in	2015-08-27 16:30:06.007665205 +0200
*************** between the two given labels in system d
*** 7020,7029 ****
  slots on IA64 VMS, using an integer of the given size.
  @end defmac
  
! @defmac ASM_OUTPUT_DWARF_OFFSET (@var{stream}, @var{size}, @var{label}, @var{section})
  A C statement to issue assembly directives that create a
! section-relative reference to the given @var{label}, using an integer of the
! given @var{size}.  The label is known to be defined in the given @var{section}.
  @end defmac
  
  @defmac ASM_OUTPUT_DWARF_PCREL (@var{stream}, @var{size}, @var{label})
--- 7020,7030 ----
  slots on IA64 VMS, using an integer of the given size.
  @end defmac
  
! @defmac ASM_OUTPUT_DWARF_OFFSET (@var{stream}, @var{size}, @var{label}, @var{offset}, @var{section})
  A C statement to issue assembly directives that create a
! section-relative reference to the given @var{label} plus @var{offset}, using
! an integer of the given @var{size}.  The label is known to be defined in the
! given @var{section}.
  @end defmac
  
  @defmac ASM_OUTPUT_DWARF_PCREL (@var{stream}, @var{size}, @var{label})
Index: trunk/gcc/tree-streamer-in.c
===================================================================
*** trunk.orig/gcc/tree-streamer-in.c	2015-08-27 16:29:15.324199116 +0200
--- trunk/gcc/tree-streamer-in.c	2015-08-27 16:30:06.008665214 +0200
*************** lto_input_ts_decl_common_tree_pointers (
*** 706,711 ****
--- 706,712 ----
    /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
       for early inlining so drop it on the floor instead of ICEing in
       dwarf2out.c.  */
+   DECL_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
  
    if ((TREE_CODE (expr) == VAR_DECL
         || TREE_CODE (expr) == PARM_DECL)
Index: trunk/gcc/tree-streamer-out.c
===================================================================
*** trunk.orig/gcc/tree-streamer-out.c	2015-08-27 16:29:15.324199116 +0200
--- trunk/gcc/tree-streamer-out.c	2015-08-27 16:30:06.008665214 +0200
*************** write_ts_decl_common_tree_pointers (stru
*** 619,624 ****
--- 619,625 ----
    /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
       for early inlining so drop it on the floor instead of ICEing in
       dwarf2out.c.  */
+   stream_write_tree (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p);
  
    if ((TREE_CODE (expr) == VAR_DECL
         || TREE_CODE (expr) == PARM_DECL)
Index: trunk/gcc/config/darwin-protos.h
===================================================================
*** trunk.orig/gcc/config/darwin-protos.h	2015-08-27 16:29:15.325199125 +0200
--- trunk/gcc/config/darwin-protos.h	2015-08-27 16:30:06.008665214 +0200
*************** extern void darwin_globalize_label (FILE
*** 91,99 ****
  extern void darwin_assemble_visibility (tree, int);
  
  extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *,
! 					   const char *);
  extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *,
! 					    section *);
  
  extern void darwin_asm_declare_object_name (FILE *, const char *, tree);
  extern void darwin_asm_declare_constant_name (FILE *, const char *,
--- 91,99 ----
  extern void darwin_assemble_visibility (tree, int);
  
  extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *,
! 					   const char *, HOST_WIDE_INT);
  extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *,
! 					    HOST_WIDE_INT, section *);
  
  extern void darwin_asm_declare_object_name (FILE *, const char *, tree);
  extern void darwin_asm_declare_constant_name (FILE *, const char *,
Index: trunk/gcc/config/i386/cygming.h
===================================================================
*** trunk.orig/gcc/config/i386/cygming.h	2015-08-27 16:29:15.325199125 +0200
--- trunk/gcc/config/i386/cygming.h	2015-08-27 16:30:06.008665214 +0200
*************** along with GCC; see the file COPYING3.
*** 97,109 ****
  /* Use section relative relocations for debugging offsets.  Unlike
     other targets that fake this by putting the section VMA at 0, PE
     won't allow it.  */
! #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL, SECTION)	\
    do {								\
      switch (SIZE)						\
        {								\
        case 4:							\
  	fputs ("\t.secrel32\t", FILE);				\
  	assemble_name (FILE, LABEL);				\
  	break;							\
        case 8:							\
  	/* This is a hack.  There is no 64-bit section relative	\
--- 97,111 ----
  /* Use section relative relocations for debugging offsets.  Unlike
     other targets that fake this by putting the section VMA at 0, PE
     won't allow it.  */
! #define ASM_OUTPUT_DWARF_OFFSET(FILE, SIZE, LABEL, OFFSET, SECTION) \
    do {								\
      switch (SIZE)						\
        {								\
        case 4:							\
  	fputs ("\t.secrel32\t", FILE);				\
  	assemble_name (FILE, LABEL);				\
+ 	if (offset != 0)					\
+ 	  fprintf (FILE, "+" HOST_WIDE_INT_PRINT_DEC, offset)	\
  	break;							\
        case 8:							\
  	/* This is a hack.  There is no 64-bit section relative	\
*************** along with GCC; see the file COPYING3.
*** 113,118 ****
--- 115,122 ----
  	   Fake the 64-bit offset by zero-extending it.  */	\
  	fputs ("\t.secrel32\t", FILE);				\
  	assemble_name (FILE, LABEL);				\
+ 	if (offset != 0)					\
+ 	  fprintf (FILE, "+" HOST_WIDE_INT_PRINT_DEC, offset)	\
  	fputs ("\n\t.long\t0", FILE);				\
  	break;							\
        default:							\
Index: trunk/gcc/cgraphunit.c
===================================================================
*** trunk.orig/gcc/cgraphunit.c	2015-08-27 16:27:53.211444237 +0200
--- trunk/gcc/cgraphunit.c	2015-08-27 16:32:44.166120343 +0200
*************** symbol_table::compile (void)
*** 2322,2328 ****
  
    /* Clean up anything that needs cleaning up after initial debug
       generation.  */
!   (*debug_hooks->early_finish) ();
  
    timevar_push (TV_CGRAPHOPT);
    if (pre_ipa_mem_report)
--- 2322,2328 ----
  
    /* Clean up anything that needs cleaning up after initial debug
       generation.  */
!   (*debug_hooks->early_finish) (main_input_filename);
  
    timevar_push (TV_CGRAPHOPT);
    if (pre_ipa_mem_report)
Index: trunk/gcc/dbxout.c
===================================================================
*** trunk.orig/gcc/dbxout.c	2015-08-27 16:29:15.326199134 +0200
--- trunk/gcc/dbxout.c	2015-08-27 16:30:06.010665232 +0200
*************** const struct gcc_debug_hooks dbx_debug_h
*** 354,360 ****
  {
    dbxout_init,
    dbxout_finish,
!   debug_nothing_void,
    debug_nothing_void,
    debug_nothing_int_charstar,
    debug_nothing_int_charstar,
--- 354,360 ----
  {
    dbxout_init,
    dbxout_finish,
!   debug_nothing_charstar,
    debug_nothing_void,
    debug_nothing_int_charstar,
    debug_nothing_int_charstar,
*************** const struct gcc_debug_hooks dbx_debug_h
*** 380,385 ****
--- 380,387 ----
    dbxout_late_global_decl,		 /* late_global_decl */
    dbxout_type_decl,			 /* type_decl */
    debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
+   debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+   debug_nothing_tree_charstar_uhwi,	 /* register_external_die */
    debug_nothing_tree,		         /* deferred_inline_function */
    debug_nothing_tree,		         /* outlining_inline_function */
    debug_nothing_rtx_code_label,	         /* label */
Index: trunk/gcc/debug.c
===================================================================
*** trunk.orig/gcc/debug.c	2015-08-27 16:29:15.327199143 +0200
--- trunk/gcc/debug.c	2015-08-27 16:30:06.010665232 +0200
*************** const struct gcc_debug_hooks do_nothing_
*** 28,34 ****
  {
    debug_nothing_charstar,
    debug_nothing_charstar,
!   debug_nothing_void,			/* early_finish */
    debug_nothing_void,
    debug_nothing_int_charstar,
    debug_nothing_int_charstar,
--- 28,34 ----
  {
    debug_nothing_charstar,
    debug_nothing_charstar,
!   debug_nothing_charstar,			/* early_finish */
    debug_nothing_void,
    debug_nothing_int_charstar,
    debug_nothing_int_charstar,
*************** const struct gcc_debug_hooks do_nothing_
*** 50,55 ****
--- 50,57 ----
    debug_nothing_tree,	         	 /* late_global_decl */
    debug_nothing_tree_int,		 /* type_decl */
    debug_nothing_tree_tree_tree_bool,	 /* imported_module_or_decl */
+   debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */
+   debug_nothing_tree_charstar_uhwi,	 /* register_external_die */
    debug_nothing_tree,		         /* deferred_inline_function */
    debug_nothing_tree,		         /* outlining_inline_function */
    debug_nothing_rtx_code_label,	         /* label */
*************** debug_nothing_tree_int (tree decl ATTRIB
*** 139,141 ****
--- 141,156 ----
  			int local ATTRIBUTE_UNUSED)
  {
  }
+ 
+ bool
+ debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ 					unsigned HOST_WIDE_INT *)
+ {
+   return false;
+ }
+ 
+ void
+ debug_nothing_tree_charstar_uhwi (tree, const char *,
+ 				  unsigned HOST_WIDE_INT)
+ {
+ }
Index: trunk/gcc/debug.h
===================================================================
*** trunk.orig/gcc/debug.h	2015-08-27 16:29:15.327199143 +0200
--- trunk/gcc/debug.h	2015-08-27 16:30:06.010665232 +0200
*************** struct gcc_debug_hooks
*** 31,37 ****
    void (* finish) (const char *main_filename);
  
    /* Run cleanups necessary after early debug generation.  */
!   void (* early_finish) (void);
  
    /* Called from cgraph_optimize before starting to assemble
       functions/variables/toplevel asms.  */
--- 31,37 ----
    void (* finish) (const char *main_filename);
  
    /* Run cleanups necessary after early debug generation.  */
!   void (* early_finish) (const char *main_filename);
  
    /* Called from cgraph_optimize before starting to assemble
       functions/variables/toplevel asms.  */
*************** struct gcc_debug_hooks
*** 146,151 ****
--- 146,159 ----
    void (* imported_module_or_decl) (tree decl, tree name,
  				    tree context, bool child);
  
+   /* Return true if a DIE for the tree is available and return a symbol
+      and offset that can be used to refer to it externally.  */
+   bool (* die_ref_for_decl) (tree, const char **, unsigned HOST_WIDE_INT *);
+ 
+   /* Early debug information for the tree is available at symbol plus
+      offset externally.  */
+   void (* register_external_die) (tree, const char *, unsigned HOST_WIDE_INT);
+ 
    /* DECL is an inline function, whose body is present, but which is
       not being output at this point.  */
    void (* deferred_inline_function) (tree decl);
*************** extern void debug_nothing_tree_tree_tree
*** 200,205 ****
--- 208,217 ----
  extern bool debug_true_const_tree (const_tree);
  extern void debug_nothing_rtx_insn (rtx_insn *);
  extern void debug_nothing_rtx_code_label (rtx_code_label *);
+ extern bool debug_false_tree_charstarstar_uhwistar (tree, const char **,
+ 						    unsigned HOST_WIDE_INT *);
+ extern void debug_nothing_tree_charstar_uhwi (tree, const char *,
+ 					      unsigned HOST_WIDE_INT);
  
  /* Hooks for various debug formats.  */
  extern const struct gcc_debug_hooks do_nothing_debug_hooks;
Index: trunk/gcc/passes.c
===================================================================
*** trunk.orig/gcc/passes.c	2015-08-27 16:29:15.327199143 +0200
--- trunk/gcc/passes.c	2015-08-27 16:30:41.416990896 +0200
*************** rest_of_decl_compilation (tree decl,
*** 318,324 ****
        && !decl_function_context (decl)
        && !current_function_decl
        && DECL_SOURCE_LOCATION (decl) != BUILTINS_LOCATION
!       && !decl_type_context (decl)
        /* Avoid confusing the debug information machinery when there are
  	 errors.  */
        && !seen_error ())
--- 318,332 ----
        && !decl_function_context (decl)
        && !current_function_decl
        && DECL_SOURCE_LOCATION (decl) != BUILTINS_LOCATION
!       && (!decl_type_context (decl)
! 	  /* If we created a varpool node for the decl make sure to
! 	     call early_global_decl.  Otherwise we miss changes
! 	     introduced by member definitions like
! 	       struct A { static int staticdatamember; };
! 	       int A::staticdatamember;
! 	     and thus have incomplete early debug.  */
! 	  || (TREE_CODE (decl) == VAR_DECL
! 	      && TREE_STATIC (decl) && !DECL_EXTERNAL (decl)))
        /* Avoid confusing the debug information machinery when there are
  	 errors.  */
        && !seen_error ())
Index: trunk/gcc/cp/semantics.c
===================================================================
*** trunk.orig/gcc/cp/semantics.c	2015-08-27 16:29:15.329199162 +0200
--- trunk/gcc/cp/semantics.c	2015-08-27 16:30:06.012665251 +0200
*************** finish_member_declaration (tree decl)
*** 2962,2976 ****
     translation units which include the PCH file.  */
  
  void
! note_decl_for_pch (tree decl)
  {
    gcc_assert (pch_file);
  
    /* There's a good chance that we'll have to mangle names at some
       point, even if only for emission in debugging information.  */
    if (VAR_OR_FUNCTION_DECL_P (decl)
        && !processing_template_decl)
      mangle_decl (decl);
  }
  
  /* Finish processing a complete template declaration.  The PARMS are
--- 2962,2982 ----
     translation units which include the PCH file.  */
  
  void
! note_decl_for_pch (tree)
  {
    gcc_assert (pch_file);
  
+   /* ???  This changes debug info with/without PCH as DW_AT_linkage_name
+      attributes are added at different times (early when with PCH
+      or late, via pending assembler names, when without PCH).
+      See g++.dg/pch/system-[12].C.  */
+ #if 0
    /* There's a good chance that we'll have to mangle names at some
       point, even if only for emission in debugging information.  */
    if (VAR_OR_FUNCTION_DECL_P (decl)
        && !processing_template_decl)
      mangle_decl (decl);
+ #endif
  }
  
  /* Finish processing a complete template declaration.  The PARMS are
Index: trunk/gcc/testsuite/lib/lto.exp
===================================================================
*** trunk.orig/gcc/testsuite/lib/lto.exp	2015-08-27 16:29:15.329199162 +0200
--- trunk/gcc/testsuite/lib/lto.exp	2015-08-27 16:30:06.012665251 +0200
*************** proc lto_prune_warns { text } {
*** 39,44 ****
--- 39,47 ----
      regsub -all "(^|\n)\[ \t\]*\[\(\]file \[^\n\]* value=\[^\n\]*; file \[^\n\]* value=\[^\n\]*\[)\];" $text "" text
      regsub -all "(^|\n)\[ \t\]*\[^\n\]* definition taken" $text "" text
  
+     # Temporary measure against early-debug ld complaints
+     regsub -all "(^|\n)\[^\n\]*: plugin needed to handle lto object\[^\n\]*" $text "" text
+ 
      verbose "lto_prune_warns: exit: $text" 2
  
      return $text
Index: trunk/gcc/testsuite/lib/prune.exp
===================================================================
*** trunk.orig/gcc/testsuite/lib/prune.exp	2015-08-27 16:29:15.329199162 +0200
--- trunk/gcc/testsuite/lib/prune.exp	2015-08-27 16:30:06.013665260 +0200
*************** proc prune_gcc_output { text } {
*** 68,73 ****
--- 68,76 ----
      # Ignore harmless warnings from Xcode 4.0.
      regsub -all "(^|\n)\[^\n\]*ld: warning: could not create compact unwind for\[^\n\]*" $text "" text
  
+     # Temporary measure against early-debug ld complaints
+     regsub -all "(^|\n)\[^\n\]*: plugin needed to handle lto object\[^\n\]*" $text "" text
+ 
      #send_user "After:$text\n"
  
      return $text
Index: trunk/gcc/testsuite/lib/gcc-dg.exp
===================================================================
*** trunk.orig/gcc/testsuite/lib/gcc-dg.exp	2015-08-27 16:29:15.330199171 +0200
--- trunk/gcc/testsuite/lib/gcc-dg.exp	2015-08-27 16:30:06.013665260 +0200
*************** proc gcc-dg-prune { system text } {
*** 346,351 ****
--- 346,354 ----
  	return "::unsupported::memory full"
      }
  
+     # Temporary measure against early-debug ld complaints
+     regsub -all "(^|\n)\[^\n\]*: plugin needed to handle lto object\[^\n\]*" $text "" text
+ 
      return $text
  }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]