From 61c2c7b1e5623d1add0d7281d218f0073dab1943 Mon Sep 17 00:00:00 2001 From: jakub Date: Thu, 10 Dec 2009 21:58:49 +0000 Subject: [PATCH] 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. * 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 --- gcc/ChangeLog | 26 ++++++++++++++++++ gcc/cgraph.c | 17 +++++++++++- gcc/cgraph.h | 2 ++ gcc/cgraphunit.c | 51 +++++++++++++++++++++++++++++++++-- gcc/cp/ChangeLog | 9 +++++++ gcc/cp/decl2.c | 19 ++++++++++++- gcc/cp/optimize.c | 22 ++++++++------- gcc/ipa-inline.c | 7 ++++- gcc/ipa.c | 42 ++++++++++++++++++++++++++--- gcc/lto-cgraph.c | 47 ++++++++++++++++++++++++++++++-- gcc/testsuite/ChangeLog | 7 +++++ gcc/testsuite/g++.dg/opt/dtor2-aux.cc | 16 +++++++++++ gcc/testsuite/g++.dg/opt/dtor2.C | 13 +++++++++ gcc/testsuite/g++.dg/opt/dtor2.h | 29 ++++++++++++++++++++ libstdc++-v3/ChangeLog | 6 +++++ libstdc++-v3/config/abi/pre/gnu.ver | 41 +++++++++++++++++++++------- 16 files changed, 325 insertions(+), 29 deletions(-) create mode 100644 gcc/testsuite/g++.dg/opt/dtor2-aux.cc create mode 100644 gcc/testsuite/g++.dg/opt/dtor2.C create mode 100644 gcc/testsuite/g++.dg/opt/dtor2.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b027bc9..79fb7b1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2009-12-10 Jakub Jelinek + + 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 PR middle-end/42228 diff --git a/gcc/cgraph.c b/gcc/cgraph.c index a3efdfc..0ed097a 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -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. */ diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 51426e6..268e6d4 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -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; diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 58bdd85..cf1a001 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -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 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bb3f8f9..c98e68a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2009-12-10 Jakub Jelinek + + 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 PR c++/42010 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index faa3c9d..d4a866a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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 diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 9210a80..325df8f 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -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. */ diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 120c234..b146d0b 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -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); diff --git a/gcc/ipa.c b/gcc/ipa.c index 708b800..b1844db 100644 --- 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))) diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 309a1e6..e02999d 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2b1220b..939bab3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2009-12-10 Jakub Jelinek + + 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 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 index 0000000..9e87cc8 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/dtor2-aux.cc @@ -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 index 0000000..39b8e69 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/dtor2.C @@ -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 index 0000000..a869400 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/dtor2.h @@ -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 (); +}; diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index da30ea7..cab2d6b 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,9 @@ +2009-12-10 Jakub Jelinek + + PR c++/42317 + * config/abi/pre/gnu.ver: Don't export certain base dtors that + weren't previously exported. + 2009-12-10 Paolo Carlini PR libstdc++/42261 (take 2) diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 20baa96..4ed1cfe 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -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; -- 2.7.4