Patchwork [google/gcc-4_7] Backport Fission patches from trunk (issue6405076)

login
register
mail settings
Submitter Cary Coutant
Date July 23, 2012, 9:21 p.m.
Message ID <20120723212127.3FAC0E1504@ccoutant.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/172749/
State New
Headers show

Comments

Cary Coutant - July 23, 2012, 9:21 p.m.
This patch is for the google/gcc-4_7 branch.  It backports five Fission
patches from trunk, with two minor differences:

  - The DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes are
    both generated, and provide the offset to the corresponding
    pubnames/pubtypes section.  This is done for compatibility
    with the gold linker, which does not yet support the flag
    form.

  - Enumerator names are placed in .debug_pubtypes instead of
    .debug_pubnames.  In trunk with -fdebug_types_section enabled,
    enumerators were missing from the pubnames table.

Tested by bootstrap and regression testing.


2012-07-23  Cary Coutant  <ccoutant@google.com>
    
    Backport Fission patches from trunk at r188195, r188857, r189084,
    r189094, and r189392.
    
    2012-07-09  Sterling Augustine  <saugustine@google.com>
    
    cp/
    	* error.c (lang_decl_name): Use TFF_UNQUALIFIED_NAME flag.
    testsuite/
    	* g++.dg/debug/dwarf2/pubnames-2.C: New.
    
    2012-06-29   Cary Coutant  <ccoutant@google.com>
    
    	* dwarf2out.c (add_pubname_string): Don't check for want_pubnames.
    	(gen_subprogram_die): Don't add pubname if want_pubnames is false.
    	(gen_variable_die): Likewise.
    	(gen_namespace_die): Likewise.
    
    2012-06-29  Sterling Augustine  <saugustine@google.com>
    
    	* dwarf2out.c (add_pubname): Add comment.
    	(add_pubtype): Fix indentation.
    	(gen_enumeration_type_die): Likewise.
    
    2012-06-21   Sterling Augustine  <saugustine@google.com>
    		 Cary Coutant  <ccoutant@google.com>
    
    	* dwarf2out.c (is_cu_die, is_namespace_die, is_class_die,
    	add_AT_pubnames, add_enumerator_pubname, want_pubnames): New functions.
    	(comdat_type_struct): New field 'skeleton_die'.
    	(breakout_comdat_types): Update it.
    	(add_pubname): Rework logic.  Call is_class_die, is_cu_die and
    	is_namespace_die.  Fix minor style violation.  Call want_pubnames.
    	(add_pubname_string): Call want_pubnames.
    	(add_pubtype): Rework logic for calculating type name.  Call
    	is_namespace_die.  Call want_pubnames.
    	(output_pubnames): Move conditional logic deciding when to produce the
    	section from dwarf2out_finish.  Use new skeleton_die field.
    	(base_type_die): Call add_pubtype.
    	(gen_enumeration_type_die): Unconditionally call add_pubtype.
    	(gen_subprogram_die): Adjust calls to add_pubname.
    	(gen_namespace_die): Call add_pubname_string.
    	(dwarf2out_finish): Call add_AT_pubnames; Move logic on when to
    	produce pubnames and pubtypes sections to output_pubnames.
    	(common.opt): New option '-gpubnames'.
    	(invoke.texi): Document it.
    
    2012-06-04  Sterling Augustine  <saugustine@google.com>
    
    c-family/
    	* c-pretty-print.h (pp_c_flag_gnu_v3): New enumerator.
    	* c-pretty-print.c (pp_c_specifier_qualifier_list): Check
    	it at both the start and end of the function.
    cp/
    	* error.c (dump_decl): Check pp_c_flag_gnu_v3.
    	(decl_as_dwarf_string, lang_decl_dwarf_name): New functions.
    	(lang_decl_name): Handle namespace decls.
    	* cp-tree.h: Declare decl_as_dwarf_string, lang_decl_dwarf_name.
    	* cp-lang.c: Call them.
    


--
This patch is available for review at http://codereview.appspot.com/6405076

Patch

diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index dc63f00..b596d3b 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -446,7 +446,7 @@  pp_c_specifier_qualifier_list (c_pretty_printer *pp, tree t)
 {
   const enum tree_code code = TREE_CODE (t);
 
-  if (TREE_CODE (t) != POINTER_TYPE)
+  if (!(pp->flags & pp_c_flag_gnu_v3) && code != POINTER_TYPE)
     pp_c_type_qualifier_list (pp, t);
   switch (code)
     {
@@ -494,6 +494,8 @@  pp_c_specifier_qualifier_list (c_pretty_printer *pp, tree t)
       pp_simple_type_specifier (pp, t);
       break;
     }
+  if ((pp->flags & pp_c_flag_gnu_v3) && code != POINTER_TYPE)
+    pp_c_type_qualifier_list (pp, t);
 }
 
 /* parameter-type-list:
diff --git a/gcc/c-family/c-pretty-print.h b/gcc/c-family/c-pretty-print.h
index 8d399dd..2f9f94a 100644
--- a/gcc/c-family/c-pretty-print.h
+++ b/gcc/c-family/c-pretty-print.h
@@ -30,7 +30,8 @@  along with GCC; see the file COPYING3.  If not see
 typedef enum
   {
      pp_c_flag_abstract = 1 << 1,
-     pp_c_flag_last_bit = 2
+     pp_c_flag_gnu_v3 = 1 << 2,
+     pp_c_flag_last_bit = 3
   } pp_c_pretty_print_flags;
 
 
diff --git a/gcc/common.opt b/gcc/common.opt
index 747dec9..ec94e86 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2408,6 +2408,14 @@  gmlt
 Common RejectNegative
 Generate debug information at level 1 with minimal line table
 
+gno-pubnames
+Common RejectNegative Var(debug_generate_pub_sections, 0) Init(-1)
+Don't generate DWARF pubnames and pubtypes sections.
+
+gpubnames
+Common RejectNegative Var(debug_generate_pub_sections, 1)
+Generate DWARF pubnames and pubtypes sections.
+
 gno-record-gcc-switches
 Common RejectNegative Var(dwarf_record_gcc_switches,0) Init(0)
 Don't record gcc command line switches in DWARF DW_AT_producer.
diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
index 6291398..04d24fc 100644
--- a/gcc/cp/cp-lang.c
+++ b/gcc/cp/cp-lang.c
@@ -164,11 +164,11 @@  cxx_dwarf_name (tree t, int verbosity)
       && (ANON_AGGRNAME_P (DECL_NAME (t)) || LAMBDANAME_P (DECL_NAME (t))))
     return NULL;
   if (verbosity >= 2)
-    return decl_as_string (t,
-			   TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME
-			   | TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS);
+    return decl_as_dwarf_string (t,
+                                 TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME
+                                 | TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS);
 
-  return cxx_printable_name (t, verbosity);
+  return lang_decl_dwarf_name (t, verbosity, false);
 }
 
 static enum classify_record
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a94c923..d328904 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5151,8 +5151,10 @@  extern const char *type_as_string		(tree, int);
 extern const char *type_as_string_translate	(tree, int);
 extern const char *decl_as_string		(tree, int);
 extern const char *decl_as_string_translate	(tree, int);
+extern const char *decl_as_dwarf_string		(tree, int);
 extern const char *expr_as_string		(tree, int);
 extern const char *lang_decl_name		(tree, int, bool);
+extern const char *lang_decl_dwarf_name		(tree, int, bool);
 extern const char *language_to_string		(enum languages);
 extern const char *class_key_or_enum_as_string	(tree);
 extern void print_instantiation_context		(void);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 7edfee0..a440962 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1028,7 +1028,12 @@  dump_decl (tree t, int flags)
 	    dump_scope (CP_DECL_CONTEXT (t), flags);
 	  flags &= ~TFF_UNQUALIFIED_NAME;
 	  if (DECL_NAME (t) == NULL_TREE)
-	    pp_cxx_ws_string (cxx_pp, M_("{anonymous}"));
+            {
+              if (!(pp_c_base (cxx_pp)->flags & pp_c_flag_gnu_v3))
+                pp_cxx_ws_string (cxx_pp, M_("{anonymous}"));
+              else
+                pp_cxx_ws_string (cxx_pp, M_("(anonymous namespace)"));
+            }
 	  else
 	    pp_cxx_tree_identifier (cxx_pp, DECL_NAME (t));
 	}
@@ -2555,6 +2560,21 @@  expr_as_string (tree decl, int flags)
   return pp_formatted_text (cxx_pp);
 }
 
+/* Wrap decl_as_string with options appropriate for dwarf.  */
+
+const char *
+decl_as_dwarf_string (tree decl, int flags)
+{
+  const char *name;
+  /* Curiously, reinit_cxx_pp doesn't reset the flags field, so setting the flag
+     here will be adequate to get the desired behaviour.  */
+  pp_c_base (cxx_pp)->flags |= pp_c_flag_gnu_v3;
+  name = decl_as_string (decl, flags);
+  /* Subsequent calls to the pretty printer shouldn't use this style.  */
+  pp_c_base (cxx_pp)->flags &= ~pp_c_flag_gnu_v3;
+  return name;
+}
+
 const char *
 decl_as_string (tree decl, int flags)
 {
@@ -2572,6 +2592,21 @@  decl_as_string_translate (tree decl, int flags)
   return pp_formatted_text (cxx_pp);
 }
 
