bool, tree, tree);
extern tree type_order_value (tree, tree);
+/* True iff DECL represents a declaration of a friend template
+ specialization, e.g. friend void f<>(). */
+
+inline bool
+decl_specialization_friend_p (tree decl)
+{
+ return (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_UNIQUE_FRIEND_P (decl)
+ && DECL_IMPLICIT_INSTANTIATION (decl)
+ && TREE_CODE (DECL_TI_TEMPLATE (decl)) != TEMPLATE_DECL);
+}
+
/* In module.cc */
class module_state; /* Forward declare. */
inline bool modules_p () { return flag_modules != 0; }
gcc_assert (identifier_p (fns) || OVL_P (fns));
DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args);
+ /* Remember the befriending class like push_template_decl does for
+ template friends. */
+ gcc_checking_assert (!DECL_CHAIN (decl));
+ DECL_CHAIN (decl) = current_scope ();
+
for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
if (TREE_PURPOSE (t)
&& TREE_CODE (TREE_PURPOSE (t)) == DEFERRED_PARSE)
if (decl == error_mark_node)
return error_mark_node;
- if (!class_template_depth && DECL_IMPLICIT_INSTANTIATION (decl)
- && TREE_CODE (DECL_TI_TEMPLATE (decl)) != TEMPLATE_DECL)
+ if (!class_template_depth
+ && decl_specialization_friend_p (decl))
/* "[if no non-template match is found,] each remaining function template
is replaced with the specialization chosen by deduction from the
friend declaration or discarded if deduction fails."
}
if (TREE_CODE (decl) == TEMPLATE_DECL
- && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
+ ? DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)
+ : decl_specialization_friend_p (decl))
{
mk = MK_local_friend;
break;
tree container = NULL_TREE;
if (TREE_CODE (decl) == TEMPLATE_DECL
- && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
+ ? DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)
+ : decl_specialization_friend_p (decl))
container = DECL_CHAIN (decl);
else
container = CP_DECL_CONTEXT (decl);
case MK_local_friend:
{
- /* Find by index on the class's DECL_LIST */
+ /* Find by index on the class's DECL_LIST. We set TREE_CHAIN to
+ point to the class in push_template_decl or grokfndecl. */
unsigned ix = 0;
for (tree decls = CLASSTYPE_DECL_LIST (TREE_CHAIN (decl));
decls; decls = TREE_CHAIN (decls))
{
tree new_friend;
- if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_TEMPLATE_INSTANTIATION (decl)
- && TREE_CODE (DECL_TI_TEMPLATE (decl)) != TEMPLATE_DECL)
+ if (decl_specialization_friend_p (decl))
/* This was a friend declared with an explicit template
argument list, e.g.:
--- /dev/null
+// { dg-additional-options "-fmodules" }
+
+export module M;
+
+export {
+template <class T>
+int fn() {
+ return T::mem;
+}
+
+template <class T>
+class A {
+ inline static int mem = 42;
+ friend int fn<A>();
+};
+
+template <class T>
+class B {
+ inline static int mem = 24;
+ friend int fn<B>();
+};
+}
--- /dev/null
+// { dg-additional-options "-fmodules" }
+
+import M;
+
+int main()
+{
+ fn<A<int>>();
+ fn<B<int>>();
+}