extern void set_defining_module_for_partial_spec (tree);
extern void maybe_key_decl (tree ctx, tree decl);
extern void propagate_defining_module (tree decl, tree orig);
+extern void transfer_defining_module (tree olddecl, tree newdecl);
extern void remove_defining_module (tree decl);
extern void mangle_module (int m, bool include_partition);
else
DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
+ /* Transfer purviewness and importingness to the old decl. */
+ transfer_defining_module (olddecl, newdecl);
+
if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
tree old_result = DECL_TEMPLATE_RESULT (olddecl);
}
}
- /* Propagate purviewness and importingness as with
- set_instantiating_module, unless newdecl is a friend injection. */
- if (modules_p () && DECL_LANG_SPECIFIC (new_result)
- && !(TREE_CODE (new_result) == FUNCTION_DECL
- && DECL_UNIQUE_FRIEND_P (new_result)))
- {
- if (DECL_MODULE_PURVIEW_P (new_result))
- DECL_MODULE_PURVIEW_P (old_result) = true;
- if (!DECL_MODULE_IMPORT_P (new_result))
- DECL_MODULE_IMPORT_P (old_result) = false;
- }
-
/* If the new declaration is a definition, update the file and
line information on the declaration, and also make
the old declaration the same definition. */
/* Set when importing the primary module interface. */
imp = imp->parent;
+ /* Ensure this is actually a module unit. */
+ gcc_checking_assert (imp);
+
imp->mangle (include_partition);
}
}
}
+/* NEWDECL matched with OLDDECL, transfer defining module information
+ onto OLDDECL. We've already validated attachment matches. */
+
+void
+transfer_defining_module (tree olddecl, tree newdecl)
+{
+ if (!modules_p ())
+ return;
+
+ tree old_inner = STRIP_TEMPLATE (olddecl);
+ tree new_inner = STRIP_TEMPLATE (newdecl);
+
+ if (DECL_LANG_SPECIFIC (new_inner))
+ {
+ gcc_checking_assert (DECL_LANG_SPECIFIC (old_inner));
+ if (DECL_MODULE_PURVIEW_P (new_inner))
+ DECL_MODULE_PURVIEW_P (old_inner) = true;
+ if (!DECL_MODULE_IMPORT_P (new_inner))
+ DECL_MODULE_IMPORT_P (old_inner) = false;
+ }
+
+ if (tree *orig = imported_temploid_friends->get (newdecl))
+ {
+ tree &slot = imported_temploid_friends->get_or_insert (olddecl);
+ if (!slot)
+ slot = *orig;
+ else if (slot != *orig)
+ /* This can happen when multiple classes declare the same
+ friend function (e.g. g++.dg/modules/tpl-friend-4);
+ make sure we at least attach to the same module. */
+ gcc_checking_assert (get_originating_module (slot)
+ == get_originating_module (*orig));
+ }
+}
+
/* DECL is being freed, clear data we don't need anymore. */
void
--- /dev/null
+// PR c++/122551
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi M }
+
+export module M;
+export template <typename T> struct S {
+ operator int() const { return 123; }
+ template <typename U> friend void f(U);
+ template <typename U> friend void g(U) {}
+ friend void h(int);
+ friend void i(int) {}
+};
+template <typename U> void f(U) {}
+template <typename U> void g(U);
+void h(int) {}
+void i(int);
--- /dev/null
+// PR c++/122551
+// { dg-additional-options "-fmodules" }
+// { dg-module-cmi X }
+
+export module X;
+import M;
+
+export S<int> test() {
+ return {};
+}
--- /dev/null
+// PR c++/122551
+// { dg-additional-options "-fmodules" }
+
+import X;
+
+int main() {
+ f(test());
+ g(test());
+ h(test());
+ i(test());
+}