+/* Wrap lang_decl_name with options appropriate for dwarf.  */
+
+const char *
+lang_decl_dwarf_name (tree decl, int v, bool translate)
+{
+  const char *name;
+  /* Curiously, reinit_cxx_pp doesn't reset the flags field, so setting the flag
+     here will be adequate to get the desired behaviour.  */
+  pp_c_base (cxx_pp)->flags |= pp_c_flag_gnu_v3;
+  name = lang_decl_name (decl, v, translate);
+  /* Subsequent calls to the pretty printer shouldn't use this style.  */
+  pp_c_base (cxx_pp)->flags &= ~pp_c_flag_gnu_v3;
+  return name;
+}
+
 /* Generate the three forms of printable names for cxx_printable_name.  */
 
 const char *
@@ -2595,6 +2630,9 @@  lang_decl_name (tree decl, int v, bool translate)
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
     dump_function_name (decl, TFF_PLAIN_IDENTIFIER);
+  else if ((DECL_NAME (decl) == NULL_TREE)
+           && TREE_CODE (decl) == NAMESPACE_DECL)
+    dump_decl (decl, TFF_PLAIN_IDENTIFIER | TFF_UNQUALIFIED_NAME);
   else
     dump_decl (DECL_NAME (decl), TFF_PLAIN_IDENTIFIER);
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9e3e66e..8934ab4 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -4954,6 +4954,10 @@  most expressive format available (DWARF 2, stabs, or the native format
 if neither of those are supported), including GDB extensions if at all
 possible.
 
+@item -gpubnames
+@opindex gpubnames
+Generate dwarf .debug_pubnames and .debug_pubtypes sections.
+
 @item -gstabs
 @opindex gstabs
 Produce debugging information in stabs format (if that is supported),
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 23f6fff..cc91aee 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2879,6 +2879,7 @@  typedef struct GTY(()) comdat_type_struct
 {
   dw_die_ref root_die;
   dw_die_ref type_die;
+  dw_die_ref skeleton_die;
   char signature[DWARF_TYPE_SIGNATURE_SIZE];
   struct comdat_type_struct *next;
 }
@@ -3353,6 +3354,7 @@  static void output_comp_unit (dw_die_ref, int);
 static void output_comdat_type_unit (comdat_type_node *);
 static const char *dwarf2_name (tree, int);
 static void add_pubname (tree, dw_die_ref);
+static void add_enumerator_pubname (const char *, dw_die_ref);
 static void add_pubname_string (const char *, dw_die_ref);
 static void add_pubtype (tree, dw_die_ref);
 static void output_pubnames (VEC (pubname_entry,gc) *);
