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] Updated LTO early debug patch


So the state below now will pass LTO bootstrap (fingers crossing,
stage3 running) as well as regular bootstrap.  Iff I didn't break
sth in the last minute.  You need up-to-date trunk (watch out,
fortran seems to be broken) to pull the fixes for trunk LTO bootstrap.

Richard.



Index: trunk/gcc/dwarf2asm.c
===================================================================
*** trunk.orig/gcc/dwarf2asm.c	2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/dwarf2asm.c	2015-08-31 16:03:09.786994930 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/dwarf2asm.h	2015-08-31 16:03:09.786994930 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/dwarf2out.c	2015-08-31 16:03:09.797995028 +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,9549 ----
        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);
+ #ifdef ASM_WEAKEN_LABEL
+       /* We prefer a .weak because that handles duplicates from duplicate
+          archive members in a graceful way.  */
+       ASM_WEAKEN_LABEL (asm_out_file, oldsym);
+ #else
+       targetm.asm_out.globalize_label (asm_out_file, oldsym);
+ #endif
+       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
--- 16436,16448 ----
    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
*************** tree_add_const_value_attribute (dw_die_r
*** 16393,16404 ****
    init = t;
    gcc_assert (!DECL_P (init));
  
!   rtl = rtl_for_decl_init (init, type);
!   if (rtl)
!     return add_const_value_attribute (die, rtl);
    /* If the host and target are sane, try harder.  */
!   else if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
! 	   && initializer_constant_valid_p (init, type))
      {
        HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (init));
        if (size > 0 && (int) size == size)
--- 16675,16692 ----
    init = t;
    gcc_assert (!DECL_P (init));
  
!   if (!early_dwarf)
!     {
!       /* For early dwarf we may not create references to possibly optimized
!          out objects as with early LTO resolve_addr will _not_ fix this
! 	 up late.  */
!       rtl = rtl_for_decl_init (init, type);
!       if (rtl)
! 	return add_const_value_attribute (die, rtl);
!     }
    /* If the host and target are sane, try harder.  */
!   if (CHAR_BIT == 8 && BITS_PER_UNIT == 8
!       && initializer_constant_valid_p (init, type))
      {
        HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (init));
        if (size > 0 && (int) size == size)
*************** add_scalar_info (dw_die_ref die, enum dw
*** 16779,16784 ****
--- 17067,17085 ----
        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
--- 18339,18347 ----
  	 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
--- 18610,18615 ----
*************** 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
--- 18682,18740 ----
      }
  }
  
! /* 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 ****
--- 18957,18972 ----
        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 ****
--- 18990,18998 ----
      {
        /* 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);
--- 19433,19438 ----
*************** 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;
      }
  }
  
--- 19441,19446 ----
*************** 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);
--- 19739,19764 ----
        && (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 ****
--- 19994,20013 ----
      {
        /* 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 ****
--- 21111,21141 ----
      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;
  
--- 21148,21171 ----
      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)
--- 21178,21222 ----
  					     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 ****
--- 21619,21627 ----
  
        /* 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.  */
--- 21635,21645 ----
  	}
  
        /* 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 ****
--- 21706,21717 ----
        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 ****
--- 21723,21730 ----
        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 ****
--- 21822,21837 ----
  	  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
--- 21848,21863 ----
  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,21992 ****
  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);
--- 22172,22769 ----
  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);
*************** append_entry_to_tmpl_value_parm_die_tabl
*** 22105,22110 ****
--- 22882,22889 ----
    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 ****
--- 22913,22920 ----
    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);
      }
  }
  
--- 22930,22950 ----
  {
    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 ****
--- 22962,22976 ----
    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.  */
--- 24000,24069 ----
        }
  }
  
! /* 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);
--- 24071,24193 ----
            = 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 ****
--- 24643,24658 ----
        }
  }
  
+ /* 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.  */
--- 24668,24675 ----
  
    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 ****
--- 24681,24696 ----
  	      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);
--- 24935,24942 ----
  	  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
--- 26004,26195 ----
    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 ());
--- 26199,26210 ----
    }
  #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)
--- 26474,26497 ----
     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
