[C++ PATCH] Fix PR641, 11876 (Excessive friend declaration warning)

Kriang Lerdsuwanakij lerdsuwa@users.sourceforge.net
Fri Aug 22 13:45:00 GMT 2003


Hi

Currently, friend declaration in code like

  template <class T> class X {
    friend class X<int>;
    ...
  };

triggers a warning about X<int> is a friend of itself during
template instantiation of X<int>.  I feel that cases like this
do not quite justify the warning.  I propose the following patch
that only issue such diagnostics only during parsing.  So
during template instantiation, we silently ignore the friend
declaration.  With the above approach, we still provide a warning
for case like

  class X {
    friend class X;
  };

Tested on i686-pc-linux-gnu.  OK for mainline?


2003-08-22  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/641, c++/11876
	* friend.c (add_friend): Add complain parameter.
	(make_friend_class): Likewise.
	(do_friend): Adjust add_friend call.
	* decl.c (grokdeclarator): Adjust make_friend_class call.
	* parser.c (cp_parser_member_declaration): Likewise.
	(cp_parser_template_declaration_after_exp): Likewise.
	* pt.c (instantiate_class_template): Adjust make_friend_class
	and add_friend call.
	* cp-tree.h (make_friend_class): Adjust declaration.
	(add_friend): Likewise.

2003-08-22  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/641, c++/11876
	* g++.dg/template/friend22.C: New test.
	* g++.dg/template/friend23.C: Likewise.


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	Thu Aug 14 19:58:57 2003
--- gcc-main-new/gcc/cp/cp-tree.h	Mon Aug 18 22:29:24 2003
*************** extern tree cplus_expand_constant       
*** 3838,3845 ****
  
  /* friend.c */
  extern int is_friend				(tree, tree);
! extern void make_friend_class			(tree, tree);
! extern void add_friend                          (tree, tree);
  extern tree do_friend				(tree, tree, tree, tree, tree, enum overload_flags, tree, int);
  
  /* in init.c */
--- 3838,3845 ----
  
  /* friend.c */
  extern int is_friend				(tree, tree);
! extern void make_friend_class			(tree, tree, bool);
! extern void add_friend                          (tree, tree, bool);
  extern tree do_friend				(tree, tree, tree, tree, tree, enum overload_flags, tree, int);
  
  /* in init.c */
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c	Thu Aug 14 19:58:57 2003
--- gcc-main-new/gcc/cp/decl.c	Mon Aug 18 22:30:35 2003
*************** grokdeclarator (tree declarator,
*** 11266,11272 ****
  	    {
  	      /* A friendly class?  */
  	      if (current_class_type)
! 		make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type));
  	      else
  		error ("trying to make class `%T' a friend of global scope",
  		          type);
--- 11266,11273 ----
  	    {
  	      /* A friendly class?  */
  	      if (current_class_type)
! 		make_friend_class (current_class_type, TYPE_MAIN_VARIANT (type),
! 				   /*complain=*/true);
  	      else
  		error ("trying to make class `%T' a friend of global scope",
  		          type);
diff -cprN gcc-main-save/gcc/cp/friend.c gcc-main-new/gcc/cp/friend.c
*** gcc-main-save/gcc/cp/friend.c	Thu Jul 17 22:46:21 2003
--- gcc-main-new/gcc/cp/friend.c	Mon Aug 18 22:29:23 2003
*************** is_friend (tree type, tree supplicant)
*** 127,136 ****
  }
  
  /* Add a new friend to the friends of the aggregate type TYPE.
!    DECL is the FUNCTION_DECL of the friend being added.  */
  
  void
! add_friend (tree type, tree decl)
  {
    tree typedecl;
    tree list;
--- 127,140 ----
  }
  
  /* Add a new friend to the friends of the aggregate type TYPE.
!    DECL is the FUNCTION_DECL of the friend being added.
! 
!    If COMPLAIN is true, warning about duplicate friend is issued.
!    We want to have this diagnostics during parsing but not
!    when a template is being instantiated.  */
  
  void