@@ -3482,6 +3484,7 @@  static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
 				     const char *, const char *);
 static void output_loc_list (dw_loc_list_ref);
 static char *gen_internal_sym (const char *);
+static bool want_pubnames (void);
 
 static void prune_unmark_dies (dw_die_ref);
 static void prune_unused_types_mark_generic_parms_dies (dw_die_ref);
@@ -3556,6 +3559,12 @@  static void gen_scheduled_generic_parms_dies (void);
 #ifndef COLD_TEXT_SECTION_LABEL
 #define COLD_TEXT_SECTION_LABEL         "Ltext_cold"
 #endif
+#ifndef DEBUG_PUBNAMES_SECTION_LABEL
+#define DEBUG_PUBNAMES_SECTION_LABEL	    "Ldebug_pubnames"
+#endif
+#ifndef DEBUG_PUBTYPES_SECTION_LABEL
+#define DEBUG_PUBTYPES_SECTION_LABEL	    "Ldebug_pubtypes"
+#endif
 #ifndef DEBUG_LINE_SECTION_LABEL
 #define DEBUG_LINE_SECTION_LABEL	"Ldebug_line"
 #endif
@@ -3592,6 +3601,8 @@  static char cold_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_pubnames_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char debug_pubtypes_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
@@ -6726,6 +6737,23 @@  is_cu_die (dw_die_ref c)
   return c && c->die_tag == DW_TAG_compile_unit;
 }
 
+/* Returns true iff C is a namespace DIE.  */
+
+static inline bool
+is_namespace_die (dw_die_ref c)
+{
+  return c && c->die_tag == DW_TAG_namespace;
+}
+
+/* Returns true iff C is a class or structure DIE.  */
+
+static inline bool
+is_class_die (dw_die_ref c)
+{
+  return c && (c->die_tag == DW_TAG_class_type
+               || c->die_tag == DW_TAG_structure_type);
+}
+
 static char *
 gen_internal_sym (const char *prefix)
 {
@@ -7306,6 +7334,7 @@  break_out_comdat_types (dw_die_ref die)
            declaration into the new type unit DIE, then remove this DIE
 	   from the main CU (or replace it with a skeleton if necessary).  */
 	replacement = remove_child_or_replace_with_skeleton (unit, c, prev);
+	type_node->skeleton_die = replacement;
 
         /* Break out nested types into their own type units.  */
         break_out_comdat_types (c);
@@ -8626,6 +8655,34 @@  output_comp_unit (dw_die_ref die, int output_if_empty)
     }
 }
 
+/* Whether to generate the DWARF accelerator tables in .debug_pubnames
+   and .debug_pubtypes.  This is configured per-target, but can be
+   overridden by the -gpubnames or -gno-pubnames options.  */
+
+static inline bool
+want_pubnames (void)
+{
+  if (GENERATE_MINIMUM_LINE_TABLE)
+    return false;
+  return (debug_generate_pub_sections != -1
+	  ? debug_generate_pub_sections
+	  : targetm.want_debug_pub_sections);
+}
+
+/* Add the DW_AT_GNU_pubnames and DW_AT_GNU_pubtypes attributes.  */
+
+static void
+add_AT_pubnames (dw_die_ref die)
+{
+  if (want_pubnames ())
+    {
+      /* FIXME: Should use add_AT_pubnamesptr.  This works because most targets
+         don't care what the base section is.  */
+      add_AT_lineptr (die, DW_AT_GNU_pubnames, debug_pubnames_section_label);
+      add_AT_lineptr (die, DW_AT_GNU_pubtypes, debug_pubtypes_section_label);
+    }
+}
+
 /* Output a comdat type unit DIE and its children.  */
 
 static void