--- 26509,26718 ----
      }
    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-31 16:02:26.049605208 +0200
--- trunk/gcc/gimplify.c	2015-08-31 16:03:09.798995037 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-streamer-in.c	2015-08-31 16:03:09.798995037 +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
*** 1289,1294 ****
--- 1290,1297 ----
  }
  
  
+ 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
*** 1309,1314 ****
--- 1312,1334 ----
        && 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 *
*** 1470,1475 ****
--- 1490,1502 ----
      {
        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-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-streamer-out.c	2015-08-31 16:03:09.799995046 +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
*** 377,382 ****
--- 378,403 ----
  			 (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_
*** 750,755 ****
--- 771,777 ----
        /* 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)
*************** DFS::DFS_write_tree_body (struct output_
*** 864,874 ****
--- 886,900 ----
  	 handle - those that represent inlined function scopes.
  	 For the drop rest them on the floor instead of ICEing
  	 in dwarf2out.c.  */
+ #if 1
        if (inlined_function_outer_scope_p (expr))
  	{
  	  tree ultimate_origin = block_ultimate_origin (expr);
  	  DFS_follow_tree_edge (ultimate_origin);
  	}
+ #else
+       DFS_follow_tree_edge (BLOCK_ABSTRACT_ORIGIN (expr));
+ #endif
        /* Do not follow BLOCK_NONLOCALIZED_VARS.  We cannot handle debug
  	 information for early inlined BLOCKs so drop it on the floor instead
  	 of ICEing in dwarf2out.c.  */
Index: trunk/gcc/lto-streamer.h
===================================================================
*** trunk.orig/gcc/lto-streamer.h	2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-streamer.h	2015-08-31 16:03:09.799995046 +0200
*************** DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, typ
*** 1220,1223 ****
--- 1220,1232 ----
  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-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-wrapper.c	2015-08-31 16:03:09.800995055 +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]);
*************** 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");
--- 900,907 ----
    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 ****
--- 920,926 ----
    /* 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,
--- 955,961 ----
  				  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
      {
--- 1156,1260 ----
          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");
+   char last_archive[1024];
+   last_archive[0] = '\0';
+   for (i = 0; i < ltoobj_argc; ++i)
+     {
+       char *p;
+       if ((p = strrchr (ltoobj_argv[i], '@')))
+ 	{
+ 	  /* Add archives only once.  */
+ 	  if (strncmp (last_archive, ltoobj_argv[i], p - ltoobj_argv[i]) == 0
+ 	      && last_archive[p - ltoobj_argv[i]] == '\0')
+ 	    continue;
+ 	  strncpy (last_archive, ltoobj_argv[i], p - ltoobj_argv[i]);
+ 	  last_archive[p - ltoobj_argv[i]] = '\0';
+ 	  fprintf (script, "INPUT(%s)\n", last_archive);
+ 	}
+       else
+ 	fprintf (script, "INPUT(%s)\n", ltoobj_argv[i]);
+     }
+   fprintf (script, "SECTIONS {\n");
+   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");
+   fprintf (script, "}\n");
+   fclose (script);
+     }
+ 
+     {
+   /* 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,--whole-archive");
+   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 (lto_mode == LTO_MODE_LTO)
      {
+       /* ???  We'd like to put the linker script creating debug_obj
+          here directly to avoid the extra I/O and to handle archives
+ 	 more optimistically (drop unused members early debug).  */
+       printf ("%s\n", debug_obj);
        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,1314 ****
--- 1401,1414 ----
  	  for (i = 0; i < nr; ++i)
  	    maybe_unlink (input_names[i]);
  	}
