diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1dbb577a38d7dac2c5dd91e3220cf165a66682c5..bafdf63dc63b6fbdd841b1db6ea5dbae4c7af51e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7447,6 +7447,7 @@ extern bool handle_module_option (unsigned opt, const char *arg, int value); /* In optimize.cc */ extern tree clone_attrs (tree); extern bool maybe_clone_body (tree); +extern void maybe_optimize_cdtor (tree); /* In parser.cc */ extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool, diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 1339f210dde52460b72d377e64e38719e1cb9a42..806a2a4bc69d0131825d1c7fd668a4e073219812 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -3568,6 +3568,9 @@ import_export_decl (tree decl) } DECL_INTERFACE_KNOWN (decl) = 1; + + if (DECL_CLONED_FUNCTION_P (decl)) + maybe_optimize_cdtor (decl); } /* Return an expression that performs the destruction of DECL, which diff --git a/gcc/cp/optimize.cc b/gcc/cp/optimize.cc index ff4fb5be5bd9daa51fa62c696a8f2e2cec90b045..7147f5e00f1331a17a06918e1c034d0723df43ea 100644 --- a/gcc/cp/optimize.cc +++ b/gcc/cp/optimize.cc @@ -723,3 +723,58 @@ maybe_clone_body (tree fn) /* We don't need to process the original function any further. */ return 1; } + +/* If maybe_clone_body is called while the cdtor is still tentative, + DECL_ONE_ONLY will be false and so will be can_alias_cdtor (fn). + In that case we wouldn't try to optimize using an alias and instead + would emit separate base and complete cdtor. The following function + attempts to still optimize that case when we import_export_decl + is called first time on one of the clones. */ + +void +maybe_optimize_cdtor (tree orig_decl) +{ + tree fns[3]; + tree fn = DECL_CLONED_FUNCTION (orig_decl); + gcc_checking_assert (DECL_MAYBE_IN_CHARGE_CDTOR_P (fn)); + if (DECL_INTERFACE_KNOWN (fn) + || !TREE_ASM_WRITTEN (fn) + || !DECL_ONE_ONLY (orig_decl) + || symtab->global_info_ready) + return; + + populate_clone_array (fn, fns); + + if (!fns[0] || !fns[1]) + return; + for (int i = 2 - !fns[2]; i >= 0; --i) + if (fns[i] != orig_decl && DECL_INTERFACE_KNOWN (fns[i])) + return; + DECL_INTERFACE_KNOWN (fn) = 1; + comdat_linkage (fn); + if (!can_alias_cdtor (fn)) + return; + /* For comdat base and complete cdtors put them into the same, + *[CD]5* comdat group instead of *[CD][12]*. */ + auto n0 = cgraph_node::get_create (fns[0]); + auto n1 = cgraph_node::get_create (fns[1]); + auto n2 = fns[2] ? cgraph_node::get_create (fns[1]) : NULL; + if (n0->lowered || n1->lowered || (n2 && n2->lowered)) + return; + import_export_decl (fns[0]); + n1->definition = false; + if (!n0->create_same_body_alias (fns[1], fns[0])) + return; + + tree comdat_group = cdtor_comdat_group (fns[1], fns[0]); + n1 = cgraph_node::get (fns[1]); + n0->set_comdat_group (comdat_group); + if (n1->same_comdat_group) + n1->remove_from_same_comdat_group (); + n1->add_to_same_comdat_group (n0); + if (fns[2]) + n2->add_to_same_comdat_group (n0); + import_export_decl (fns[1]); + /* Remove the body now that it is an alias. */ + release_function_body (fns[1]); +} diff --git a/gcc/testsuite/g++.dg/abi/comdat2.C b/gcc/testsuite/g++.dg/abi/comdat2.C new file mode 100644 index 0000000000000000000000000000000000000000..502d00c0582638120da15721b060d342dd7b09d3 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/comdat2.C @@ -0,0 +1,26 @@ +// PR lto/113208 +// { dg-do compile { target { c++11 && { *-*-*gnu* } } } } +// { dg-additional-options "-O2 -fkeep-inline-functions" } +// { dg-final { scan-assembler "_ZN1BI1CEC5ERKS1_,comdat" } } +// { dg-final { scan-assembler-not "_ZN1BI1CEC1ERKS1_,comdat" } } +// { dg-final { scan-assembler-not "_ZN1BI1CEC2ERKS1_,comdat" } } + +template <typename T> +struct A { + int foo () const; + A (int, int); +}; +template <typename T> +struct B : A<T> { + constexpr B (const B &x) : A<T> (1, x.foo ()) {} + B () : A<T> (1, 2) {} +}; +struct C; +struct D : B<C> {}; +void bar (D); + +void +baz (D x) +{ + bar (x); +} diff --git a/gcc/testsuite/g++.dg/abi/comdat5.C b/gcc/testsuite/g++.dg/abi/comdat5.C new file mode 100644 index 0000000000000000000000000000000000000000..f6542aa0d4c150093a367cf8bb4eab9d5801701d --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/comdat5.C @@ -0,0 +1,28 @@ +// PR lto/113208 +// { dg-do compile { target { c++11 && { *-*-*gnu* } } } } +// { dg-additional-options "-O2" } +// { dg-final { scan-assembler-not "_ZN1BI1CEC5ERKS1_,comdat" } } +// { dg-final { scan-assembler-not "_ZN1BI1CEC1ERKS1_,comdat" } } +// { dg-final { scan-assembler-not "_ZN1BI1CEC2ERKS1_,comdat" } } + +template <typename T> +struct A { + int foo () const; + A (int, int); +}; +template <typename T> +struct B : A<T> { + constexpr B (const B &x) : A<T> (1, x.foo ()) {} + B () : A<T> (1, 2) {} +}; +struct C; +struct D : B<C> {}; +void bar (D); + +void +baz (D x) +{ + bar (x); +} + +extern template struct B<C>; diff --git a/gcc/testsuite/g++.dg/lto/pr113208.h b/gcc/testsuite/g++.dg/lto/pr113208.h new file mode 100644 index 0000000000000000000000000000000000000000..7901ede7e921f63fc60637ef7a413b1d1f95917b --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr113208.h @@ -0,0 +1,10 @@ +template <typename _Tp> struct _Vector_base { + int g() const; + _Vector_base(int, int); +}; +template <typename _Tp> +struct vector : _Vector_base<_Tp> { + CONSTEXPR vector(const vector &__x) + : _Vector_base<_Tp>(1, __x.g()) {} + vector() : _Vector_base<_Tp>(1, 2) {} +}; diff --git a/gcc/testsuite/g++.dg/lto/pr113208_0.C b/gcc/testsuite/g++.dg/lto/pr113208_0.C new file mode 100644 index 0000000000000000000000000000000000000000..dbaca558d31e5397208529a16160c1fa74bf70de --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr113208_0.C @@ -0,0 +1,13 @@ +// { dg-lto-do link } +// { dg-lto-options { {-O1 -std=c++20 -flto}} } +// { dg-extra-ld-options "-r -nostdlib -flinker-output=nolto-rel" } +// { dg-require-linker-plugin "" } + +#define CONSTEXPR constexpr +#include "pr113208.h" + +struct QualityValue; +struct k : vector<QualityValue> {}; + +void m(k); +void n(k i) { m(i); } diff --git a/gcc/testsuite/g++.dg/lto/pr113208_1.C b/gcc/testsuite/g++.dg/lto/pr113208_1.C new file mode 100644 index 0000000000000000000000000000000000000000..f925086b527a54f072ef7d6b26ae6be3f380446d --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr113208_1.C @@ -0,0 +1,6 @@ +#define CONSTEXPR +#include "pr113208.h" + +struct QualityValue; +vector<QualityValue> values1; +vector<QualityValue> values{values1};