@@ -8691,29 +8748,47 @@  dwarf2_name (tree decl, int scope)
 static void
 add_pubname_string (const char *str, dw_die_ref die)
 {
-  if (!GENERATE_MINIMUM_LINE_TABLE && targetm.want_debug_pub_sections)
-    {
-      pubname_entry e;
+  pubname_entry e;
 
-      e.die = die;
-      e.name = xstrdup (str);
-      VEC_safe_push (pubname_entry, gc, pubname_table, &e);
-    }
+  e.die = die;
+  e.name = xstrdup (str);
+  VEC_safe_push (pubname_entry, gc, pubname_table, &e);
 }
 
 static void
 add_pubname (tree decl, dw_die_ref die)
 {
-  if (!GENERATE_MINIMUM_LINE_TABLE
-      && targetm.want_debug_pub_sections
-      && TREE_PUBLIC (decl))
+  if (!want_pubnames ())
+    return;
+
+  /* Don't add items to the table when we expect that the consumer will have
+     just read the enclosing die.  For example, if the consumer is looking at a
+     class_member, it will either be inside the class already, or will have just
+     looked up the class to find the member.  Either way, searching the class is
+     faster than searching the index.  */
+  if ((TREE_PUBLIC (decl) && !is_class_die (die->die_parent))
+      || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
     {
       const char *name = dwarf2_name (decl, 1);
+
       if (name)
 	add_pubname_string (name, die);
     }
 }
 
+/* Add an enumerator to the pubtypes section.  */
+
+static void
+add_enumerator_pubname (const char *scope_name, dw_die_ref die)
+{
+  pubname_entry e;
+
+  gcc_assert (scope_name);
+  e.name = concat (scope_name, get_AT_string (die, DW_AT_name), NULL);
+  e.die = die;
+  VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+}
+
 /* Add a new entry to .debug_pubtypes if appropriate.  */
 
 static void
@@ -8721,39 +8796,54 @@  add_pubtype (tree decl, dw_die_ref die)
 {
   pubname_entry e;
 
-  if (!targetm.want_debug_pub_sections)
+  if (!want_pubnames ())
     return;
 
-  e.name = NULL;
   if ((TREE_PUBLIC (decl)
-       || is_cu_die (die->die_parent))
+       || is_cu_die (die->die_parent) || is_namespace_die (die->die_parent))
       && (die->die_tag == DW_TAG_typedef || COMPLETE_TYPE_P (decl)))
     {
-      e.die = die;
-      if (TYPE_P (decl))
-	{
-	  if (TYPE_NAME (decl))
-	    {
-	      if (TREE_CODE (TYPE_NAME (decl)) == IDENTIFIER_NODE)
-		e.name = IDENTIFIER_POINTER (TYPE_NAME (decl));
-	      else if (TREE_CODE (TYPE_NAME (decl)) == TYPE_DECL
-		       && DECL_NAME (TYPE_NAME (decl)))
-		e.name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (decl)));
-	      else
-	       e.name = xstrdup ((const char *) get_AT_string (die, DW_AT_name));
-	    }
+      tree scope = NULL;
+      const char *scope_name = "";
+      const char *sep = is_cxx () ? "::" : ".";
+      const char *name;
+
+      scope = TYPE_P (decl) ? TYPE_CONTEXT (decl) : NULL;
+      if (scope && TREE_CODE (scope) == NAMESPACE_DECL)
+        {
+          scope_name = lang_hooks.dwarf_name (scope, 1);
+          if (scope_name != NULL && scope_name[0] != '\0')
+            scope_name = concat (scope_name, sep, NULL);
+          else
+            scope_name = "";
 	}
+
+      if (TYPE_P (decl))
+        name = type_tag (decl);
       else
-	{
-	  e.name = dwarf2_name (decl, 1);
-	  if (e.name)
-	    e.name = xstrdup (e.name);
-	}
+        name = lang_hooks.dwarf_name (decl, 1);
 
       /* If we don't have a name for the type, there's no point in adding
 	 it to the table.  */
-      if (e.name && e.name[0] != '\0')
-	VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+      if (name != NULL && name[0] != '\0')
+        {
+          e.die = die;
+          e.name = concat (scope_name, name, NULL);
+          VEC_safe_push (pubname_entry, gc, pubtype_table, &e);
+        }
+
+      /* Although it might be more consistent to add the pubinfo for the
+         enumerators as their dies are created, they should only be added if the
+         enum type meets the criteria above.  So rather than re-check the parent
+         enum type whenever an enumerator die is created, just output them all
+         here.  This isn't protected by the name conditional because anonymous
+         enums don't have names.  */
+      if (die->die_tag == DW_TAG_enumeration_type)
+        {
+          dw_die_ref c;
+
+          FOR_EACH_CHILD (die, c, add_enumerator_pubname (scope_name, c));
+        }
     }
 }
 