+       /* ???  We'd like to put the linker script creating debug_obj
+          here directly to avoid the extra I/O and to handle archives
+ 	 more optimistically (drop unused members early debug).  */
+       printf ("%s\n", debug_obj);
+       free (debug_obj);
+       debug_obj = NULL;
+       free (linker_script);
+       linker_script = NULL;
        for (i = 0; i < nr; ++i)
  	{
  	  fputs (output_names[i], stdout);
Index: trunk/gcc/lto/lto.c
===================================================================
*** trunk.orig/gcc/lto/lto.c	2015-08-31 16:02:04.394412282 +0200
--- trunk/gcc/lto/lto.c	2015-08-31 16:03:09.800995055 +0200
*************** unify_scc (struct data_in *data_in, unsi
*** 1629,1634 ****
--- 1629,1637 ----
  	      ggc_free (scc->entries[i]);
  	    }
  
+ 	  /* Drop DIE references.  */
+ 	  dref_queue.truncate (0);
+ 
  	  break;
  	}
  
*************** lto_read_decls (struct lto_file_decl_dat
*** 1705,1711 ****
  	  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;
  
--- 1708,1713 ----
*************** lto_read_decls (struct lto_file_decl_dat
*** 1745,1760 ****
  	      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
--- 1747,1752 ----
*************** lto_read_decls (struct lto_file_decl_dat
*** 1770,1775 ****
--- 1762,1775 ----
  		    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-31 16:02:26.049605208 +0200
--- trunk/gcc/config/darwin.c	2015-08-31 16:03:09.801995064 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/config/darwin.h	2015-08-31 16:03:09.801995064 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/config/ia64/ia64.h	2015-08-31 16:03:09.801995064 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/doc/tm.texi.in	2015-08-31 16:03:09.802995073 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/tree-streamer-in.c	2015-08-31 16:03:09.802995073 +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)
*************** lto_input_ts_block_tree_pointers (struct
*** 918,923 ****
--- 919,927 ----
       function scopes.  For the rest them on the floor instead of ICEing in
       dwarf2out.c.  */
    BLOCK_ABSTRACT_ORIGIN (expr) = stream_read_tree (ib, data_in);
+   if (BLOCK_ABSTRACT_ORIGIN (expr)
+       && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (expr)) == FUNCTION_DECL)
+     gcc_assert (!DECL_IS_BUILTIN (BLOCK_ABSTRACT_ORIGIN (expr)));
    /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
       for early inlined BLOCKs so drop it on the floor instead of ICEing in
       dwarf2out.c.  */
Index: trunk/gcc/tree-streamer-out.c
===================================================================
*** trunk.orig/gcc/tree-streamer-out.c	2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/tree-streamer-out.c	2015-08-31 16:03:09.803995081 +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)
*************** write_ts_block_tree_pointers (struct out
*** 800,812 ****
--- 801,818 ----
    /* Stream BLOCK_ABSTRACT_ORIGIN for the limited cases we can handle - those
       that represent inlined function scopes.
       For the rest them on the floor instead of ICEing in dwarf2out.c.  */
+ #if 1
    if (inlined_function_outer_scope_p (expr))
      {
        tree ultimate_origin = block_ultimate_origin (expr);
        stream_write_tree (ob, ultimate_origin, ref_p);
+       gcc_assert (!DECL_IS_BUILTIN (ultimate_origin));
      }
    else
      stream_write_tree (ob, NULL_TREE, ref_p);
+ #else
+   stream_write_tree (ob, BLOCK_ABSTRACT_ORIGIN (expr), ref_p);
+ #endif
    /* Do not stream BLOCK_NONLOCALIZED_VARS.  We cannot handle debug information
       for early inlined BLOCKs so drop it on the floor instead of ICEing in
       dwarf2out.c.  */
Index: trunk/gcc/config/darwin-protos.h
===================================================================
*** trunk.orig/gcc/config/darwin-protos.h	2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/config/darwin-protos.h	2015-08-31 16:03:09.803995081 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/config/i386/cygming.h	2015-08-31 16:03:09.803995081 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/cgraphunit.c	2015-08-31 16:03:09.803995081 +0200
*************** analyze_functions (bool first_time)
*** 1135,1142 ****
  	     at looking at optimized away DECLs, since
  	     late_global_decl will subsequently be called from the
  	     contents of the now pruned symbol table.  */
  	  if (!decl_function_context (node->decl))
! 	    (*debug_hooks->late_global_decl) (node->decl);
  
  	  node->remove ();
  	  continue;
--- 1135,1157 ----
  	     at looking at optimized away DECLs, since
  	     late_global_decl will subsequently be called from the
  	     contents of the now pruned symbol table.  */
+ #if 0
  	  if (!decl_function_context (node->decl))
! 	    {
! 	      /* ???  If we are about to generate LTO bytecode
! 	         we can't have non-early DIEs because those may
! 		 refer to decls we'll never output via
! 		 loc_list_from_tree -> rtl_for_decl_location
! 		 which via make_decl_rtl_for_debug relies on
! 		 resolve_addr to remove referenes to not output
! 		 symbols.  Exactly what we do _not_ want here btw!
! 		 We want the early path which only uses
! 		 tree_add_const_value_attribute_for_decl.  But
! 		 we should have visited this decl early anyway.
! 		 Thus do nothing now (or invent a new hook).  */
! 	      (*debug_hooks->late_global_decl) (node->decl);
! 	    }
! #endif
  
  	  node->remove ();
  	  continue;
*************** symbol_table::finalize_compilation_unit
*** 2492,2498 ****
  
        /* Clean up anything that needs cleaning up after initial debug
  	 generation.  */
!       (*debug_hooks->early_finish) ();
      }
  
    /* Finally drive the pass manager.  */
--- 2507,2513 ----
  
        /* Clean up anything that needs cleaning up after initial debug
  	 generation.  */
!       (*debug_hooks->early_finish) (main_input_filename);
      }
  
    /* Finally drive the pass manager.  */
