]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/5369 (template member friend declaration not honored)
authorKriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Sat, 22 Nov 2003 06:49:21 +0000 (06:49 +0000)
committerKriang Lerdsuwanakij <lerdsuwa@gcc.gnu.org>
Sat, 22 Nov 2003 06:49:21 +0000 (06:49 +0000)
PR c++/5369
* friend.c (is_friend): Handle member function of a class
template as template friend.
(do_friend): Likewise.
* decl2.c (check_classfn): Add template_header_p parameter.
* decl.c (start_decl): Adjust check_classfn call.
(grokfndecl): Likewise.
* pt.c (is_specialization_of_friend): New function.
(uses_template_parms_level): Likewise.
(push_template_decl_real): Use uses_template_parms_level.
(tsubst_friend_function): Adjust check_classfn call.
* cp-tree.h (check_classfn): Adjust declaration.
(uses_template_parms_level): Add declaration.
(is_specialization_of_friend): Likewise.

* g++.dg/template/memfriend1.C: New test.
* g++.dg/template/memfriend2.C: Likewise.
* g++.dg/template/memfriend3.C: Likewise.
* g++.dg/template/memfriend4.C: Likewise.
* g++.dg/template/memfriend5.C: Likewise.
* g++.dg/template/memfriend6.C: Likewise.
* g++.dg/template/memfriend7.C: Likewise.
* g++.dg/template/memfriend8.C: Likewise.
* g++.old-deja/g++.pt/friend44.C: Remove a bogus error.

From-SVN: r73833

16 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/friend.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/memfriend1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/memfriend8.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend44.C

index a27679f3b028b999fd360788cb99934e16d8db13..d047b0a644546d054e12f6ec2c66717c124fa9b3 100644 (file)
@@ -1,3 +1,20 @@
+2003-11-22  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
+       PR c++/5369
+       * friend.c (is_friend): Handle member function of a class
+       template as template friend.
+       (do_friend): Likewise.
+       * decl2.c (check_classfn): Add template_header_p parameter.
+       * decl.c (start_decl): Adjust check_classfn call.
+       (grokfndecl): Likewise.
+       * pt.c (is_specialization_of_friend): New function.
+       (uses_template_parms_level): Likewise.
+       (push_template_decl_real): Use uses_template_parms_level.
+       (tsubst_friend_function): Adjust check_classfn call.
+       * cp-tree.h (check_classfn): Adjust declaration.
+       (uses_template_parms_level): Add declaration.
+       (is_specialization_of_friend): Likewise.
+
 2003-11-21  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/12515
index 75245abfc7b497bebba1b89dd117e35fe59fc1a0..80414db73a676262936742b4e8764a1463c7ca1e 100644 (file)
@@ -3718,7 +3718,7 @@ extern void maybe_make_one_only   (tree);
 extern void grokclassfn        (tree, tree, enum overload_flags, tree);
 extern tree grok_array_decl (tree, tree);
 extern tree delete_sanity (tree, tree, int, int);
-extern tree check_classfn (tree, tree);
+extern tree check_classfn (tree, tree, bool);
 extern void check_member_template (tree);
 extern tree grokfield (tree, tree, tree, tree, tree);
 extern tree grokbitfield (tree, tree, tree);
@@ -3877,6 +3877,7 @@ extern void redeclare_class_template            (tree, tree);
 extern tree lookup_template_class              (tree, tree, tree, tree, int, tsubst_flags_t);
 extern tree lookup_template_function            (tree, tree);
 extern int uses_template_parms                 (tree);
+extern int uses_template_parms_level           (tree, int);
 extern tree instantiate_class_template         (tree);
 extern tree instantiate_template               (tree, tree, tsubst_flags_t);
 extern int fn_type_unification                  (tree, tree, tree, tree, tree, unification_kind_t, int);
@@ -3894,6 +3895,7 @@ extern int is_member_template                   (tree);
 extern int comp_template_parms                  (tree, tree);
 extern int template_class_depth                 (tree);
 extern int is_specialization_of                 (tree, tree);