@@ -8767,6 +8857,18 @@  output_pubnames (VEC (pubname_entry, gc) * names)
   unsigned long pubnames_length = size_of_pubnames (names);
   pubname_ref pub;
 
+  if (!want_pubnames () || !info_section_emitted)
+    return;
+  if (names == pubname_table)
+    {
+      switch_to_section (debug_pubnames_section);
+      ASM_OUTPUT_LABEL (asm_out_file, debug_pubnames_section_label);
+    }
+  else
+    {
+      switch_to_section (debug_pubtypes_section);
+      ASM_OUTPUT_LABEL (asm_out_file, debug_pubtypes_section_label);
+    }
   if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
     dw2_asm_output_data (4, 0xffffffff,
       "Initial length escape value indicating 64-bit DWARF extension");
@@ -8794,8 +8896,23 @@  output_pubnames (VEC (pubname_entry, gc) * names)
 	  || pub->die->die_offset != 0
 	  || !flag_eliminate_unused_debug_types)
 	{
-	  dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
-			       "DIE offset");
+	  dw_offset die_offset = pub->die->die_offset;
+
+	  /* If we're putting types in their own .debug_types sections,
+	     the .debug_pubtypes table will still point to the compile
+	     unit (not the type unit), so we want to use the offset of
+	     the skeleton DIE (if there is one).  */
+	  if (use_debug_types && names == pubtype_table)
+	    {
+	      comdat_type_node_ref type_node = pub->die->die_id.die_type_node;
+
+	      if (type_node != NULL)
+	        die_offset = (type_node->skeleton_die != NULL
+			      ? type_node->skeleton_die->die_offset
+			      : 0);
+	    }
+
+	  dw2_asm_output_data (DWARF_OFFSET_SIZE, die_offset, "DIE offset");
 
 	  dw2_asm_output_nstring (pub->name, -1, "external name");
 	}
@@ -9678,6 +9795,7 @@  base_type_die (tree type)
   add_AT_unsigned (base_type_result, DW_AT_byte_size,
 		   int_size_in_bytes (type));
   add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+  add_pubtype (type, base_type_result);
 
   return base_type_result;
 }
@@ -16764,8 +16882,7 @@  gen_enumeration_type_die (tree type, dw_die_ref context_die)
   else
     add_AT_flag (type_die, DW_AT_declaration, 1);
 
-  if (get_AT (type_die, DW_AT_name))
-    add_pubtype (type, type_die);
+  add_pubtype (type, type_die);
 
   return type_die;
 }
@@ -17275,6 +17392,7 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 	{
 	  subr_die = new_die (DW_TAG_subprogram, context_die, decl);
 	  add_AT_specification (subr_die, old_die);
+          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)
@@ -17289,6 +17407,7 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 	add_AT_flag (subr_die, DW_AT_external, 1);
 
       add_name_and_src_coords_attributes (subr_die, decl);
+      add_pubname (decl, subr_die);
       if (debug_info_level > DINFO_LEVEL_TERSE)
 	{
 	  add_prototyped_attribute (subr_die, TREE_TYPE (decl));
@@ -17400,7 +17519,6 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
       }
 #endif
 
-	  add_pubname (decl, subr_die);
 	}
       else
 	{
@@ -17421,7 +17539,6 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 		  add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
 					fde->dw_fde_second_end,
 					&range_list_added);
-		  add_pubname (decl, subr_die);
 		  if (range_list_added)
 		    add_ranges (NULL);
 		}
