OSDN Git Service

PR c++/42317
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 10 Dec 2009 21:58:49 +0000 (21:58 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 10 Dec 2009 21:58:49 +0000 (21:58 +0000)
* cgraph.h (struct cgraph_node): Add same_comdat_group field.
* cgraph.c (cgraph_remove_node): Unchain node from same_comdat_group
circular list.
(cgraph_node_can_be_local_p): Return false for DECL_COMDAT with
node->same_comdat_group.
* ipa.c (cgraph_remove_unreachable_nodes): For any reachable node
mark all its same_comdat_group nodes as also reachable.
(cgraph_externally_visible_p): Return true even if any of
same_comdat_group nodes has address taken.
* lto-cgraph.c (lto_output_node): Stream out same_comdat_group.
(output_cgraph): Ensure other same_comdat_group nodes are also
included.
(input_node): Stream in same_comdat_group.
(input_cgraph_1): Fix up same_comdat_group fields from references
to pointers.
* cgraphunit.c (cgraph_analyze_functions): Mark all other
same_comdat_group nodes as reachable.
(cgraph_mark_functions_to_output): For each node->process process
also other same_comdat_group nodes.
* ipa-inline.c (cgraph_clone_inlined_nodes): Don't reuse nodes
with same_comdat_group non-NULL.
(cgraph_mark_inline_edge): Likewise.

* decl2.c (cp_write_global_declarations): Clear DECL_EXTERNAL
also on all other functions in the same comdat group.
* optimize.c (maybe_clone_body): Also optimize virtual implicit
dtors.  For virtual comdat dtors tell cgraph that base and deleting
dtor are in the same comdat group.

* config/abi/pre/gnu.ver: Don't export certain base dtors that
weren't previously exported.

* g++.dg/opt/dtor2.C: New test.
* g++.dg/opt/dtor2.h: New file.
* g++.dg/opt/dtor2-aux.cc: New file.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@155143 138bc75d-0d04-0410-961f-82ee72b054a4

16 files changed:
gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/cp/ChangeLog
gcc/cp/decl2.c
gcc/cp/optimize.c
gcc/ipa-inline.c
gcc/ipa.c
gcc/lto-cgraph.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/opt/dtor2-aux.cc [new file with mode: 0644]
gcc/testsuite/g++.dg/opt/dtor2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/opt/dtor2.h [new file with mode: 0644]
libstdc++-v3/ChangeLog
libstdc++-v3/config/abi/pre/gnu.ver

index b027bc9..79fb7b1 100644 (file)
@@ -1,3 +1,29 @@
+2009-12-10  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/42317
+       * cgraph.h (struct cgraph_node): Add same_comdat_group field.
+       * cgraph.c (cgraph_remove_node): Unchain node from same_comdat_group
+       circular list.
+       (cgraph_node_can_be_local_p): Return false for DECL_COMDAT with
+       node->same_comdat_group.
+       * ipa.c (cgraph_remove_unreachable_nodes): For any reachable node
+       mark all its same_comdat_group nodes as also reachable.
+       (cgraph_externally_visible_p): Return true even if any of
+       same_comdat_group nodes has address taken.
+       * lto-cgraph.c (lto_output_node): Stream out same_comdat_group.
+       (output_cgraph): Ensure other same_comdat_group nodes are also
+       included.
+       (input_node): Stream in same_comdat_group.
+       (input_cgraph_1): Fix up same_comdat_group fields from references
+       to pointers.
+       * cgraphunit.c (cgraph_analyze_functions): Mark all other
+       same_comdat_group nodes as reachable.
+       (cgraph_mark_functions_to_output): For each node->process process
+       also other same_comdat_group nodes.
+       * ipa-inline.c (cgraph_clone_inlined_nodes): Don't reuse nodes
+       with same_comdat_group non-NULL.
+       (cgraph_mark_inline_edge): Likewise.
+
 2009-12-10  Jan Hubicka  <jh@suse.cz>
 
        PR middle-end/42228
index a3efdfc..0ed097a 100644 (file)
@@ -1443,6 +1443,20 @@ cgraph_remove_node (struct cgraph_node *node)
   while (node->same_body)
     cgraph_remove_same_body_alias (node->same_body);
 
+  if (node->same_comdat_group)
+    {
+      struct cgraph_node *prev;
+      for (prev = node->same_comdat_group;
+          prev->same_comdat_group != node;
+          prev = prev->same_comdat_group)
+       ;
+      if (node->same_comdat_group == prev)
+       prev->same_comdat_group = NULL;
+      else
+       prev->same_comdat_group = node->same_comdat_group;
+      node->same_comdat_group = NULL;
+    }
+
   /* While all the clones are removed after being proceeded, the function
      itself is kept in the cgraph even after it is compiled.  Check whether
      we are done with this body and reclaim it proactively if this is the case.
@@ -2172,7 +2186,8 @@ bool
 cgraph_node_can_be_local_p (struct cgraph_node *node)
 {
   return (!node->needed
-         && (DECL_COMDAT (node->decl) || !node->local.externally_visible));
+         && ((DECL_COMDAT (node->decl) && !node->same_comdat_group)
+             || !node->local.externally_visible));
 }
 
 /* Bring NODE local.  */
index 51426e6..268e6d4 100644 (file)
@@ -200,6 +200,8 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   /* For normal nodes pointer to the list of alias and thunk nodes,
      in alias/thunk nodes pointer to the normal node.  */
   struct cgraph_node *same_body;
+  /* Circular list of nodes in the same comdat group if non-NULL.  */
+  struct cgraph_node *same_comdat_group;
   /* For functions with many calls sites it holds map from call expression
      to the edge to speed up cgraph_edge function.  */
   htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
index 58bdd85..cf1a001 100644 (file)
@@ -982,6 +982,14 @@ cgraph_analyze_functions (void)
        if (!edge->callee->reachable)
          cgraph_mark_reachable_node (edge->callee);
 
+      if (node->same_comdat_group)
+       {
+         for (next = node->same_comdat_group;
+              next != node;
+              next = next->same_comdat_group)
+           cgraph_mark_reachable_node (next);
+       }
+
       /* If decl is a clone of an abstract function, mark that abstract
         function so that we don't release its body. The DECL_INITIAL() of that
          abstract function declaration will be later needed to output debug info.  */
@@ -1094,13 +1102,21 @@ static void
 cgraph_mark_functions_to_output (void)
 {
   struct cgraph_node *node;
+#ifdef ENABLE_CHECKING
+  bool check_same_comdat_groups = false;
+
+  for (node = cgraph_nodes; node; node = node->next)
+    gcc_assert (!node->process);
+#endif
 
   for (node = cgraph_nodes; node; node = node->next)
     {
       tree decl = node->decl;
       struct cgraph_edge *e;
 
-      gcc_assert (!node->process);
+      gcc_assert (!node->process || node->same_comdat_group);
+      if (node->process)
+       continue;
 
       for (e = node->callers; e; e = e->next_caller)
        if (e->inline_failed)
@@ -1115,7 +1131,23 @@ cgraph_mark_functions_to_output (void)
              || (e && node->reachable))
          && !TREE_ASM_WRITTEN (decl)
          && !DECL_EXTERNAL (decl))
-       node->process = 1;
+       {
+         node->process = 1;
+         if (node->same_comdat_group)
+           {
+             struct cgraph_node *next;
+             for (next = node->same_comdat_group;
+                  next != node;
+                  next = next->same_comdat_group)
+               next->process = 1;
+           }
+       }
+      else if (node->same_comdat_group)
+       {
+#ifdef ENABLE_CHECKING
+         check_same_comdat_groups = true;
+#endif
+       }
       else
        {
          /* We should've reclaimed all functions that are not needed.  */
@@ -1135,6 +1167,21 @@ cgraph_mark_functions_to_output (void)
        }
 
     }
