On 11/16/25 5:02 AM, Nathaniel Shead wrote:
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?
OK.
-- >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:} } }