diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 317d5cd..9d64046 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -11227,6 +11227,16 @@ c_parse_final_cleanups (void)
   c_write_global_declarations_1 (BLOCK_VARS (ext_block));
 
   timevar_stop (TV_PHASE_DEFERRED);
+
+  /* Purge unreferenced extern variables from the debug information.  */
+  if (!seen_error ())
+  {
+    tree decl;
+    for (decl = BLOCK_VARS (ext_block); decl; decl = DECL_CHAIN (decl))
+       if (DECL_EXTERNAL (decl))
+	 (*debug_hooks->late_global_decl) (decl);
+  }
+
   timevar_start (TV_PHASE_PARSING);
 
   ext_block = NULL;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 877745c..93929e6 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "calls.h"
 #include "decl.h"
 #include "toplev.h"
+#include "debug.h"
 #include "c-family/c-objc.h"
 #include "c-family/c-pragma.h"
 #include "dumpfile.h"
@@ -4408,6 +4409,42 @@ lower_var_init ()
     }
 }
 
+/* We call this routine on each namespace to remove unreferenced extern
+   variables from the debug information.  */
+
+static int
+purge_unused_extern_globals (tree name_space)
+{
+  int rc;
+  cp_binding_level *level = NAMESPACE_LEVEL (name_space);
+  tree decl;
+
+  if (seen_error ())
+    return 1;
+
+  if (!level)
+    return 0;
+
+  for (decl = level->names; decl; decl = DECL_CHAIN (decl))
+    {
+      switch (TREE_CODE (decl))
+	{
+	case VAR_DECL:
+	  if (DECL_EXTERNAL (decl))
+	    (*debug_hooks->late_global_decl) (decl);
+	  break;
+	case NAMESPACE_DECL:
+	  if ((rc = purge_unused_extern_globals (decl)))
+	    return rc;
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  return 0;
+}
+
 /* This routine is called at the end of compilation.
    Its job is to create all the code needed to initialize and
    destroy the global aggregates.  We do the destruction
@@ -4791,6 +4828,10 @@ c_parse_final_cleanups (void)
     }
 
   timevar_stop (TV_PHASE_DEFERRED);
+
+  /* Purge unreferenced extern variables from the debug information.  */
+  purge_unused_extern_globals (global_namespace);
+
   timevar_start (TV_PHASE_PARSING);
 
   /* Indicate that we're done with front end processing.  */
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index c277d27..261aeef 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -62,6 +62,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "function.h"
 #include "rtl.h"
 #include "tree.h"
+#include "cp/cp-tree.h"
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
@@ -25512,6 +25513,16 @@ dwarf2out_early_global_decl (tree decl)
   symtab->global_info_ready = save;
 }
 
+/* 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));
+}
+
 /* Output debug information for global decl DECL.  Called from
    toplev.c after compilation proper has finished.  */
 
@@ -25520,29 +25531,73 @@ dwarf2out_late_global_decl (tree decl)
 {
   /* Fill-in any location information we were unable to determine
      on the first pass.  */
-  if (VAR_P (decl) && !POINTER_BOUNDS_P (decl))
+  if (! VAR_P (decl) || POINTER_BOUNDS_P (decl))
+    return;
+
+  dw_die_ref die = lookup_decl_die (decl);
+
+  /* We have to generate early debug late for LTO.  */
+  if (! die && in_lto_p)
     {
-      dw_die_ref die = lookup_decl_die (decl);
+      dwarf2out_decl (decl);
+      die = lookup_decl_die (decl);
+    }
 
-      /* We have to generate early debug late for LTO.  */
-      if (! die && in_lto_p)
-	{
-	  dwarf2out_decl (decl);
-	  die = lookup_decl_die (decl);
-	}
+  /* Discard this VAR_DECL if it refers to a file-scope
+     (or namespace-scope) extern data object declaration and if the
+     declaration was never even referenced from within this entire
+     compilation unit.  We suppress these DIEs in order to save space
+     in the .debug section (by eliminating entries which are probably
+     useless).  Note that we must not suppress block-local extern and
+     static member declarations (whether used or not) because that
+     would screw-up the debugger's name lookup mechanism and cause
+     it to miss things which really ought to be in scope at a
+     given point.  */
+  if (die && ! die->die_perennial_p
+      && DECL_EXTERNAL (decl)
+      && ! DECL_CLASS_SCOPE_P (decl)
+      && ! TREE_USED (decl))
+    {
+      mark_removed (die);
 
-      if (die)
-	{
-	  /* We get called via the symtab code invoking late_global_decl
-	     for symbols that are optimized out.  Do not add locations
-	     for those, except if they have a DECL_VALUE_EXPR, in which case
-	     they are relevant for debuggers.  */
-	  varpool_node *node = varpool_node::get (decl);
-	  if ((! node || ! node->definition) && ! DECL_HAS_VALUE_EXPR_P (decl))
-	    tree_add_const_value_attribute_for_decl (die, decl);
-	  else
-	    add_location_or_const_value_attribute (die, decl, false);
-	}
+      dw_die_ref next = die->die_sib;
+      if (die == die->die_sib)
+	next = NULL;
+
+      dw_die_ref *ptail = &die->die_parent->die_child;
+      dw_die_ref prev = (*ptail)->die_sib;
+      while (prev->die_sib != die)
+	prev = prev->die_sib;
+      prev->die_sib = next;
+
+      if (prev == die)
+	prev = NULL;
+      if (*ptail == die)
+       *ptail = prev;
+
+      die->die_parent = NULL;
+      die->die_sib = NULL;
+
+      /* Die has been removed, so we pretend we couldn't find it in
+	the first place.  */
+      die = NULL;
+    }
+
+  if (! die)
+    return;
+
+  varpool_node *node = varpool_node::get (decl);
+  if ((! node || ! node->in_other_partition)
+      && ! DECL_EXTERNAL (decl))
+    {
+      /* We get called via the symtab code invoking late_global_decl
+	 for symbols that are optimized out.  Do not add locations
+	 for those, except if they have a DECL_VALUE_EXPR, in which case
+	 they are relevant for debuggers.  */
+      if ((! node || ! node->definition) && ! DECL_HAS_VALUE_EXPR_P (decl))
+	tree_add_const_value_attribute_for_decl (die, decl);
+      else
+	add_location_or_const_value_attribute (die, decl, false);
     }
 }
 
@@ -25646,6 +25701,10 @@ dwarf2out_imported_module_or_decl_1 (tree decl,
     add_AT_string (imported_die, DW_AT_name,
 		   IDENTIFIER_POINTER (name));
   add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
+
+  /* To avoid issues with the unreferenced extern removal, we mark the imported
+     DIE as perennial so it won't be considered for removal.  */
+  at_import_die->die_perennial_p = 1;
 }
 
 /* Output debug information for imported module or decl DECL.
@@ -27860,16 +27919,6 @@ prune_unused_types_update_strings (dw_die_ref die)
       }
 }
 
-/* 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
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pr81135.C b/gcc/testsuite/g++.dg/debug/dwarf2/pr81135.C
new file mode 100644
index 0000000..84cf557
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/pr81135.C
@@ -0,0 +1,25 @@
+// { dg-do compile }
+// { dg-options "-gdwarf-2 -dA" }
+// { dg-final { scan-assembler "DW_TAG_variable\[^.\]*\.ascii \"i..\"" } }
+// { dg-final { scan-assembler "DW_TAG_variable\[^.\]*\.ascii \"m..\"" } }
+// { dg-final { scan-assembler-not "DW_TAG_variable\[^.\]*\.ascii \"j..\"" } }
+// { dg-final { scan-assembler-not "DW_TAG_variable\[^.\]*\.ascii \"k..\"" } }
+// { dg-final { scan-assembler-not "DW_TAG_variable\[^.\]*\.ascii \"l..\"" } }
+
+extern int i;
+extern int j;
+
+namespace {
+  extern int k;
+}
+
+namespace foo {
+  extern int l;
+  extern int m;
+}
+
+int
+main (void)
+{
+  return i + foo::m;
+}
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr81135.C b/gcc/testsuite/gcc.dg/debug/dwarf2/pr81135.C
new file mode 100644
index 0000000..5902bd3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr81135.C
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-gdwarf-2 -dA" }
+// { dg-final { scan-assembler "DW_TAG_variable\[^.\]*\.ascii \"i..\"" } }
+// { dg-final { scan-assembler-not "DW_TAG_variable\[^.\]*\.ascii \"j..\"" } }
+
+extern int i;
+extern int j;
+
+int
+main (void)
+{
+  return i;
+}