@@ -17443,8 +17560,6 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 				 fde->dw_fde_begin);
 		  add_AT_lbl_id (subr_die, DW_AT_high_pc,
 				 fde->dw_fde_end);
-		  /* Add it.   */
-		  add_pubname (decl, subr_die);
 
 		  /* Build a minimal DIE for the secondary section.  */
 		  seg_die = new_die (DW_TAG_subprogram,
@@ -17473,14 +17588,14 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 		  add_AT_lbl_id (seg_die, DW_AT_high_pc,
 				 fde->dw_fde_second_end);
 		  add_name_attribute (seg_die, name);
-		  add_pubname_string (name, seg_die);
+		  if (want_pubnames ())
+		    add_pubname_string (name, seg_die);
 		}
 	    }
 	  else
 	    {
 	      add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin);
 	      add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end);
-	      add_pubname (decl, subr_die);
 	    }
 	}
 
@@ -17901,7 +18016,8 @@  gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	    }
           else if (DECL_EXTERNAL (decl))
 	    add_AT_flag (com_die, DW_AT_declaration, 1);
-	  add_pubname_string (cnam, com_die); /* ??? needed? */
+	  if (want_pubnames ())
+	    add_pubname_string (cnam, com_die); /* ??? needed? */
 	  com_die->decl_id = DECL_UID (com_decl);
 	  slot = htab_find_slot (common_block_die_table, com_die, INSERT);
 	  *slot = (void *) com_die;
@@ -19483,6 +19599,9 @@  gen_namespace_die (tree decl, dw_die_ref context_die)
       add_AT_die_ref (namespace_die, DW_AT_import, origin_die);
       equate_decl_number_to_die (decl, namespace_die);
     }
+  /* Bypass dwarf2_name's check for DECL_NAMELESS.  */
+  if (want_pubnames ())
+    add_pubname_string (lang_hooks.dwarf_name (decl, 1), namespace_die);
 }
 
 /* Generate Dwarf debug information for a decl described by DECL.
@@ -21186,6 +21305,10 @@  dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 
   ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label,
 			       DEBUG_INFO_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (debug_pubnames_section_label,
+			       DEBUG_PUBNAMES_SECTION_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (debug_pubtypes_section_label,
+			       DEBUG_PUBTYPES_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
 			       DEBUG_LINE_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
@@ -22788,6 +22911,8 @@  dwarf2out_finish (const char *filename)
     }
   htab_delete (comdat_type_table);
 
+  add_AT_pubnames (comp_unit_die ());
+
   /* 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);
@@ -22811,42 +22936,12 @@  dwarf2out_finish (const char *filename)
       output_location_lists (comp_unit_die ());
     }
 
-  /* Output public names table if necessary.  */
-  if (!VEC_empty (pubname_entry, pubname_table))
-    {
-      gcc_assert (info_section_emitted);
-      switch_to_section (debug_pubnames_section);
-      output_pubnames (pubname_table);
-    }
-
-  /* Output public types table if necessary.  */
+  /* Output public names and types tables if necessary.  */
+  output_pubnames (pubname_table);
   /* ??? Only defined by DWARF3, but emitted by Darwin for DWARF2.
      It shouldn't hurt to emit it always, since pure DWARF2 consumers
      simply won't look for the section.  */