! add_friend (tree type, tree decl, bool complain)
  {
    tree typedecl;
    tree list;
*************** add_friend (tree type, tree decl)
*** 153,162 ****
  	    {
  	      if (decl == TREE_VALUE (friends))
  		{
! 		  warning ("`%D' is already a friend of class `%T'",
! 			      decl, type);
! 		  cp_warning_at ("previous friend declaration of `%D'",
! 				 TREE_VALUE (friends));
  		  return;
  		}
  	    }
--- 157,169 ----
  	    {
  	      if (decl == TREE_VALUE (friends))
  		{
! 		  if (complain)
! 		    {
! 		      warning ("`%D' is already a friend of class `%T'",
! 			       decl, type);
! 		      cp_warning_at ("previous friend declaration of `%D'",
! 				     TREE_VALUE (friends));
! 		    }
  		  return;
  		}
  	    }
*************** add_friend (tree type, tree decl)
*** 192,201 ****
     classes that are not defined.  If a type has not yet been defined,
     then the DECL_WAITING_FRIENDS contains a list of types
     waiting to make it their friend.  Note that these two can both
!    be in use at the same time!  */
  
  void
! make_friend_class (tree type, tree friend_type)
  {
    tree classes;
    int is_template_friend;
--- 199,212 ----
     classes that are not defined.  If a type has not yet been defined,
     then the DECL_WAITING_FRIENDS contains a list of types
     waiting to make it their friend.  Note that these two can both
!    be in use at the same time!
! 
!    If COMPLAIN is true, warning about duplicate friend is issued.
!    We want to have this diagnostics during parsing but not
!    when a template is being instantiated.  */
  
  void
! make_friend_class (tree type, tree friend_type, bool complain)
  {
    tree classes;
    int is_template_friend;
*************** make_friend_class (tree type, tree frien
*** 227,234 ****
      }
    else if (same_type_p (type, friend_type))
      {
!       pedwarn ("class `%T' is implicitly friends with itself",
! 	          type);
        return;
      }
    else
--- 238,246 ----
      }
    else if (same_type_p (type, friend_type))
      {
!       if (complain)
! 	pedwarn ("class `%T' is implicitly friends with itself",
! 		 type);
        return;
      }
    else
*************** make_friend_class (tree type, tree frien
*** 275,282 ****
  	{
  	  if (friend_type == probe)
  	    {
! 	      warning ("`%D' is already a friend of `%T'",
! 		       probe, type);
  	      break;
  	    }
  	}
--- 287,295 ----
  	{
  	  if (friend_type == probe)
  	    {
! 	      if (complain)
! 		warning ("`%D' is already a friend of `%T'",
! 			 probe, type);
  	      break;
  	    }
  	}
*************** make_friend_class (tree type, tree frien
*** 284,291 ****
  	{
  	  if (same_type_p (probe, friend_type))
  	    {
! 	      warning ("`%T' is already a friend of `%T'",
! 		       probe, type);
  	      break;
  	    }
  	}
--- 297,305 ----
  	{
  	  if (same_type_p (probe, friend_type))
  	    {
! 	      if (complain)
! 		warning ("`%T' is already a friend of `%T'",
! 			 probe, type);
  	      break;
  	    }
  	}
*************** do_friend (tree ctype, tree declarator, 
*** 369,375 ****
  	 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);
        /* 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.  */
--- 383,389 ----
  	 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.  */
*************** do_friend (tree ctype, tree declarator, 
*** 378,384 ****
  	  decl = check_classfn (ctype, decl);
  
  	  if (decl)
! 	    add_friend (current_class_type, decl);
  	}
        else
  	error ("member `%D' declared as friend before type `%T' defined",
--- 392,398 ----
  	  decl = check_classfn (ctype, decl);
  
  	  if (decl)
! 	    add_friend (current_class_type, decl, /*complain=*/true);
  	}
        else
  	error ("member `%D' declared as friend before type `%T' defined",
*************** do_friend (tree ctype, tree declarator, 
*** 446,452 ****
  	}
  
        add_friend (current_class_type, 
! 		  is_friend_template ? DECL_TI_TEMPLATE (decl) : decl);
        DECL_FRIEND_P (decl) = 1;
      }
  
--- 460,467 ----
  	}
  
        add_friend (current_class_type, 
! 		  is_friend_template ? DECL_TI_TEMPLATE (decl) : decl,
! 		  /*complain=*/true);
        DECL_FRIEND_P (decl) = 1;
      }
  
diff -cprN gcc-main-save/gcc/cp/parser.c gcc-main-new/gcc/cp/parser.c
*** gcc-main-save/gcc/cp/parser.c	Thu Aug 14 19:58:57 2003
--- gcc-main-new/gcc/cp/parser.c	Mon Aug 18 22:30:35 2003
*************** cp_parser_member_declaration (cp_parser*
*** 11771,11777 ****
  		 error ("friend declaration does not name a class or "
  			"function");
  	       else
! 		 make_friend_class (current_class_type, type);
  	    }
  	  /* If there is no TYPE, an error message will already have
  	     been issued.  */
--- 11771,11778 ----
  		 error ("friend declaration does not name a class or "
  			"function");
  	       else
! 		 make_friend_class (current_class_type, type,
! 				    /*complain=*/true);
  	    }
  	  /* If there is no TYPE, an error message will already have
  	     been issued.  */
*************** cp_parser_template_declaration_after_exp
*** 13567,13573 ****
        if (member_p && !friend_p && decl)
  	decl = finish_member_template_decl (decl);
        else if (friend_p && decl && TREE_CODE (decl) == TYPE_DECL)
! 	make_friend_class (current_class_type, TREE_TYPE (decl));
      }
    /* We are done with the current parameter list.  */
    --parser->num_template_parameter_lists;
