Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? And 15 (I guess after the release has been made)?
-- >8 -- In r15-9029-geb26b667518c95, we started checking for conflicting declarations with any reachable decl attached to the same originating module. This exposed the issue in the PR, where we would always create a new type even if a matching type existed in the original module. This patch reworks lookup_imported_hidden_friend to handle this case better, by first checking for any reachable decl in the attached module before looking in the mergeable decl slots. PR c++/119863 gcc/cp/ChangeLog: * name-lookup.cc (get_mergeable_namespace_binding): Remove no-longer-used function. (lookup_imported_hidden_friend): Also look for hidden imported decls in an attached decl's module. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-18_a.C: New test. * g++.dg/modules/tpl-friend-18_b.C: New test. * g++.dg/modules/tpl-friend-18_c.C: New test. Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> --- gcc/cp/name-lookup.cc | 43 ++++++++++--------- .../g++.dg/modules/tpl-friend-18_a.C | 25 +++++++++++ .../g++.dg/modules/tpl-friend-18_b.C | 9 ++++ .../g++.dg/modules/tpl-friend-18_c.C | 10 +++++ 4 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-18_a.C create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-18_b.C create mode 100644 gcc/testsuite/g++.dg/modules/tpl-friend-18_c.C diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 498126a191a..165c26bb578 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -4178,22 +4178,6 @@ mergeable_namespace_slots (tree ns, tree name, bool is_attached, tree *vec) return vslot; } -/* Retrieve the bindings for an existing mergeable entity in namespace - NS slot NAME. Returns NULL if no such bindings exists. */ - -static tree -get_mergeable_namespace_binding (tree ns, tree name, bool is_attached) -{ - tree *mslot = find_namespace_slot (ns, name, false); - if (!mslot || !*mslot || TREE_CODE (*mslot) != BINDING_VECTOR) - return NULL_TREE; - - tree *vslot = get_fixed_binding_slot - (mslot, name, is_attached ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, - false); - return vslot ? *vslot : NULL_TREE; -} - /* DECL is a new mergeable namespace-scope decl. Add it to the mergeable entities on GSLOT. */ @@ -4574,9 +4558,9 @@ lookup_imported_hidden_friend (tree friend_tmpl) lazy_load_pendings (friend_tmpl); - tree bind = get_mergeable_namespace_binding - (current_namespace, DECL_NAME (inner), DECL_MODULE_ATTACH_P (inner)); - if (!bind) + tree name = DECL_NAME (inner); + tree *slot = find_namespace_slot (current_namespace, name, false); + if (!slot || !*slot || TREE_CODE (*slot) != BINDING_VECTOR) return NULL_TREE; /* We're only interested in declarations attached to the same module @@ -4584,9 +4568,28 @@ lookup_imported_hidden_friend (tree friend_tmpl) int m = get_originating_module (friend_tmpl, /*global=-1*/true); gcc_assert (m != 0); + /* First check whether there's a reachable declaration attached to the module + we're looking for. */ + if (m > 0) + if (binding_slot *mslot = search_imported_binding_slot (slot, m)) + { + if (mslot->is_lazy ()) + lazy_load_binding (m, current_namespace, name, mslot); + for (ovl_iterator iter (*mslot); iter; ++iter) + if (DECL_CLASS_TEMPLATE_P (*iter)) + return *iter; + } + + /* Otherwise, look in the mergeable slots for this name, in case an importer + has already instantiated this declaration. */ + tree *vslot = get_fixed_binding_slot + (slot, name, m > 0 ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, false); + if (!vslot || !*vslot) + return NULL_TREE; + /* There should be at most one class template from the module we're looking for, return it. */ - for (ovl_iterator iter (bind); iter; ++iter) + for (ovl_iterator iter (*vslot); iter; ++iter) if (DECL_CLASS_TEMPLATE_P (*iter) && get_originating_module (*iter, true) == m) return *iter; diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-18_a.C b/gcc/testsuite/g++.dg/modules/tpl-friend-18_a.C new file mode 100644 index 00000000000..333c9764ce0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-18_a.C @@ -0,0 +1,25 @@ +// PR c++/119863 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi A } + +export module A; + +template<typename> +class T; + +template<typename> +class U +{ + template<typename> + friend class T; +}; + +template<typename V> +class T +{ + U<V> x = {}; +}; + +export +template<typename V> +T<V> f(V) { return {}; } diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-18_b.C b/gcc/testsuite/g++.dg/modules/tpl-friend-18_b.C new file mode 100644 index 00000000000..2e537edcd4d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-18_b.C @@ -0,0 +1,9 @@ +// PR c++/119863 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi B } + +export module B; + +// this should not be considered conflicting +template <typename> +class T; diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-18_c.C b/gcc/testsuite/g++.dg/modules/tpl-friend-18_c.C new file mode 100644 index 00000000000..6c8d85b1290 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-18_c.C @@ -0,0 +1,10 @@ +// PR c++/119863 +// { dg-additional-options "-fmodules" } + +import A; +import B; + +int main() +{ + auto const x = f(1); +} -- 2.47.0