aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/module.cc
diff options
context:
space:
mode:
authorNathaniel Shead <nathanieloshead@gmail.com>2024-04-29 17:00:13 +1000
committerNathaniel Shead <nathanieloshead@gmail.com>2024-04-30 15:02:17 +1000
commitb5f6a56940e70838a07e885de03a92e2bd64674a (patch)
tree3a813f9171150f71c9380728386eb35c8ed2dcfb /gcc/cp/module.cc
parent2faf040335f9b49c33ba6d40cf317920f27ce431 (diff)
downloadgcc-b5f6a56940e70838a07e885de03a92e2bd64674a.zip
gcc-b5f6a56940e70838a07e885de03a92e2bd64674a.tar.gz
gcc-b5f6a56940e70838a07e885de03a92e2bd64674a.tar.bz2
c++: Fix instantiation of imported temploid friends [PR114275]
This patch fixes a number of issues with the handling of temploid friend declarations. The primary issue is that instantiations of friend declarations should attach the declaration to the same module as the befriending class, by [module.unit] p7.1 and [temp.friend] p2; this could be a different module from the current TU, and so needs special handling. The other main issue here is that we can't assume that just because name lookup didn't find a definition for a hidden class template, that it doesn't exist at all: it could be a non-exported entity that we've nevertheless streamed in from an imported module. We need to ensure that when instantiating template friend classes that we return the same TEMPLATE_DECL that we got from our imports, otherwise we will get later issues with 'duplicate_decls' (rightfully) complaining that they're different when trying to merge. This doesn't appear necessary for function templates due to the existing name lookup handling already finding these hidden declarations. PR c++/105320 PR c++/114275 gcc/cp/ChangeLog: * cp-tree.h (propagate_defining_module): Declare. (lookup_imported_hidden_friend): Declare. * decl.cc (duplicate_decls): Also check if hidden decls can be redeclared in this module. * module.cc (imported_temploid_friends): New. (init_modules): Initialize it. (trees_out::decl_value): Write it; don't consider imported temploid friends as attached to a module. (trees_in::decl_value): Read it. (get_originating_module_decl): Follow the owning decl for an imported temploid friend. (propagate_defining_module): New. * name-lookup.cc (get_mergeable_namespace_binding): New. (lookup_imported_hidden_friend): New. * pt.cc (tsubst_friend_function): Propagate defining module for new friend functions. (tsubst_friend_class): Lookup imported hidden friends. Check for valid module attachment of existing names. Propagate defining module for new classes. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-10_a.C: New test. * g++.dg/modules/tpl-friend-10_b.C: New test. * g++.dg/modules/tpl-friend-10_c.C: New test. * g++.dg/modules/tpl-friend-10_d.C: New test. * g++.dg/modules/tpl-friend-11_a.C: New test. * g++.dg/modules/tpl-friend-11_b.C: New test. * g++.dg/modules/tpl-friend-12_a.C: New test. * g++.dg/modules/tpl-friend-12_b.C: New test. * g++.dg/modules/tpl-friend-12_c.C: New test. * g++.dg/modules/tpl-friend-12_d.C: New test. * g++.dg/modules/tpl-friend-12_e.C: New test. * g++.dg/modules/tpl-friend-12_f.C: New test. * g++.dg/modules/tpl-friend-13_a.C: New test. * g++.dg/modules/tpl-friend-13_b.C: New test. * g++.dg/modules/tpl-friend-13_c.C: New test. * g++.dg/modules/tpl-friend-13_d.C: New test. * g++.dg/modules/tpl-friend-13_e.C: New test. * g++.dg/modules/tpl-friend-13_f.C: New test. * g++.dg/modules/tpl-friend-13_g.C: New test. * g++.dg/modules/tpl-friend-14_a.C: New test. * g++.dg/modules/tpl-friend-14_b.C: New test. * g++.dg/modules/tpl-friend-14_c.C: New test. * g++.dg/modules/tpl-friend-14_d.C: New test. * g++.dg/modules/tpl-friend-9.C: New test. Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com> Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc/cp/module.cc')
-rw-r--r--gcc/cp/module.cc62
1 files changed, 62 insertions, 0 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index c2f077d..5b8ff5b 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2727,6 +2727,12 @@ vec<tree, va_heap, vl_embed> *post_load_decls;
typedef hash_map<tree, auto_vec<tree>> keyed_map_t;
static keyed_map_t *keyed_table;
+/* Instantiations of temploid friends imported from another module
+ need to be attached to the same module as the temploid. This maps
+ these decls to the temploid they are instantiated them, as there is
+ no other easy way to get this information. */
+static hash_map<tree, tree> *imported_temploid_friends;
+
/********************************************************************/
/* Tree streaming. The tree streaming is very specific to the tree
structures themselves. A tag indicates the kind of tree being
@@ -7820,6 +7826,12 @@ trees_out::decl_value (tree decl, depset *dep)
&& DECL_MODULE_ATTACH_P (not_tmpl))
is_attached = true;
+ /* But don't consider imported temploid friends as attached,
+ since importers will need to merge this decl even if it was
+ attached to a different module. */
+ if (imported_temploid_friends->get (decl))
+ is_attached = false;
+
bits.b (is_attached);
}
bits.b (dep && dep->has_defn ());
@@ -7997,6 +8009,15 @@ trees_out::decl_value (tree decl, depset *dep)
}
}
+ if (TREE_CODE (inner) == FUNCTION_DECL
+ || TREE_CODE (inner) == TYPE_DECL)
+ {
+ /* Write imported temploid friends so that importers can reconstruct
+ this information on stream-in. */
+ tree* slot = imported_temploid_friends->get (decl);
+ tree_node (slot ? *slot : NULL_TREE);
+ }
+
bool is_typedef = false;
if (!type && TREE_CODE (inner) == TYPE_DECL)
{
@@ -8303,6 +8324,11 @@ trees_in::decl_value ()
}
}
+ if (TREE_CODE (inner) == FUNCTION_DECL
+ || TREE_CODE (inner) == TYPE_DECL)
+ if (tree owner = tree_node ())
+ imported_temploid_friends->put (decl, owner);
+
/* Regular typedefs will have a NULL TREE_TYPE at this point. */
unsigned tdef_flags = 0;
bool is_typedef = false;
@@ -18941,6 +18967,12 @@ get_originating_module_decl (tree decl)
&& DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
decl = TYPE_NAME (DECL_CHAIN (decl));
+ /* An imported temploid friend is attached to the same module the
+ befriending class was. */
+ if (imported_temploid_friends)
+ if (tree *slot = imported_temploid_friends->get (decl))
+ decl = *slot;
+
int use;
if (tree ti = node_template_info (decl, use))
{
@@ -19249,6 +19281,34 @@ maybe_key_decl (tree ctx, tree decl)
vec.safe_push (decl);
}
+/* DECL is an instantiated friend that should be attached to the same
+ module that ORIG is. */
+
+void
+propagate_defining_module (tree decl, tree orig)
+{
+ if (!modules_p ())
+ return;
+
+ tree not_tmpl = STRIP_TEMPLATE (orig);
+ if (DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_ATTACH_P (not_tmpl))
+ {
+ tree inner = STRIP_TEMPLATE (decl);
+ retrofit_lang_decl (inner);
+ DECL_MODULE_ATTACH_P (inner) = true;
+ }
+
+ if (DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_IMPORT_P (not_tmpl))
+ {
+ bool exists = imported_temploid_friends->put (decl, orig);
+
+ /* We should only be called if lookup for an existing decl
+ failed, in which case there shouldn't already be an entry
+ in the map. */
+ gcc_assert (!exists);
+ }
+}
+
/* Create the flat name string. It is simplest to have it handy. */
void
@@ -20462,6 +20522,8 @@ init_modules (cpp_reader *reader)
pending_table = new pending_map_t (EXPERIMENT (1, 400));
entity_map = new entity_map_t (EXPERIMENT (1, 400));
vec_safe_reserve (entity_ary, EXPERIMENT (1, 400));
+ imported_temploid_friends
+ = new hash_map<tree,tree> (EXPERIMENT (1, 400));
}
#if CHECKING_P