On Fri, 22 Aug 2025, Nathaniel Shead wrote: > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? > > -- >8 -- > > In the PR, we're getting a linker error from _Vector_impl's destructor > never getting emitted. This is because of a combination of factors: > > 1. in imp-member-4_a, the destructor is not used and so there is no > definition generated. > > 2. in imp-member-4_b, the destructor gets synthesized (as part of the > synthesis for Coll's destructor) but is not ODR-used and so does not > get emitted. Despite there being a definition provided in this TU, > the destructor is still considered imported and so isn't streamed > into the module body. > > 3. in imp-member-4_c, we need to ODR-use the destructor but we only got > a forward declaration from imp-member-4_b, so we cannot emit a body. > > The point of failure here is step 2; this function has effectively been > declared in the imp-member-4_b module, and so we shouldn't treat it as > imported. This way we'll properly stream the body so that importers can > emit it.
Nice analysis and fix! What do you think about backporting this to 15? > > PR c++/120499 > > gcc/cp/ChangeLog: > > * method.cc (synthesize_method): Set the instantiating module. > > gcc/testsuite/ChangeLog: > > * g++.dg/modules/imp-member-4_a.C: New test. > * g++.dg/modules/imp-member-4_b.C: New test. > * g++.dg/modules/imp-member-4_c.C: New test. > > Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> > --- > gcc/cp/method.cc | 3 +++ > gcc/testsuite/g++.dg/modules/imp-member-4_a.C | 25 +++++++++++++++++++ > gcc/testsuite/g++.dg/modules/imp-member-4_b.C | 17 +++++++++++++ > gcc/testsuite/g++.dg/modules/imp-member-4_c.C | 14 +++++++++++ > 4 files changed, 59 insertions(+) > create mode 100644 gcc/testsuite/g++.dg/modules/imp-member-4_a.C > create mode 100644 gcc/testsuite/g++.dg/modules/imp-member-4_b.C > create mode 100644 gcc/testsuite/g++.dg/modules/imp-member-4_c.C > > diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc > index 397e496ed47..ef8370fac5b 100644 > --- a/gcc/cp/method.cc > +++ b/gcc/cp/method.cc > @@ -1851,6 +1851,9 @@ synthesize_method (tree fndecl) > finish_function_body (stmt); > finish_function (/*inline_p=*/false); > > + /* Remember that we were defined in this module. */ > + set_instantiating_module (fndecl); > + > if (!DECL_DELETED_FN (fndecl)) > expand_or_defer_fn (fndecl); > > diff --git a/gcc/testsuite/g++.dg/modules/imp-member-4_a.C > b/gcc/testsuite/g++.dg/modules/imp-member-4_a.C > new file mode 100644 > index 00000000000..f0699eb314c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/imp-member-4_a.C > @@ -0,0 +1,25 @@ > +// PR c++/120499 > +// { dg-additional-options "-fmodules -fdump-lang-module-blocks" } > +// { dg-module-cmi A } > + > +export module A; > + > +struct allocator { > + ~allocator() {} > +}; > + > +export template <typename _Tp> > +struct vector { > + struct _Vector_impl : public allocator {}; > + _Vector_impl _M_impl; > + vector() = default; > +}; > + > +template <typename T> > +struct regex_token_iterator { > + vector<int> _M_subs; > +}; > +template struct regex_token_iterator<const char*>; > + > +// No definition of _Vector_impl::~_Vector_impl here (not synthesized) > +// { dg-final { scan-lang-dump-not > {'::vector@A:1<int>::_Vector_impl@A:1<int>::__dt '} module } } > diff --git a/gcc/testsuite/g++.dg/modules/imp-member-4_b.C > b/gcc/testsuite/g++.dg/modules/imp-member-4_b.C > new file mode 100644 > index 00000000000..db485095e77 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/imp-member-4_b.C > @@ -0,0 +1,17 @@ > +// PR c++/120499 > +// { dg-additional-options "-fmodules -fdump-lang-module-blocks" } > +// { dg-module-cmi B } > + > +export module B; > +import A; > + > +struct Coll { > + vector<int> vals; > +}; > + > +export Coll createColl() { > + return Coll{}; > +} > + > +// But the definition of _Vector_impl::~_Vector_impl has been synthesized > here > +// { dg-final { scan-lang-dump-times {\[0\]=decl definition > '::vector@A:1<int>::_Vector_impl@A:1<int>::__dt '} 1 module } } > diff --git a/gcc/testsuite/g++.dg/modules/imp-member-4_c.C > b/gcc/testsuite/g++.dg/modules/imp-member-4_c.C > new file mode 100644 > index 00000000000..d405ce28bf7 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/imp-member-4_c.C > @@ -0,0 +1,14 @@ > +// PR c++/120499 > +// { dg-module-do link } > +// { dg-additional-options "-fmodules -fdump-lang-module" } > + > +import B; > + > +int main() { > + createColl(); > +} > + > +// And we should use the definition of _Vector_impl::~_Vector_impl now. > +// In this case we got the seeded import from A of the declaration > +// so let's just ensure we stream the definition. > +// { dg-final { scan-lang-dump {Reading function definition > '::vector@A:1<int>::_Vector_impl@A:1<int>::__dt @A:1'} module } } > -- > 2.47.0 > >