On 3/26/25 9:23 AM, Nathaniel Shead wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
-- >8 --
When doing tsubst_friend_class, we need to first check if any imported
module has already created a (hidden) declaration for the class so that
we don't end up with conflicting declarations. Currently we do this
using DECL_MODULE_IMPORT_P, but this is not set in cases where the class
is in the global module and matches an existing GM declaration we've
seen (via an include, for example).
This patch fixes this by checking DECL_MODULE_ENTITY_P instead, which is
set on all entities that have been seen from a module import. We also
use the 'for_mangle' version of get_originating_module so that we don't
treat imported GM entities as attached to the module we imported them
from.
I had actually made the same change on my branch to get the libstdc++
testsuite running with modules, I just haven't gotten around to merging
it because I hadn't come up with a reduced testcase. Here's a patch
that merges mine with yours, does it work for you?
From af6f9df393363a6afde28ba01c29e16d98db0fe4 Mon Sep 17 00:00:00 2001
From: Nathaniel Shead <nathanielosh...@gmail.com>
Date: Thu, 27 Mar 2025 00:23:24 +1100
Subject: [PATCH] c++/modules: Fix tsubst of global module friend classes
[PR118920]
To: gcc-patches@gcc.gnu.org
When doing tsubst_friend_class, we need to first check if any imported
module has already created a (hidden) declaration for the class so that
we don't end up with conflicting declarations. Currently we do this
using DECL_MODULE_IMPORT_P, but this is not set in cases where the class
is in the global module and matches an existing GM declaration we've
seen (via an include, for example).
This patch fixes this by checking DECL_MODULE_ENTITY_P instead, which is
set on all entities that have been seen from a module import. We also
use the 'for_mangle' version of get_originating_module so that we don't
treat imported GM entities as attached to the module we imported them
from. And rename that parameter to something more general.
And dump_module_suffix is another place where we want to treat global module
entities as not coming from a module.
PR c++/118920
gcc/cp/ChangeLog:
* name-lookup.cc (lookup_imported_hidden_friend): Check for
module entity rather than just module import.
* module.cc (get_originating_module): Rename for_mangle parm to
global_m1.
* error.cc (dump_module_suffix): Don't decorate global module decls.
gcc/testsuite/ChangeLog:
* g++.dg/modules/tpl-friend-17.h: New test.
* g++.dg/modules/tpl-friend-17_a.C: New test.
* g++.dg/modules/tpl-friend-17_b.C: New test.
Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
Co-authored-by: Jason Merrill <ja...@redhat.com>
---
gcc/testsuite/g++.dg/modules/tpl-friend-17.h | 8 ++++++++
gcc/cp/error.cc | 3 ++-
gcc/cp/module.cc | 12 ++++++++----
gcc/cp/name-lookup.cc | 10 +++++-----
gcc/testsuite/g++.dg/modules/tpl-friend-17_a.C | 9 +++++++++
gcc/testsuite/g++.dg/modules/tpl-friend-17_b.C | 11 +++++++++++
6 files changed, 43 insertions(+), 10 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-17.h
create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-17_a.C
create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-17_b.C
diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-17.h b/gcc/testsuite/g++.dg/modules/tpl-friend-17.h
new file mode 100644
index 00000000000..429ab3d5977
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-friend-17.h
@@ -0,0 +1,8 @@
+// PR c++/118920
+
+template <typename> struct unique_ptr {
+ template <typename> friend class out_ptr_t;
+};
+template <typename> struct shared_ptr {
+ template <typename> friend class out_ptr_t;
+};
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 72e16958548..ec7527e96d1 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -308,7 +308,8 @@ dump_module_suffix (cxx_pretty_printer *pp, tree decl)
return;
}
- if (unsigned m = get_originating_module (decl))
+ int m = get_originating_module (decl, /*global=-1*/true);
+ if (m > 0)
if (const char *n = module_name (m, false))
{
pp_character (pp, '@');
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 2cded878c64..f2d64bf3b5f 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -20371,20 +20371,24 @@ get_originating_module_decl (tree decl)
return decl;
}
+/* If DECL is imported, return which module imported it, or 0 for the current
+ module. Except that if GLOBAL_M1, return -1 for decls attached to the
+ global module. */
+
int
-get_originating_module (tree decl, bool for_mangle)
+get_originating_module (tree decl, bool global_m1)
{
tree owner = get_originating_module_decl (decl);
tree not_tmpl = STRIP_TEMPLATE (owner);
if (!DECL_LANG_SPECIFIC (not_tmpl))
- return for_mangle ? -1 : 0;
+ return global_m1 ? -1 : 0;
- if (for_mangle && !DECL_MODULE_ATTACH_P (not_tmpl))
+ if (global_m1 && !DECL_MODULE_ATTACH_P (not_tmpl))
return -1;
int mod = !DECL_MODULE_IMPORT_P (not_tmpl) ? 0 : get_importing_module (owner);
- gcc_checking_assert (!for_mangle || !(*modules)[mod]->is_header ());
+ gcc_checking_assert (!global_m1 || !(*modules)[mod]->is_header ());
return mod;
}
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 742e5d289dc..7f1ee869d52 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -4568,7 +4568,7 @@ lookup_imported_hidden_friend (tree friend_tmpl)
tree inner = DECL_TEMPLATE_RESULT (friend_tmpl);
if (!DECL_LANG_SPECIFIC (inner)
- || !DECL_MODULE_IMPORT_P (inner))
+ || !DECL_MODULE_ENTITY_P (inner))
return NULL_TREE;
lazy_load_pendings (friend_tmpl);
@@ -4578,16 +4578,16 @@ lookup_imported_hidden_friend (tree friend_tmpl)
if (!bind)
return NULL_TREE;
- /* We're only interested in declarations coming from the same module
- of the friend class we're attempting to instantiate. */
- int m = get_originating_module (friend_tmpl);
+ /* We're only interested in declarations attached to the same module
+ as the friend class we're attempting to instantiate. */
+ int m = get_originating_module (friend_tmpl, /*global=-1*/true);
gcc_assert (m != 0);
/* There should be at most one class template from the module we're
looking for, return it. */
for (ovl_iterator iter (bind); iter; ++iter)
if (DECL_CLASS_TEMPLATE_P (*iter)
- && get_originating_module (*iter) == m)
+ && get_originating_module (*iter, true) == m)
return *iter;
return NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-17_a.C b/gcc/testsuite/g++.dg/modules/tpl-friend-17_a.C
new file mode 100644
index 00000000000..7c5a3ac7ed1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-friend-17_a.C
@@ -0,0 +1,9 @@
+// PR c++/118920
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi M }
+
+module;
+#include "tpl-friend-17.h"
+export module M;
+unique_ptr<int> s;
+export template <typename> void foo() { shared_ptr<int> u; }
diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-17_b.C b/gcc/testsuite/g++.dg/modules/tpl-friend-17_b.C
new file mode 100644
index 00000000000..33586e662ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-friend-17_b.C
@@ -0,0 +1,11 @@
+// PR c++/118920
+// { dg-additional-options "-fmodules" }
+
+#include "tpl-friend-17.h"
+import M;
+
+int main() {
+ // instantiating shared_ptr<int> should find previously generated
+ // out_ptr_t template from the unique_ptr<int> instantiation
+ foo<int>();
+}
--
2.49.0