+#ifdef ENABLE_CHECKING
+  if (check_same_comdat_groups)
+    for (node = cgraph_nodes; node; node = node->next)
+      if (node->same_comdat_group && !node->process)
+       {
+         tree decl = node->decl;
+         if (!node->global.inlined_to
+             && gimple_has_body_p (decl)
+             && !DECL_EXTERNAL (decl))
+           {
+             dump_cgraph_node (stderr, node);
+             internal_error ("failed to reclaim unneeded function");
+           }
+       }
+#endif
 }
 
 /* DECL is FUNCTION_DECL.  Initialize datastructures so DECL is a function
index bb3f8f9..c98e68a 100644 (file)
@@ -1,3 +1,12 @@
+2009-12-10  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/42317
+       * decl2.c (cp_write_global_declarations): Clear DECL_EXTERNAL
+       also on all other functions in the same comdat group.
+       * optimize.c (maybe_clone_body): Also optimize virtual implicit
+       dtors.  For virtual comdat dtors tell cgraph that base and deleting
+       dtor are in the same comdat group.
+
 2009-12-04  Jason Merrill  <jason@redhat.com>
 
        PR c++/42010
index faa3c9d..d4a866a 100644 (file)
@@ -3660,7 +3660,7 @@ cp_write_global_declarations (void)
              && DECL_INITIAL (decl)
              && decl_needed_p (decl))
            {
-             struct cgraph_node *node = cgraph_get_node (decl), *alias;
+             struct cgraph_node *node = cgraph_get_node (decl), *alias, *next;
 
              DECL_EXTERNAL (decl) = 0;
              /* If we mark !DECL_EXTERNAL one of the same body aliases,
@@ -3671,6 +3671,23 @@ cp_write_global_declarations (void)
                  for (alias = node->same_body; alias; alias = alias->next)
                    DECL_EXTERNAL (alias->decl) = 0;
                }
+             /* If we mark !DECL_EXTERNAL one of the symbols in some comdat
+                group, we need to mark all symbols in the same comdat group
+                that way.  */
+             if (node->same_comdat_group)
+               for (next = node->same_comdat_group;
+                    next != node;
+                    next = next->same_comdat_group)
+                 {
+                   DECL_EXTERNAL (next->decl) = 0;
+                   if (next->same_body)
+                     {
+                       for (alias = next->same_body;
+                            alias;
+                            alias = alias->next)
+                         DECL_EXTERNAL (alias->decl) = 0;
+                     }
+                 }
            }
 
          /* If we're going to need to write this function out, and
index 9210a80..325df8f 100644 (file)
@@ -292,12 +292,7 @@ maybe_clone_body (tree fn)
          && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fns[0]))
          && (!DECL_ONE_ONLY (fns[0])
              || (HAVE_COMDAT_GROUP
-                 && DECL_WEAK (fns[0])
-                 /* Don't optimize synthetized virtual dtors, because then
-                    the deleting and other dtors are emitted when needed
-                    and so it is not certain we would emit both
-                    deleting and complete/base dtors in the comdat group.  */
-                 && (fns[2] == NULL || !DECL_ARTIFICIAL (fn))))
+                 && DECL_WEAK (fns[0])))
          && cgraph_same_body_alias (clone, fns[0]))
        {
          alias = true;
@@ -396,9 +391,18 @@ maybe_clone_body (tree fn)
     {
       DECL_COMDAT_GROUP (fns[1]) = comdat_group;
       if (fns[2])
-       /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
-          virtual, it goes into the same comdat group as well.  */
-       DECL_COMDAT_GROUP (fns[2]) = comdat_group;
+       {
+         struct cgraph_node *base_dtor_node, *deleting_dtor_node;
+         /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
+            virtual, it goes into the same comdat group as well.  */
+         DECL_COMDAT_GROUP (fns[2]) = comdat_group;
+         base_dtor_node = cgraph_node (fns[0]);
+         deleting_dtor_node = cgraph_node (fns[2]);
+         gcc_assert (base_dtor_node->same_comdat_group == NULL);
+         gcc_assert (deleting_dtor_node->same_comdat_group == NULL);
+         base_dtor_node->same_comdat_group = deleting_dtor_node;
+         deleting_dtor_node->same_comdat_group = base_dtor_node;
+       }
     }
 
   /* We don't need to process the original function any further.  */
index 120c234..b146d0b 100644 (file)
@@ -247,6 +247,10 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
         In that case just go ahead and re-use it.  */
       if (!e->callee->callers->next_caller
          && cgraph_can_remove_if_no_direct_calls_p (e->callee)
+         /* Don't reuse if more than one function shares a comdat group.
+            If the other function(s) are needed, we need to emit even
+            this function out of line.  */
+         && !e->callee->same_comdat_group
          && !cgraph_new_nodes)
        {
          gcc_assert (!e->callee->global.inlined_to);
@@ -311,7 +315,8 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
   e->callee->global.inlined = true;
 
   if (e->callee->callers->next_caller
-      || !cgraph_can_remove_if_no_direct_calls_p (e->callee))
+      || !cgraph_can_remove_if_no_direct_calls_p (e->callee)
+      || e->callee->same_comdat_group)
     duplicate = true;
   cgraph_clone_inlined_nodes (e, true, update_original);
 
index 708b800..b1844db 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -1,5 +1,5 @@
 /* Basic IPA optimizations and utilities.
-   Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation,
+   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
    Inc.
 
 This file is part of GCC.
@@ -179,7 +179,25 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
                  first = e->callee;
                }
            }
-       
+
+      /* If any function in a comdat group is reachable, force
+        all other functions in the same comdat group to be
+        also reachable.  */
+      if (node->same_comdat_group
+         && node->reachable
+         && !node->global.inlined_to)
+       {
+         for (next = node->same_comdat_group;
+              next != node;
+              next = next->same_comdat_group)
+           if (!next->reachable)
+             {
+               next->aux = first;
+               first = next;
+               next->reachable = true;
+             }
+       }
+
       /* We can freely remove inline clones even if they are cloned, however if
         function is clone of real clone, we must keep it around in order to
         make materialize_clones produce function body with the changes
@@ -302,8 +320,24 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
   /* COMDAT functions must be shared only if they have address taken,
      otherwise we can produce our own private implementation with
      -fwhole-program.  */
-  if (DECL_COMDAT (node->decl) && (node->address_taken || !node->analyzed))
-    return true;
+  if (DECL_COMDAT (node->decl))
+    {
+      if (node->address_taken || !node->analyzed)
+       return true;
+      if (node->same_comdat_group)
+       {
+         struct cgraph_node *next;
+
+         /* If more than one function is in the same COMDAT group, it must
+            be shared even if just one function in the comdat group has
+            address taken.  */
+         for (next = node->same_comdat_group;
+              next != node;
+              next = next->same_comdat_group)
+           if (next->address_taken || !next->analyzed)
+             return true;
+       }
+    }
   if (MAIN_NAME_P (DECL_NAME (node->decl)))
     return true;
   if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
index 309a1e6..e02999d 100644 (file)
@@ -306,6 +306,15 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
   lto_output_sleb128_stream (ob->main_stream,
                             node->global.estimated_growth);
   lto_output_uleb128_stream (ob->main_stream, node->global.inlined);
+  if (node->same_comdat_group)
+    {
+      ref = lto_cgraph_encoder_lookup (encoder, node->same_comdat_group);
+      gcc_assert (ref != LCC_NOT_FOUND);
+    }
+  else
+    ref = LCC_NOT_FOUND;
+  lto_output_sleb128_stream (ob->main_stream, ref);
+
   if (node->same_body)
     {
       struct cgraph_node *alias;
@@ -407,8 +416,30 @@ output_cgraph (cgraph_node_set set)
              /* We should have moved all the inlines.  */
              gcc_assert (!callee->global.inlined_to);
              lto_cgraph_encoder_encode (encoder, callee);
+             /* Also with each included function include all other functions
+                in the same comdat group.  */
+             if (callee->same_comdat_group)
+               {
+                 struct cgraph_node *next;
+                 for (next = callee->same_comdat_group;
+                      next != callee;
+                      next = next->same_comdat_group)
+                   if (!cgraph_node_in_set_p (next, set))
+                     lto_cgraph_encoder_encode (encoder, next);
+               }
            }
        }