-  if (!VEC_empty (pubname_entry, pubtype_table))
-    {
-      bool empty = false;
-      
-      if (flag_eliminate_unused_debug_types)
-	{
-	  /* The pubtypes table might be emptied by pruning unused items.  */
-	  unsigned i;
-	  pubname_ref p;
-	  empty = true;
-	  FOR_EACH_VEC_ELT (pubname_entry, pubtype_table, i, p)
-	    if (p->die->die_offset != 0)
-	      {
-		empty = false;
-		break;
-	      }
-	}
-      if (!empty)
-	{
-	  gcc_assert (info_section_emitted);
-	  switch_to_section (debug_pubtypes_section);
-	  output_pubnames (pubtype_table);
-	}
-    }
+  output_pubnames (pubtype_table);
 
   /* Output the address range information if a CU (.debug_info section)
      was emitted.  We output an empty table even if we had no functions
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-2.C
new file mode 100644
index 0000000..eef0336
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/pubnames-2.C
@@ -0,0 +1,194 @@ 
+// { dg-do compile }
+// { dg-options "-gpubnames -gdwarf-4 -std=c++0x -dA" }
+// { dg-final { scan-assembler ".section\t.debug_pubnames" } }
+// { dg-final { scan-assembler "\"\\(anonymous namespace\\)\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::G_A\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::G_B\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::G_C\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::\\(anonymous namespace\\)\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"F_A\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"F_B\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"F_C\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"inline_func_1\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::c1::c1\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::c1::~c1\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::c1::val\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"check_enum\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"main\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int>::c2\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<double>::c2\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int const\\\*>::c2\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"check<one::c1>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"check<two::c2<int> \\>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"check<two::c2<double> \\>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"check<two::c2<int const\\\*> \\>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int>::val\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<double>::val\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int const\\\*>::val\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"__static_initialization_and_destruction_0\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int>::~c2\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<double>::~c2\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int const\\\*>::~c2\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"_GLOBAL__sub_I__ZN3one3c1vE\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"anonymous_union_var\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::ci\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2v1\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2v2\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2v3\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::c1v\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::\\(anonymous namespace\\)::one_anonymous_var\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"\\(anonymous namespace\\)::c1_count\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"\\(anonymous namespace\\)::c2_count\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"\\(anonymous namespace\\)::three\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"\\(anonymous namespace\\)::three::anonymous_three_var\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler ".section\t.debug_pubtypes" } }
+// { dg-final { scan-assembler "\"one::G\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::c1\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"int\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"one::c1\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<double>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"double\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<double>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int const\\\*>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"two::c2<int const\\\*>\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"F\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"anonymous_union_container\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+// { dg-final { scan-assembler "\"bool\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } }
+
+namespace
+{
+int c1_count;
+int c2_count;
+
+namespace three
+{
+int anonymous_three_var;
+}
+};
+
+namespace one
+{
+
+enum G
+{
+  G_A,
+  G_B,
+  G_C
+};
+
+namespace {
+int one_anonymous_var;
+}
+
+class c1
+{
+ public:
+  static int count;
+
+  c1()
+  { ++c1_count; }
+
+  ~c1()
+  {
+    --c1_count;
+  }
+
+  enum E
+  {
+    E_A,
+    E_B,
+    E_C,
+  };
+
+  int
+  val()
+  { return E_A; }
+};
+
+c1 c1v;
+};
+
+namespace two
+{
+const int ci = 3;
+
+template <typename T>
+class c2
+{
+ public:
+  c2(T t)
+    : t_(t)
+  {
+    ++c2_count;
+  }
+
+  ~c2()
+  { --c2_count; }
+
+  T
+  val()
+  { return this->t_; }
+
+  T t_;
+};
+
+c2<int> c2v1(1);
+c2<double> c2v2(2.0);
+c2<int const*> c2v3(&ci);
+};
+
+enum F
+{
+  F_A,
+  F_B,
+  F_C
+};
+
+template <class C>
+bool
+check(C* c)
+{ return c->val() == 0; }
+
+bool
+check_enum(int i)
+{ return i > 0; }
+
+struct anonymous_union_container {
+  union {
+    struct astruct {
+      int a;
+    };
+    int b;
+  } u;
+};
+
+anonymous_union_container anonymous_union_var;
+
+#ifdef __GNUC__
+#define ALWAYS_INLINE __attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+static inline ALWAYS_INLINE int
+inline_func_1(int i)
+{ return i * 17; }
+
+int
+main()
+{
+  F f = F_A;
+  one::G g = one::G_A;
+  check_enum(f);
+  check_enum(g);
+  check(&one::c1v);
+  check(&two::c2v1);
+  check(&two::c2v2);
+  check(&two::c2v3);
+  anonymous_union_var.u.b = inline_func_1(3) - 51;
+  return anonymous_union_var.u.b;
+}