2009-12-01 Jakub Jelinek PR c++/3187 * optimize.c (cdtor_comdat_group): New function. (maybe_clone_body): Also optimize DECL_COMDAT base/complete cdtors and in that case put also the deleting dtor in the same comdat group as base and complete dtor if dtor is virtual. * config/abi/pre/gnu.ver: Don't export certain base dtors that weren't previously exported. --- gcc/cp/optimize.c.jj 2009-11-30 15:53:13.000000000 +0100 +++ gcc/cp/optimize.c 2009-11-30 19:18:51.000000000 +0100 @@ -142,6 +142,46 @@ build_delete_destructor_body (tree delet } } +/* Return name of comdat group for complete and base ctor (or dtor) + that have the same body. If dtor is virtual, deleting dtor goes + into this comdat group as well. */ + +static tree +cdtor_comdat_group (tree complete, tree base) +{ + tree complete_name = DECL_COMDAT_GROUP (complete); + tree base_name = DECL_COMDAT_GROUP (base); + char *grp_name; + const char *p, *q; + bool diff_seen = false; + size_t idx; + if (complete_name == NULL) + complete_name = cxx_comdat_group (complete); + if (base_name == NULL) + base_name = cxx_comdat_group (base); + gcc_assert (IDENTIFIER_LENGTH (complete_name) + == IDENTIFIER_LENGTH (base_name)); + grp_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (complete_name) + 1); + p = IDENTIFIER_POINTER (complete_name); + q = IDENTIFIER_POINTER (base_name); + for (idx = 0; idx < IDENTIFIER_LENGTH (complete_name); idx++) + if (p[idx] == q[idx]) + grp_name[idx] = p[idx]; + else + { + gcc_assert (!diff_seen + && idx > 0 + && (p[idx - 1] == 'C' || p[idx - 1] == 'D') + && p[idx] == '1' + && q[idx] == '2'); + grp_name[idx] = '5'; + diff_seen = true; + } + grp_name[idx] = '\0'; + gcc_assert (diff_seen); + return get_identifier (grp_name); +} + /* FN is a function that has a complete body. Clone the body as necessary. Returns nonzero if there's no longer any need to process the main body. */ @@ -149,6 +189,7 @@ build_delete_destructor_body (tree delet bool maybe_clone_body (tree fn) { + tree comdat_group = NULL_TREE; tree clone; tree fns[3]; bool first = true; @@ -248,10 +289,20 @@ maybe_clone_body (tree fn) && idx == 1 && !flag_use_repository && DECL_INTERFACE_KNOWN (fns[0]) - && !DECL_ONE_ONLY (fns[0]) + && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fns[0])) + && (!DECL_ONE_ONLY (fns[0]) + || (HAVE_COMDAT_GROUP && DECL_WEAK (fns[0]))) && cgraph_same_body_alias (clone, fns[0])) { alias = true; + if (DECL_ONE_ONLY (fns[0])) + { + /* For comdat base and complete cdtors put them + into the same, *[CD]5* comdat group instead of + *[CD][12]*. */ + comdat_group = cdtor_comdat_group (fns[1], fns[0]); + DECL_COMDAT_GROUP (fns[0]) = comdat_group; + } emit_associated_thunks (clone); } @@ -333,6 +384,15 @@ maybe_clone_body (tree fn) } pop_from_top_level (); + if (comdat_group) + { + 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; + } + /* We don't need to process the original function any further. */ return 1; } --- libstdc++-v3/config/abi/pre/gnu.ver.jj 2009-11-12 14:14:03.000000000 +0100 +++ libstdc++-v3/config/abi/pre/gnu.ver 2009-11-30 20:47:34.000000000 +0100 @@ -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;