This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] Member function of class template as friend (revised)


Hi

This is a revised version of patch

  http://gcc.gnu.org/ml/gcc-patches/2003-08/msg00644.html

to add support for template friend declarations described in 14.5.3/6.
Only the case when a member function is handled for now, i.e.,

  template <class T> struct A {
    void f();
  };
  class C {
    template <class T> friend void A<T>::f();
  };

The main processing is moved from 'is_friend' in previous version
to a new function 'is_specialization_of_friend' in pt.c.  Another major
change in 'do_friend' is adjusted to allow arbitrary number of nested
class like

    template <class T> template <class U> friend void A<T>::B<U>::f();

which was forbidden in original patch.

Patch tested on i686-pc-linux-gnu with no regressions.  OK for
the mainline?

--Kriang


2003-09-12  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-09-12  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.


diff -cprN gcc-main-save/gcc/cp/cp-tree.h gcc-main-new/gcc/cp/cp-tree.h
*** gcc-main-save/gcc/cp/cp-tree.h	Tue Sep  2 21:48:37 2003
--- gcc-main-new/gcc/cp/cp-tree.h	Thu Sep 11 19:02:02 2003
*************** extern void maybe_make_one_only	(tree);
*** 3757,3763 ****
  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 void check_member_template (tree);
  extern tree grokfield (tree, tree, tree, tree, tree);
  extern tree grokbitfield (tree, tree, tree);
--- 3757,3763 ----
  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, bool);
  extern void check_member_template (tree);
  extern tree grokfield (tree, tree, tree, tree, tree);
  extern tree grokbitfield (tree, tree, tree);
*************** extern void redeclare_class_template    
*** 3931,3936 ****
--- 3931,3937 ----
  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);
*************** extern int is_member_template           
*** 3948,3953 ****
--- 3949,3955 ----
  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);
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c	Tue Sep  2 21:48:37 2003
--- gcc-main-new/gcc/cp/decl.c	Tue Sep  9 19:47:01 2003
*************** start_decl (tree declarator, 
*** 7061,7067 ****
  	}
        else
  	{
! 	  tree field = check_classfn (context, decl);
  	  if (field && duplicate_decls (decl, field))
  	    decl = field;
  	}
--- 7061,7069 ----
  	}
        else
  	{
! 	  tree field = check_classfn (context, decl,
! 				      processing_template_decl
! 				      > template_class_depth (context));
  	  if (field && duplicate_decls (decl, field))
  	    decl = field;
  	}