+extern bool is_specialization_of_friend         (tree, tree);
 extern int comp_template_args                   (tree, tree);
 extern void maybe_process_partial_specialization (tree);
 extern void maybe_check_template_type           (tree);
index b24727493c6b95ce5faffe895786e60670315e1f..a1b320ff3523f447e2c68484beadde8c7fb1096e 100644 (file)
@@ -3756,7 +3756,9 @@ start_decl (tree declarator,
        }
       else
        {
-         tree field = check_classfn (context, decl);
+         tree field = check_classfn (context, decl,
+                                     processing_template_decl
+                                     > template_class_depth (context));
          if (field && duplicate_decls (decl, field))
            decl = field;
        }
@@ -5661,7 +5663,9 @@ grokfndecl (tree ctype,
     {
       tree old_decl;
 
-      old_decl = check_classfn (ctype, decl);
+      old_decl = check_classfn (ctype, decl,
+                               processing_template_decl
+                               > template_class_depth (ctype));
 
       if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
        /* Because grokfndecl is always supposed to return a
index 5f1076a9b15901524894ee4dab660d7c33a4e1fb..b7774c45df865b5e3c18f4585cd8d057173ea31f 100644 (file)
@@ -643,10 +643,12 @@ check_java_method (tree method)
 
 /* Sanity check: report error if this function FUNCTION is not
    really a member of the class (CTYPE) it is supposed to belong to.
-   CNAME is the same here as it is for grokclassfn above.  */
+   CNAME is the same here as it is for grokclassfn above.
+   TEMPLATE_HEADER_P is true when this declaration comes with a
+   template header.  */
 
 tree
-check_classfn (tree ctype, tree function)
+check_classfn (tree ctype, tree function, bool template_header_p)
 {
   int ix;
   int is_template;
@@ -669,7 +671,7 @@ check_classfn (tree ctype, tree function)
 
   /* OK, is this a definition of a member template?  */
   is_template = (TREE_CODE (function) == TEMPLATE_DECL
-                || (processing_template_decl - template_class_depth (ctype)));
+                || template_header_p);
 
   ix = lookup_fnfields_1 (complete_type (ctype),
                          DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
index e9547005bba48da6a2e4207ca9c6df74b595878b..8605321012c39da62780cb4f0b8157b62900fa81 100644 (file)
@@ -60,25 +60,15 @@ is_friend (tree type, tree supplicant)
              tree friends = FRIEND_DECLS (list);
              for (; friends ; friends = TREE_CHAIN (friends))
                {
-                 if (TREE_VALUE (friends) == NULL_TREE)
-                   continue;
+                 tree friend = TREE_VALUE (friends);
 
-                 if (supplicant == TREE_VALUE (friends))
-                   return 1;
+                 if (friend == NULL_TREE)
+                   continue;
 
-                 /* Temporarily, we are more lenient to deal with
-                    nested friend functions, for which there can be
-                    more than one FUNCTION_DECL, despite being the
-                    same function.  When that's fixed, this bit can
-                    go.  */
-                 if (DECL_FUNCTION_MEMBER_P (supplicant)
-                     && same_type_p (TREE_TYPE (supplicant),
-                                     TREE_TYPE (TREE_VALUE (friends))))
+                 if (supplicant == friend)
                    return 1;
 
-                 if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL
-                     && is_specialization_of (supplicant, 
-                                              TREE_VALUE (friends)))
+                 if (is_specialization_of_friend (supplicant, friend))
                    return 1;
                }
              break;
@@ -338,8 +328,6 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls,
           tree attrlist, enum overload_flags flags, tree quals,
           int funcdef_flag)
 {
-  int is_friend_template = 0;
-
   /* Every decl that gets here is a friend of something.  */
   DECL_FRIEND_P (decl) = 1;
 
@@ -353,39 +341,70 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls,
   if (TREE_CODE (decl) != FUNCTION_DECL)
     abort ();
 
-  is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
-
   if (ctype)
     {
+      /* CLASS_TEMPLATE_DEPTH counts the number of template headers for
+        the enclosing class.  FRIEND_DEPTH counts the number of template
+        headers used for this friend declaration.  TEMPLATE_MEMBER_P is
+        true if a template header in FRIEND_DEPTH is intended for
+        DECLARATOR.  For example, the code
+
+          template <class T> struct A {
+            template <class U> struct B {
+              template <class V> template <class W>
+                friend void C<V>::f(W);
+            };
+          };
+
+        will eventually give the following results
+
+        1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U').
+        2. FRIEND_DEPTH equals 2 (for `V' and `W').
+        3. TEMPLATE_MEMBER_P is true (for `W').  */
+
+      int class_template_depth = template_class_depth (current_class_type);
+      int friend_depth = processing_template_decl - class_template_depth;
+      /* We will figure this out later.  */
+      bool template_member_p = false;
+
       tree cname = TYPE_NAME (ctype);
       if (TREE_CODE (cname) == TYPE_DECL)
        cname = DECL_NAME (cname);
 
       /* A method friend.  */
-      if (flags == NO_SPECIAL && ctype && declarator == cname)
+      if (flags == NO_SPECIAL && declarator == cname)
        DECL_CONSTRUCTOR_P (decl) = 1;
 
       /* This will set up DECL_ARGUMENTS for us.  */
       grokclassfn (ctype, decl, flags, quals);
 
-      if (is_friend_template)
-       decl = DECL_TI_TEMPLATE (push_template_decl (decl));
-      else if (DECL_TEMPLATE_INFO (decl))
-       ;
-      else if (template_class_depth (current_class_type))
-       decl = push_template_decl_real (decl, /*is_friend=*/1);
-
-      /* We can't do lookup in a type that involves template
-        parameters.  Instead, we rely on tsubst_friend_function
-        to check the validity of the declaration later.  */
-      if (processing_template_decl)
-       add_friend (current_class_type, decl, /*complain=*/true);
+      if (friend_depth)
+       {
+         if (!uses_template_parms_level (ctype, class_template_depth
+                                                + friend_depth))
+           template_member_p = true;
+       }
+
       /* A nested class may declare a member of an enclosing class
         to be a friend, so we do lookup here even if CTYPE is in
         the process of being defined.  */
-      else if (COMPLETE_TYPE_P (ctype) || TYPE_BEING_DEFINED (ctype))
+      if (class_template_depth
+         || COMPLETE_TYPE_P (ctype)
+         || TYPE_BEING_DEFINED (ctype))
        {
-         decl = check_classfn (ctype, decl);
+         if (DECL_TEMPLATE_INFO (decl))
+           /* DECL is a template specialization.  No need to
+              build a new TEMPLATE_DECL.  */
+           ;
+         else if (class_template_depth)
+           /* We rely on tsubst_friend_function to check the
+              validity of the declaration later.  */
+           decl = push_template_decl_real (decl, /*is_friend=*/1);
+         else
+           decl = check_classfn (ctype, decl, template_member_p);
+
+         if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
+           decl = DECL_TI_TEMPLATE (decl);
 
          if (decl)
            add_friend (current_class_type, decl, /*complain=*/true);
@@ -398,6 +417,8 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls,
      @@ or possibly a friend from a base class ?!?  */
   else if (TREE_CODE (decl) == FUNCTION_DECL)
     {
+      int is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
+
       /* Friends must all go through the overload machinery,
         even though they may not technically be overloaded.
 
index 5b969388a64e04d969bbb5d5fe5225a1410eaf8b..9f73174f7c5c416377e9d3d9cb10a24eae2310a4 100644 (file)
@@ -876,6 +876,140 @@ is_specialization_of (tree decl, tree tmpl)
   return 0;
 }
 
+/* Returns nonzero iff DECL is a specialization of friend declaration
+   FRIEND according to [temp.friend].  */
+
+bool
+is_specialization_of_friend (tree decl, tree friend)
+{
+  bool need_template = true;
+  int template_depth;
+
+  my_friendly_assert (TREE_CODE (decl) == FUNCTION_DECL, 0);
+
+  /* For [temp.friend/6] when FRIEND is an ordinary member function
+     of a template class, we want to check if DECL is a specialization
+     if this.  */
+  if (TREE_CODE (friend) == FUNCTION_DECL
+      && DECL_TEMPLATE_INFO (friend)
+      && !DECL_USE_TEMPLATE (friend))
+    {
+      friend = DECL_TI_TEMPLATE (friend);
+      need_template = false;
+    }
+
+  /* There is nothing to do if this is not a template friend.  */
+  if (TREE_CODE (friend) != TEMPLATE_DECL)
+    return 0;
+
+  if (is_specialization_of (decl, friend))
+    return 1;
+
+  /* [temp.friend/6]
+     A member of a class template may be declared to be a friend of a
+     non-template class.  In this case, the corresponding member of
+     every specialization of the class template is a friend of the
+     class granting friendship.
+     
+     For example, given a template friend declaration
+
+       template <class T> friend void A<T>::f();
+
+     the member function below is considered a friend
+
+       template <> struct A<int> {
+        void f();
+       };
+
+     For this type of template friend, TEMPLATE_DEPTH below will be
+     non-zero.  To determine if DECL is a friend of FRIEND, we first
+     check if the enclosing class is a specialization of another.  */
+
+  template_depth = template_class_depth (DECL_CONTEXT (friend));
+  if (template_depth
+      && DECL_CLASS_SCOPE_P (decl)
+      && is_specialization_of (TYPE_NAME (DECL_CONTEXT (decl)), 
+                              CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (friend))))
+    {
+      /* Next, we check the members themselves.  In order to handle
+        a few tricky cases like
+
+          template <class T> friend void A<T>::g(T t);
+          template <class T> template <T t> friend void A<T>::h();
+
+        we need to figure out what ARGS is (corresponding to `T' in above
+        examples) from DECL for later processing.  */
+
+      tree context = DECL_CONTEXT (decl);
+      tree args = NULL_TREE;
+      int current_depth = 0;
+      while (current_depth < template_depth)
+       {
+         if (CLASSTYPE_TEMPLATE_INFO (context))
+           {
+             if (current_depth == 0)
+               args = TYPE_TI_ARGS (context);
+             else
+               args = add_to_template_args (TYPE_TI_ARGS (context), args);
+             current_depth++;
+           }
+         context = TYPE_CONTEXT (context);
+       }
+
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       {
+         bool is_template;
+         tree friend_type;
+         tree decl_type;
+         tree friend_args_type;
+         tree decl_args_type;
+
+         /* Make sure that both DECL and FRIEND are templates or
+            non-templates.  */
+         is_template = DECL_TEMPLATE_INFO (decl)
+                       && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl));
+         if (need_template ^ is_template)
+           return 0;
+         else if (is_template)
+           {
+             /* If both are templates, check template paramter list.  */
+             tree friend_parms
+               = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend),
+                                        args, tf_none);
+             if (!comp_template_parms
+                    (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl)),
+                     friend_parms))
+               return 0;
+
+             decl_type = TREE_TYPE (DECL_TI_TEMPLATE (decl));
+           }
+         else
+           decl_type = TREE_TYPE (decl);
+
+         friend_type = tsubst_function_type (TREE_TYPE (friend), args,
+                                             tf_none, NULL_TREE);
+         if (friend_type == error_mark_node)
+           return 0;
+
+         /* Check if return types match.  */
+         if (!same_type_p (TREE_TYPE (decl_type), TREE_TYPE (friend_type)))
+           return 0;
+
+         /* Check if function parameter types match, ignoring the
+            `this' parameter.  */
+         friend_args_type = TYPE_ARG_TYPES (friend_type);
+         decl_args_type = TYPE_ARG_TYPES (decl_type);
+         if (DECL_NONSTATIC_MEMBER_FUNCTION_P (friend))
+           friend_args_type = TREE_CHAIN (friend_args_type);
+         if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
+           decl_args_type = TREE_CHAIN (decl_args_type);
+         if (compparms (decl_args_type, friend_args_type))
+           return 1;
+       }
+    }
+  return 0;
+}
+
 /* Register the specialization SPEC as a specialization of TMPL with
    the indicated ARGS.  Returns SPEC, or an equivalent prior
    declaration, if available.  */
