On Sat, Nov 15, 2025 at 10:54:55PM +1100, Nathaniel Shead wrote:
> On Sat, Nov 15, 2025 at 10:32:00AM +0530, Jason Merrill wrote:
> > On 11/15/25 9:47 AM, Nathaniel Shead wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk and 15?
> > > 
> > > -- >8 --
> > > 
> > > r16-4930-gfd5c057c2d01 ensured that we noted all class-scope variables.
> > > But I also added a clause to 'read_var_def' to skip all class-scope
> > > instantiations, under the mistaken belief that this would be handled in
> > > read_class_def.
> > > 
> > > But as the testcase shows, read_class_def cannot (and should not)
> > > register instantiations of member variable templates, as when reading
> > > the class it just sees the template declaration.  So this patch removes
> > > the constraint from read_var_def.
> > > 
> > > This may cause us to note some variables more than once but I think
> > > that's unlikely to be a large problem, and adding more constraints may
> > > hit another case that I'm not thinking of.
> > 
> > OK, but I wonder if checking primary_template_specialization_p would help
> > avoid the extras?
> 
> Thanks.  The following patch instead of the above does seem to work and
> avoid these issues:
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index ccabd640757..2b3a9301b6c 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -13062,8 +13062,10 @@ trees_in::read_var_def (tree decl, tree 
> maybe_template)
>            if (DECL_EXPLICIT_INSTANTIATION (decl)
>                && !DECL_EXTERNAL (decl))
>              setup_explicit_instantiation_definition_linkage (decl);
> -          /* Class static data members are handled in read_class_def.  */
> -          if (!DECL_CLASS_SCOPE_P (decl)
> +          /* Class non-template static members are handled in read_class_def.
> +             But still handle specialisations of member templates.  */
> +          if ((!DECL_CLASS_SCOPE_P (decl)
> +               || primary_template_specialization_p (decl))
>                && (DECL_IMPLICIT_INSTANTIATION (decl)
>                    || (DECL_EXPLICIT_INSTANTIATION (decl)
>                        && !DECL_EXTERNAL (decl))))
> 
> I might submit the first patch for trunk and 15 now though, and will do
> some more thorough testing of this (e.g. partial specs) later just for
> 16, if that's OK.
> 

Actually found some time to do some more testing and seems to work fine.
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/15?

-- >8 --

r16-4930-gfd5c057c2d01 ensured that we noted all class-scope variables.
But I also added a clause to 'read_var_def' to skip all class-scope
instantiations, under the mistaken belief that this would be handled in
read_class_def.

But as the testcase shows, read_class_def cannot (and should not)
register instantiations of member variable templates, as when reading
the class it just sees the template declaration.  So this patch
re-enables tracking instantiations of class-scope variable templates.

        PR c++/122625

gcc/cp/ChangeLog:

        * module.cc (trees_in::read_var_def): Also track class-scope
        primary template specialisations.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/inst-7_a.C: New test.
        * g++.dg/modules/inst-7_b.C: New test.

Signed-off-by: Nathaniel Shead <[email protected]>
Reviewed-by: Jason Merrill <[email protected]>
---
 gcc/cp/module.cc                        |  6 +++--
 gcc/testsuite/g++.dg/modules/inst-7_a.C | 33 +++++++++++++++++++++++++
 gcc/testsuite/g++.dg/modules/inst-7_b.C | 13 ++++++++++
 3 files changed, 50 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/inst-7_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/inst-7_b.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index ccabd640757..2b3a9301b6c 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13062,8 +13062,10 @@ trees_in::read_var_def (tree decl, tree maybe_template)
          if (DECL_EXPLICIT_INSTANTIATION (decl)
              && !DECL_EXTERNAL (decl))
            setup_explicit_instantiation_definition_linkage (decl);
-         /* Class static data members are handled in read_class_def.  */
-         if (!DECL_CLASS_SCOPE_P (decl)
+         /* Class non-template static members are handled in read_class_def.
+            But still handle specialisations of member templates.  */
+         if ((!DECL_CLASS_SCOPE_P (decl)
+              || primary_template_specialization_p (decl))
              && (DECL_IMPLICIT_INSTANTIATION (decl)
                  || (DECL_EXPLICIT_INSTANTIATION (decl)
                      && !DECL_EXTERNAL (decl))))
diff --git a/gcc/testsuite/g++.dg/modules/inst-7_a.C 
b/gcc/testsuite/g++.dg/modules/inst-7_a.C
new file mode 100644
index 00000000000..7489edfa252
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-7_a.C
@@ -0,0 +1,33 @@
+// PR c++/122625
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi M }
+
+export module M;
+struct integral_constant {
+  void f() const {}
+};
+struct span {
+  template <int> static constexpr integral_constant __v{};
+  template <int, int> static constexpr integral_constant partial{};
+};
+template <int x> constexpr integral_constant span::partial<x, 0>{};
+
+template <typename T>
+struct nested {
+  template <typename U> static const U arr[3];
+};
+template <typename T>
+struct nested<T*> {
+  template <typename U> static const U arr[3];
+};
+template <typename T> template <typename U> const U nested<T>::arr[3] = {};
+template <typename T> template <typename U> const U nested<T*>::arr[3] = {};
+template <typename T> template <typename U> const U nested<T*>::arr<U*>[3] = 
{};
+
+export inline void format() {
+  span::__v<1>.f();
+  span::partial<5, 0>.f();
+  nested<int>::arr<integral_constant>[0].f();
+  nested<int*>::arr<integral_constant>[0].f();
+  nested<int*>::arr<integral_constant*>[0].f();
+}
diff --git a/gcc/testsuite/g++.dg/modules/inst-7_b.C 
b/gcc/testsuite/g++.dg/modules/inst-7_b.C
new file mode 100644
index 00000000000..3a49b516bea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inst-7_b.C
@@ -0,0 +1,13 @@
+// PR c++/122625
+// { dg-additional-options "-fmodules" }
+
+import M;
+int main() {
+  format();
+}
+
+// { dg-final { scan-assembler {_ZNW1M4span3__vILi1EEE:} } }
+// { dg-final { scan-assembler {_ZNW1M4span7partialILi5ELi0EEE:} } }
+// { dg-final { scan-assembler {_ZNW1M6nestedIiE3arrIS_17integral_constantEE:} 
} }
+// { dg-final { scan-assembler 
{_ZNW1M6nestedIPiE3arrIS_17integral_constantEE:} } }
+// { dg-final { scan-assembler 
{_ZNW1M6nestedIPiE3arrIPS_17integral_constantEE:} } }
-- 
2.51.0

Reply via email to