Index: trunk/gcc/dbxout.c
===================================================================
*** trunk.orig/gcc/dbxout.c	2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/dbxout.c	2015-08-31 16:03:09.804995090 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/debug.c	2015-08-31 16:03:09.804995090 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/debug.h	2015-08-31 16:03:09.804995090 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/passes.c	2015-08-31 16:03:09.804995090 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/cp/semantics.c	2015-08-31 16:03:09.805995099 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/testsuite/lib/lto.exp	2015-08-31 16:03:09.806995108 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/testsuite/lib/prune.exp	2015-08-31 16:03:09.806995108 +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-31 16:02:26.049605208 +0200
--- trunk/gcc/testsuite/lib/gcc-dg.exp	2015-08-31 16:03:09.806995108 +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: trunk/gcc/lto-cgraph.c
===================================================================
*** trunk.orig/gcc/lto-cgraph.c	2015-08-31 16:02:26.049605208 +0200
--- trunk/gcc/lto-cgraph.c	2015-08-31 16:03:09.806995108 +0200
*************** compute_ltrans_boundary (lto_symtab_enco
*** 895,908 ****
        add_node_to (encoder, node, true);
        lto_set_symtab_encoder_in_partition (encoder, node);
        create_references (encoder, node);
-       /* For proper debug info, we need to ship the origins, too.  */
-       if (DECL_ABSTRACT_ORIGIN (node->decl))
- 	{
- 	  struct cgraph_node *origin_node
- 	  = cgraph_node::get_create (DECL_ABSTRACT_ORIGIN (node->decl));
- 	  origin_node->used_as_abstract_origin = true;
- 	  add_node_to (encoder, origin_node, true);
- 	}
      }
    for (lsei = lsei_start_variable_in_partition (in_encoder);
         !lsei_end_p (lsei); lsei_next_variable_in_partition (&lsei))
--- 895,900 ----
*************** compute_ltrans_boundary (lto_symtab_enco
*** 914,926 ****
        lto_set_symtab_encoder_in_partition (encoder, vnode);
        lto_set_symtab_encoder_encode_initializer (encoder, vnode);
        create_references (encoder, vnode);
-       /* For proper debug info, we need to ship the origins, too.  */
-       if (DECL_ABSTRACT_ORIGIN (vnode->decl))
- 	{
- 	  varpool_node *origin_node
- 	    = varpool_node::get (DECL_ABSTRACT_ORIGIN (vnode->decl));
- 	  lto_set_symtab_encoder_in_partition (encoder, origin_node);
- 	}
      }
    /* Pickle in also the initializer of all referenced readonly variables
       to help folding.  Constant pool variables are not shared, so we must
--- 906,911 ----


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