@@ -2861,10 +2995,8 @@ push_template_decl_real (tree decl, int is_friend)
          /* It is a conversion operator. See if the type converted to
             depends on innermost template operands.  */
          
-         if (for_each_template_parm (TREE_TYPE (TREE_TYPE (tmpl)),
-                                     template_parm_this_level_p,
-                                     &depth,
-                                     NULL))
+         if (uses_template_parms_level (TREE_TYPE (TREE_TYPE (tmpl)),
+                                        depth))
            DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;
        }
     }
@@ -4602,12 +4734,22 @@ for_each_template_parm (tree t, tree_fn_t fn, void* data, htab_t visited)
   return result;
 }
 
+/* Returns true if T depends on any template parameter.  */
+
 int
 uses_template_parms (tree t)
 {
   return for_each_template_parm (t, 0, 0, NULL);
 }
 
+/* Returns true if T depends on any template parameter with level LEVEL.  */
+
+int
+uses_template_parms_level (tree t, int level)
+{
+  return for_each_template_parm (t, template_parm_this_level_p, &level, NULL);
+}
+
 static int tinst_depth;
 extern int max_tinst_depth;
 #ifdef GATHER_STATISTICS
@@ -4917,7 +5059,7 @@ tsubst_friend_function (tree decl, tree args)
       /* Check to see that the declaration is really present, and,
         possibly obtain an improved declaration.  */
       tree fn = check_classfn (DECL_CONTEXT (new_friend),
-                              new_friend);
+                              new_friend, false);
       
       if (fn)
        new_friend = fn;