*************** grokfndecl (tree ctype, 
*** 9023,9029 ****
      {
        tree old_decl;
  
!       old_decl = check_classfn (ctype, decl);
  
        if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
  	/* Because grokfndecl is always supposed to return a
--- 9025,9033 ----
      {
        tree old_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
diff -cprN gcc-main-save/gcc/cp/decl2.c gcc-main-new/gcc/cp/decl2.c
*** gcc-main-save/gcc/cp/decl2.c	Sun Aug 31 22:33:59 2003
--- gcc-main-new/gcc/cp/decl2.c	Tue Sep  9 19:47:01 2003
*************** check_java_method (tree method)
*** 652,661 ****
  
  /* 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.  */
  
  tree
! check_classfn (tree ctype, tree function)
  {
    int ix;
    int is_template;
--- 652,663 ----
  
  /* 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.
!    TEMPLATE_HEADER_P is true when this declaration comes with a
!    template header.  */
  
  tree
! check_classfn (tree ctype, tree function, bool template_header_p)
  {
    int ix;
    int is_template;
*************** check_classfn (tree ctype, tree function
*** 678,684 ****
  
    /* OK, is this a definition of a member template?  */
    is_template = (TREE_CODE (function) == TEMPLATE_DECL
! 		 || (processing_template_decl - template_class_depth (ctype)));
  
    ix = lookup_fnfields_1 (complete_type (ctype),
  			  DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
--- 680,686 ----
  
    /* OK, is this a definition of a member template?  */
    is_template = (TREE_CODE (function) == TEMPLATE_DECL
! 		 || template_header_p);
  
    ix = lookup_fnfields_1 (complete_type (ctype),
  			  DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
diff -cprN gcc-main-save/gcc/cp/friend.c gcc-main-new/gcc/cp/friend.c
*** gcc-main-save/gcc/cp/friend.c	Sat Aug 23 19:49:44 2003
--- gcc-main-new/gcc/cp/friend.c	Thu Sep 11 21:28:58 2003
*************** is_friend (tree type, tree supplicant)
*** 60,84 ****
  	      tree friends = FRIEND_DECLS (list);
  	      for (; friends ; friends = TREE_CHAIN (friends))
  		{
! 		  if (TREE_VALUE (friends) == NULL_TREE)
! 		    continue;
  
! 		  if (supplicant == TREE_VALUE (friends))
! 		    return 1;
  
! 		  /* 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))))
  		    return 1;
  
! 		  if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL
! 		      && is_specialization_of (supplicant, 
! 					       TREE_VALUE (friends)))
  		    return 1;
  		}
  	      break;
--- 60,74 ----
  	      tree friends = FRIEND_DECLS (list);
  	      for (; friends ; friends = TREE_CHAIN (friends))
  		{
! 		  tree friend = TREE_VALUE (friends);
  
! 		  if (friend == NULL_TREE)
! 		    continue;
  
! 		  if (supplicant == friend)
  		    return 1;
  
! 		  if (is_specialization_of_friend (supplicant, friend))
  		    return 1;
  		}
  	      break;
*************** do_friend (tree ctype, tree declarator, 
*** 342,349 ****
  	   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;
  
--- 332,337 ----
*************** do_friend (tree ctype, tree declarator, 
*** 357,395 ****
    if (TREE_CODE (decl) != FUNCTION_DECL)
      abort ();
  
-   is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
- 
    if (ctype)
      {
        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)
  	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);
        /* 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))
  	{
! 	  decl = check_classfn (ctype, decl);
  
  	  if (decl)
  	    add_friend (current_class_type, decl, /*complain=*/true);
--- 345,414 ----
    if (TREE_CODE (decl) != FUNCTION_DECL)
      abort ();
  
    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 && declarator == cname)
  	DECL_CONSTRUCTOR_P (decl) = 1;
  
        /* This will set up DECL_ARGUMENTS for us.  */
        grokclassfn (ctype, decl, flags, quals);
  
!       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.  */
!       if (class_template_depth
! 	  || COMPLETE_TYPE_P (ctype)
! 	  || TYPE_BEING_DEFINED (ctype))
  	{
! 	  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);
*************** do_friend (tree ctype, tree declarator, 
*** 402,407 ****
--- 421,428 ----
       @@ 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.
  
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Tue Sep  2 21:48:37 2003
--- gcc-main-new/gcc/cp/pt.c	Fri Sep 12 21:08:30 2003
*************** is_specialization_of (tree decl, tree tm
*** 873,878 ****
--- 873,1012 ----
    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.  */
*************** push_template_decl_real (tree decl, int 
*** 2855,2864 ****
  	  /* 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))
  	    DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;
  	}
      }
--- 2989,2996 ----
  	  /* It is a conversion operator. See if the type converted to
  	     depends on innermost template operands.  */
  	  
! 	  if (uses_template_parms_level (TREE_TYPE (TREE_TYPE (tmpl)),
! 					 depth))
  	    DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;
  	}
      }
*************** for_each_template_parm (tree t, tree_fn_
*** 4595,4606 ****
--- 4727,4748 ----
    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
*************** tsubst_friend_function (tree decl, tree 
*** 4910,4916 ****
        /* 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);
        
        if (fn)
  	new_friend = fn;
--- 5052,5058 ----
        /* 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, false);
        
        if (fn)
  	new_friend = fn;
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend1.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend1.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend1.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend1.C	Thu Sep 11 19:20:27 2003
***************
*** 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 -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend2.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend2.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend2.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend2.C	Thu Sep 11 19:20:48 2003
***************
*** 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 -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend3.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend3.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend3.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend3.C	Thu Sep 11 19:27:03 2003
***************
*** 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 -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend4.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend4.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend4.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend4.C	Thu Sep 11 19:39:16 2003
***************
*** 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 -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend5.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend5.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend5.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend5.C	Thu Sep 11 19:44:33 2003
***************
*** 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 -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend6.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend6.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend6.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend6.C	Thu Sep 11 21:19:20 2003
***************
*** 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 -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend7.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend7.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend7.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend7.C	Thu Sep 11 21:34:31 2003
***************
*** 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 -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend8.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend8.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend8.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend8.C	Tue Sep  9 19:47:01 2003
***************
*** 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 ();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/friend44.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/friend44.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/friend44.C	Thu May  1 18:35:29 2003
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/friend44.C	Tue Sep  9 19:47:01 2003
*************** public:
*** 23,29 ****
  template <class T> int A<T>::f (T)
  {
    B b;
!   return b.a; // { dg-bogus "" "" { xfail *-*-* } }
  }
  
  template <class T> int A<T>::AI::f (T)
--- 23,29 ----
  template <class T> int A<T>::f (T)
  {
    B b;
!   return b.a;
  }
  
  template <class T> int A<T>::AI::f (T)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]