+      /* Also with each included function include all other functions
+        in the same comdat group.  */
+      if (node->same_comdat_group)
+       {
+         struct cgraph_node *next;
+         for (next = node->same_comdat_group;
+              next != node;
+              next = next->same_comdat_group)
+           if (!cgraph_node_in_set_p (next, set))
+             lto_cgraph_encoder_encode (encoder, next);
+       }
     }
 
   /* Write out the nodes.  */
@@ -519,7 +550,7 @@ input_node (struct lto_file_decl_data *file_data,
   bool clone_p;
   int estimated_stack_size = 0;
   int stack_frame_offset = 0;
-  int ref = LCC_NOT_FOUND;
+  int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND;
   int estimated_growth = 0;
   int time = 0;
   int size = 0;
@@ -561,6 +592,7 @@ input_node (struct lto_file_decl_data *file_data,
   size = lto_input_sleb128 (ib);
   estimated_growth = lto_input_sleb128 (ib);
   inlined = lto_input_uleb128 (ib);
+  ref2 = lto_input_sleb128 (ib);
   same_body_count = lto_input_uleb128 (ib);
 
   /* Make sure that we have not read this node before.  Nodes that
@@ -587,6 +619,9 @@ input_node (struct lto_file_decl_data *file_data,
   node->global.estimated_growth = estimated_growth;
   node->global.inlined = inlined;
 
+  /* Store a reference for now, and fix up later to be a pointer.  */
+  node->same_comdat_group = (cgraph_node_ptr) (intptr_t) ref2;
+
   while (same_body_count-- > 0)
     {
       tree alias_decl;
@@ -707,13 +742,21 @@ input_cgraph_1 (struct lto_file_decl_data *file_data,
 
   for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
     {
-      const int ref = (int) (intptr_t) node->global.inlined_to;
+      int ref = (int) (intptr_t) node->global.inlined_to;
 
       /* Fixup inlined_to from reference to pointer.  */
       if (ref != LCC_NOT_FOUND)
        node->global.inlined_to = VEC_index (cgraph_node_ptr, nodes, ref);
       else
        node->global.inlined_to = NULL;
+
+      ref = (int) (intptr_t) node->same_comdat_group;
+
+      /* Fixup same_comdat_group from reference to pointer.  */
+      if (ref != LCC_NOT_FOUND)
+       node->same_comdat_group = VEC_index (cgraph_node_ptr, nodes, ref);
+      else
+       node->same_comdat_group = NULL;
     }
 
   VEC_free (cgraph_node_ptr, heap, nodes);
index 2b1220b..939bab3 100644 (file)
@@ -1,3 +1,10 @@
+2009-12-10  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/42317
+       * g++.dg/opt/dtor2.C: New test.
+       * g++.dg/opt/dtor2.h: New file.
+       * g++.dg/opt/dtor2-aux.cc: New file.
+
 2009-12-10  Daniel Franke  <franke.daniel@gmail.com>
 
        PR fortran/41369
diff --git a/gcc/testsuite/g++.dg/opt/dtor2-aux.cc b/gcc/testsuite/g++.dg/opt/dtor2-aux.cc
new file mode 100644 (file)
index 0000000..9e87cc8
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do compile }
+// { dg-options "" }
+
+#include "dtor2.h"
+
+A::A () {}
+A::~A () {}
+
+void B::mb () {}
+B::B (int) {}
+B::~B () {}
+
+void C::mc () {}
+C::C (int x) : B (x) {}
+
+D::~D () {}
diff --git a/gcc/testsuite/g++.dg/opt/dtor2.C b/gcc/testsuite/g++.dg/opt/dtor2.C
new file mode 100644 (file)
index 0000000..39b8e69
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/42317
+// { dg-do link }
+// { dg-options "-O0" }
+// { dg-additional-sources "dtor2-aux.cc" }
+
+#include "dtor2.h"
+
+D::D (int x) : C (x) {}
+
+int
+main ()
+{
+}
diff --git a/gcc/testsuite/g++.dg/opt/dtor2.h b/gcc/testsuite/g++.dg/opt/dtor2.h
new file mode 100644 (file)
index 0000000..a869400
--- /dev/null
@@ -0,0 +1,29 @@
+struct A
+{
+  A ();
+  ~A ();
+};
+
+struct B
+{
+  A b;
+  virtual void mb ();
+  B (int);
+  virtual ~B ();
+};
+
+struct C : public B
+{
+  virtual void mc ();
+  C (int);
+  ~C ();
+};
+
+inline C::~C () {}
+
+struct D : public C
+{
+  A d;
+  D (int);
+  ~D ();
+};
index da30ea7..cab2d6b 100644 (file)
@@ -1,3 +1,9 @@
+2009-12-10  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/42317
+       * config/abi/pre/gnu.ver: Don't export certain base dtors that
+       weren't previously exported.
+
 2009-12-10  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR libstdc++/42261 (take 2)
index 20baa96..4ed1cfe 100644 (file)
@@ -72,13 +72,18 @@ GLIBCXX_3.4 {
       std::c[v-z]*;
 #     std::[d-g]*;
       std::d[a-d]*;
-      std::d[f-z]*;
+      std::d[f-n]*;
+      std::domain_error::d*;
+#     std::domain_error::~d*;
+      std::d[p-z]*;
       std::e[a-q]*;
       std::error[^_]*;
       std::e[s-z]*;
       std::gslice*;
       std::h[^a]*;
-      std::i[a-n]*;
+      std::i[a-m]*;
+      std::invalid_argument::i*;
+#     std::invalid_argument::~i*;
 #     std::ios_base::[A-Ha-z]*;
       std::ios_base::[A-Ha-f]*;
       std::ios_base::goodbit;
@@ -94,7 +99,8 @@ GLIBCXX_3.4 {
       std::istrstream*;
       std::i[t-z]*;
       std::[A-Zj-k]*;
-      std::length_error*;
+      std::length_error::l*;
+#     std::length_error::~l*;
       std::logic_error*;
       std::locale::[A-Za-e]*;
       std::locale::facet::[A-Za-z]*;
@@ -122,10 +128,14 @@ GLIBCXX_3.4 {
       std::nu[^m]*;
       std::num[^e]*;
       std::ostrstream*;
-      std::out_of_range*;
-      std::overflow_error*;
+      std::out_of_range::o*;
+#     std::out_of_range::~o*;
+      std::overflow_error::o*;
+#     std::overflow_error::~o*;
 #     std::[p-q]*;
-      std::r[^e]*;
+      std::r[^ae]*;
+      std::range_error::r*;
+#     std::range_error::~r*;
       std::re[^t]*;
 #     std::rethrow_exception
       std::set_new_handler*;
@@ -143,7 +153,8 @@ GLIBCXX_3.4 {
       std::tr1::h[^a]*;
       std::t[s-z]*;
 #     std::[A-Zu-z]*;
-      std::underflow_error*;
+      std::underflow_error::u*;
+#     std::underflow_error::~u*;
       std::uncaught_exception*;
       std::unexpected*;
       std::[A-Zv-z]*;
@@ -284,7 +295,8 @@ GLIBCXX_3.4 {
     _ZNSt15basic_streambufI[cw]St11char_traitsI[cw]EEaSERKS2_;
 
     # std::basic_stringbuf
-    _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EE[CD]*;
+    _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EEC*;
+    _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EED[^2]*;
     _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EE[0-9][a-r]*;
     _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EE[0-9]seek*;
     _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EE[0-9]set*;
@@ -639,6 +651,16 @@ GLIBCXX_3.4 {
     _ZGVNSt[^1]*;
     _ZGVNSt1[^7]*;
 
+    # complete and deleting destructors where base destructors should not
+    # be exported.
+    _ZNSt11range_errorD[01]Ev;
+    _ZNSt12domain_errorD[01]Ev;
+    _ZNSt12length_errorD[01]Ev;
+    _ZNSt12out_of_rangeD[01]Ev;
+    _ZNSt14overflow_errorD[01]Ev;
+    _ZNSt15underflow_errorD[01]Ev;
+    _ZNSt16invalid_argumentD[01]Ev;
+
     # virtual function thunks
     _ZThn8_NS*;
     _ZThn16_NS*;
@@ -891,7 +913,8 @@ GLIBCXX_3.4.10 {
     _ZNSt15basic_streambufI[cw]St11char_traitsI[cw]EE6stosscEv;
 
     _ZN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EE4syncEv;
-    _ZN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EE[5-9CD]*;
+    _ZN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EE[5-9C]*;
+    _ZN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EED[^2]*;
 
 } GLIBCXX_3.4.9;