index 73ffd70498c1bbf5f11988cb492787327ebbe042..c339a0da467ab7947665112d96d35689a15702da 100644 (file)
@@ -1,3 +1,16 @@
+2003-11-22  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>
+
+       PR c++/5369
+       * g++.dg/template/memfriend1.C: New test.
+       * g++.dg/template/memfriend2.C: Likewise.
+       * g++.dg/template/memfriend3.C: Likewise.
+       * g++.dg/template/memfriend4.C: Likewise.
+       * g++.dg/template/memfriend5.C: Likewise.
+       * g++.dg/template/memfriend6.C: Likewise.
+       * g++.dg/template/memfriend7.C: Likewise.
+       * g++.dg/template/memfriend8.C: Likewise.
+       * g++.old-deja/g++.pt/friend44.C: Remove a bogus error.
+
 2003-11-21  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/12515
diff --git a/gcc/testsuite/g++.dg/template/memfriend1.C b/gcc/testsuite/g++.dg/template/memfriend1.C
new file mode 100644 (file)
index 0000000..f454127
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Member function of class template as friend
+
+template<class T> struct A
+{
+  void f();
+};
+
+class C {
+  int i;
+  template<class T> friend void A<T>::f();
+};
+
+template<class T> struct A<T*>
+{
+  void f();
+};
+
+template<> struct A<char>
+{
+  void f();
+};
+
+template<class T> void A<T>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template<class T> void A<T*>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+void A<char>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+int main()
+{
+  A<int> a1;
+  a1.f();
+  A<int *> a2;
+  a2.f();
+  A<char> a3;
+  a3.f();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend2.C b/gcc/testsuite/g++.dg/template/memfriend2.C
new file mode 100644 (file)
index 0000000..364ad7d
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Member function template of class template as friend
+
+template <class T> struct A
+{
+  template <class U> void f();
+};
+
+class C {
+  int i;
+  template <class T> template <class U> friend void A<T>::f();
+};
+
+template <class T> struct A<T*>
+{
+  template <class U> void f();
+};
+
+template <> struct A<char>
+{
+  template <class U> void f();
+};
+
+template <class T> template <class U> void A<T>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <class T> template <class U> void A<T*>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <class U> void A<char>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <> void A<char>::f<int>()
+{
+  C c;
+  c.i = 0;
+}
+
+int main()
+{
+  A<int> a1;
+  a1.f<char>();
+  A<int *> a2;
+  a2.f<char>();
+  A<char> a3;
+  a3.f<char>();
+  a3.f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend3.C b/gcc/testsuite/g++.dg/template/memfriend3.C
new file mode 100644 (file)
index 0000000..3ea8c84
--- /dev/null
@@ -0,0 +1,55 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Member function of class template as friend
+
+template<class T> struct A
+{
+  void f(T);
+};
+
+class C {
+  int i;
+  template<class T> friend void A<T>::f(T);
+};
+
+template<class T> struct A<T*>
+{
+  void f(T*);
+};
+
+template<> struct A<char>
+{
+  void f(char);
+};
+
+template<class T> void A<T>::f(T)
+{
+  C c;
+  c.i = 0;
+}
+
+template<class T> void A<T*>::f(T*)
+{
+  C c;
+  c.i = 0;
+}
+
+void A<char>::f(char)
+{
+  C c;
+  c.i = 0;
+}
+
+int main()
+{
+  A<int> a1;
+  a1.f(0);
+  A<int *> a2;
+  int *p = 0;
+  a2.f(p);
+  A<char> a3;
+  a3.f('a');
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend4.C b/gcc/testsuite/g++.dg/template/memfriend4.C
new file mode 100644 (file)
index 0000000..5c006fe
--- /dev/null
@@ -0,0 +1,63 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Member function of class template as friend
+
+template<class T> struct A
+{
+  template <T t> void f();
+};
+
+class C {
+  int i;
+  template<class T> template <T t> friend void A<T>::f();
+};
+
+template<class T> struct A<T*>
+{
+  template <T* t> void f();
+};
+
+template<> struct A<char>
+{
+  template <char t> void f();
+};
+
+template<class T> template <T t> void A<T>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template<class T> template <T* t> void A<T*>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <char t> void A<char>::f()
+{
+  C c;
+  c.i = 0;
+}
+
+template <> void A<char>::f<'b'>()
+{
+  C c;
+  c.i = 0;
+}
+
+int d2 = 0;
+
+int main()
+{
+  A<int> a1;
+  a1.f<0>();
+  A<int *> a2;
+  a2.f<&d2>();
+  A<char> a3;
+  a3.f<'a'>();
+  a3.f<'b'>();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend5.C b/gcc/testsuite/g++.dg/template/memfriend5.C
new file mode 100644 (file)
index 0000000..38c2fb9
--- /dev/null
@@ -0,0 +1,31 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Member template function of member class template as friend
+
+template <class T> struct A {
+  template <class U> struct B {
+    template <class V> void f(V);
+  };
+};
+
+class X {
+  int i;
+  template <class T> template <class U> template <class V>
+    friend void A<T>::B<U>::f(V);
+};
+
+template <class T> template <class U> template <class V>
+  void A<T>::B<U>::f(V)
+{
+  X x;
+  x.i = 0;
+}
+
+int main()
+{
+  A<char>::B<char> a1;
+  a1.f(0);
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend6.C b/gcc/testsuite/g++.dg/template/memfriend6.C
new file mode 100644 (file)
index 0000000..21d7996
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Member function of class template as friend
+// Erroneous case: mismatch during declaration
+
+template <class T> struct A {
+  template <class U> void f(U);                // { dg-error "candidate" }
+  void g();                            // { dg-error "candidate" }
+  void h();                            // { dg-error "candidate" }
+  void i(int);                         // { dg-error "candidate" }
+};
+
+class C {
+  int ii;
+  template <class U> friend void A<U>::f(U);   // { dg-error "not match" }
+  template <class U> template <class V>
+    friend void A<U>::g();                     // { dg-error "not match" }
+  template <class U> friend int A<U>::h();     // { dg-error "not match" }
+  template <class U> friend void A<U>::i(char);        // { dg-error "not match" }
+};
diff --git a/gcc/testsuite/g++.dg/template/memfriend7.C b/gcc/testsuite/g++.dg/template/memfriend7.C
new file mode 100644 (file)
index 0000000..aed0295
--- /dev/null
@@ -0,0 +1,133 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation
+// Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+// Member function of class template as friend
+// Erroneous case: mismatch during specialization
+
+template <class T> struct A {
+  template <class U> void f(U);
+  void g();
+  void h();
+  void i(int);
+  template <T t> void j();
+};
+
+class C {
+  int ii;                              // { dg-error "private" }
+  template <class U> template <class V>
+    friend void A<U>::f(V);
+  template <class U> friend void A<U>::g();
+  template <class U> friend void A<U>::h();
+  template <class U> friend void A<U>::i(int);
+  template <class U> template <U t>
+    friend void A<U>::j();
+};
+
+template <class T> struct A<T*> {
+  void f(int);
+  template <class U> void g();
+  int h();
+  void i(char);
+  template <int> void j();
+};
+
+template <class T> void A<T*>::f(int)
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <class T> template <class U> void A<T*>::g()
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <class T> int A<T*>::h()
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <class T> void A<T*>::i(char)
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <class T> template <int> void A<T*>::j()
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <> struct A<char> {
+  void f(int);
+  template <class U> void g();
+  int h();
+  void i(char);
+  template <int> void j();
+};
+
+void A<char>::f(int)
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <class U> void A<char>::g()
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <> void A<char>::g<int>()
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+int A<char>::h()
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+void A<char>::i(char)
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <int> void A<char>::j()
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+template <> void A<char>::j<0>()
+{
+  C c;
+  c.ii = 0;                            // { dg-error "context" }
+}
+
+int main()
+{
+  A<int *> a1;
+  a1.f(0);                             // { dg-error "instantiated" }
+  a1.g<char>();                                // { dg-error "instantiated" }
+  a1.g<int>();                         // { dg-error "instantiated" }
+  a1.h();                              // { dg-error "instantiated" }
+  a1.i('a');                           // { dg-error "instantiated" }
+  a1.j<1>();                           // { dg-error "instantiated" }
+  A<char> a2;
+  a2.f(0);
+  a2.g<char>();                                // { dg-error "instantiated" }
+  a2.g<int>();
+  a2.h();
+  a2.i('a');
+  a2.j<1>();                           // { dg-error "instantiated" }
+  a2.j<0>();
+}
diff --git a/gcc/testsuite/g++.dg/template/memfriend8.C b/gcc/testsuite/g++.dg/template/memfriend8.C
new file mode 100644 (file)
index 0000000..886096b
--- /dev/null
@@ -0,0 +1,25 @@
+// { dg-do compile }
+
+// Origin: Martin Sebor <sebor@roguewave.com>
+
+// PR c++/5369: Member function of class template as friend
+
+template <class T>
+struct S
+{
+  int foo () {
+    return S<int>::bar ();
+  }
+
+private:
+
+  template <class U>
+  friend int S<U>::foo ();
+
+  static int bar () { return 0; }
+};
+
+int main ()
+{
+  S<char>().foo ();
+}
index c82c7e7824c7d9abfeb41c935131e482b811e5e2..1f79172906145ec0bf0c85b175cba57b8f80a9f7 100644 (file)
@@ -23,7 +23,7 @@ public:
 template <class T> int A<T>::f (T)
 {
   B b;
-  return b.a; // { dg-bogus "" "" { xfail *-*-* } }
+  return b.a;
 }
 
 template <class T> int A<T>::AI::f (T)