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
> 
> 

Reply via email to