--- 13568,13575 ----
        if (member_p && !friend_p && decl)
  	decl = finish_member_template_decl (decl);
        else if (friend_p && decl && TREE_CODE (decl) == TYPE_DECL)
! 	make_friend_class (current_class_type, TREE_TYPE (decl),
! 			   /*complain=*/true);
      }
    /* We are done with the current parameter list.  */
    --parser->num_template_parameter_lists;
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Thu Aug 14 19:58:57 2003
--- gcc-main-new/gcc/cp/pt.c	Mon Aug 18 22:30:36 2003
*************** instantiate_class_template (tree type)
*** 5360,5373 ****
  		++processing_template_decl;
  
  	      if (new_friend_type != error_mark_node)
! 	        make_friend_class (type, new_friend_type);
  
  	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
  		--processing_template_decl;
  	    }
  	  else
  	    /* Build new DECL_FRIENDLIST.  */
! 	    add_friend (type, tsubst_friend_function (t, args));
  	}
      }
  
--- 5360,5375 ----
  		++processing_template_decl;
  
  	      if (new_friend_type != error_mark_node)
! 	        make_friend_class (type, new_friend_type,
! 				   /*complain=*/false);
  
  	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
  		--processing_template_decl;
  	    }
  	  else
  	    /* Build new DECL_FRIENDLIST.  */
! 	    add_friend (type, tsubst_friend_function (t, args),
! 			/*complain=*/false);
  	}
      }
  
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/friend22.C gcc-main-new/gcc/testsuite/g++.dg/template/friend22.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/friend22.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/friend22.C	Mon Aug 18 22:38:03 2003
***************
*** 0 ****
--- 1,15 ----
+ // { dg-do compile }
+ 
+ // Origin: Benoit Hudson <bh@techhouse.brown.edu>
+ 
+ // PR c++/641: Duplicate friend diagnostics
+ 
+ template <class T> class iterator { };
+ template <class T> class item {
+     friend class iterator<T>;
+     friend class iterator<const T>;
+ };
+ 
+ class A { };
+ 
+ item<const A> i;
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/friend23.C gcc-main-new/gcc/testsuite/g++.dg/template/friend23.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/friend23.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/friend23.C	Mon Aug 18 22:38:09 2003
***************
*** 0 ****
--- 1,38 ----
+ // { dg-do compile }
+ 
+ // Origin: Alexandre Tolmos <ktulu@free.fr>
+ 
+ // PR c++/11876: Friend of its own class diagnostics
+ 
+ template <typename T>
+ class A
+ {
+ 	friend class A<int>;
+ 	friend class A<float>;
+ protected:
+ 	T _data;
+ 	inline A() : _data(0) {}
+ 	template <typename U>
+ 	inline A(const A<U>& r) : _data(r._data) {}
+ };
+ 
+ class B : public A<int>
+ {
+ public:
+ 	inline B() {}
+ 	inline B(const B& r) : A<int>(r) {}
+ };
+ 
+ class C : public A<float>
+ {
+ public:
+ 	inline C() {}
+ 	inline C(const B& r) : A<float>(r) {}
+ };
+ 
+ int main(int, char*[])
+ {
+ 	B b1, b2(b1);
+ 	C c(b1);
+ 	return 0;
+ }



More information about the Gcc-patches mailing list