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]

PATCH RFA: Fix for g++/7874 (friend injection)


This patch is for PR g++/7874, which is about injecting friend
functions into enclosing namespaces.  This patch is rather more
complicated than the earlier version, but I believe that it handles
all the issues that were raised.  The biggest change is
friend_of_associated_class_p, which is used to only add appropriate
friend functions when doing argument dependent lookup.

This patch includes the new option -ffriend-injection.  I've reduced
the code impact from six lines to four (i.e., one line outside of
c.opt, in pushdecl).  As discussed, we can remove this option if the
C++ maintainers consider it to be unnecessary.  I won't repeat my
earlier arguments, but I will add the argument that the C++ ARM states
unambiguously that friend functions are injected into the top level,
so in that regard ISO C++ is a change from earlier behaviour, and code
which relies on friend function injection was not always invalid.

I updated the testsuite by changing a few tests to add parameters to
permit argument dependent lookup to work, and by using the new
-ffriend-injection option for two tests.

I believe that this patch will permit the code which handles friend
class (not function) injection to use DECL_HIDDEN_FRIEND_P instead of
relying on the somewhat fragile DECL_FRIEND_P.  Once that change is
made, it may be possible to eliminate DECL_FRIEND_P, although I have
not yet fully investigated DECL_FRIEND_CONTEXT which currently uses
it.  However, any such change is a cleanup rather than a regression
fix, and as such should probably be left until after 4.1 branches.

If this patch is accepted, I propose to close PR 7874 and not backport
the patch to 3.4 or 4.0, because I think it is unwise to change the
default behaviour of the compiler in a dot release.

I have tested this patch on i686-pc-linux-gnu with a bootstrap and
with testsuite runs of g++, objc, and libstdc++-v3.

OK for mainline?

:ADDPATCH c++:

Ian


./ChangeLog:
	PR g++/7874
	* c.opt (ffriend-injection): New C++ option.
	* doc/invoke.texi (Option Summary): Mention -ffriend-injection.
	(C++ Dialect Options): Document -ffriend-injection.

cp/ChangeLog:
	PR g++/7874
	* cp-tree.h (struct lang_decl_flags): Add hidden_friend_p
	bitfield.  Make dummy bitfield one bit smaller.
	(DECL_HIDDEN_FRIEND_P): Define.
	(pushdecl_maybe_friend): Declare.
	(pushdecl_top_level_maybe_friend): Declare.
	* decl.c (duplicate_decls): Add newdecl_is_friend parameter.
	Change prototype and all callers.  Add assertion that a
	DECL_ARTIFICIAL FUNCTION_DECL is not DECL_HIDDEN_FRIEND_P.  Set
	DECL_ANTICIPATED and DECL_HIDDEN_FRIEND_P in duplicated decl if
	appropriate.
	* name-lookup.c (supplement_binding): Don't ignore a
	DECL_HIDDEN_FRIEND_P.
	(pushdecl_maybe_friend): Break out contents of pushdecl.  Add
	is_friend parameter.  Set DECL_ANTICIPATED and
	DECL_HIDDEN_FRIEND_P for a friend function.
	(pushdecl): Just call pushdecl_maybe_friend.
	(pushdecl_with_scope): Add is_friend parameter.  Change prototype
	and all callers.
	(pushdecl_namespace_level): Likewise.
	(push_overloaded_decl): Likewise.  Check DECL_HIDDEN_FRIEND_P as
	well as DECL_ANTICIPATED when checking for a builtin.
	(do_nonmember_using_decl): Check DECL_HIDDEN_FRIEND_P as well as
	DECL_ANTICIPATED when checking for a builtin.
	(do_nonmember_using_decl): Likewise.
	(pushdecl_top_level_1): Add is_friend parameter.  Change all
	callers.
	(pushdecl_top_level_maybe_friend): New function.
	(remove_hidden_names): New function.
	(struct arg_lookup): Add args field.
	(friend_of_associated_class_p): New static function.
	(arg_assoc_namespace): Ignore hidden functions which are not
	friends of an associated class of some argument.
	(lookup_arg_dependent): Remove hidden functions from list passed
	in.  Initialize k.args.
	* name-lookup.h (remove_hidden_names): Declare.
	* friend.c (do_friend): Call pushdecl_maybe_friend instead of
	pushdecl.
	* call.c (add_function_candidate): Change DECL_ANTICIPATED test to
	an assertion, with a check for DECL_HIDDEN_FRIEND_P.
	(build_new_function_call): Add koenig_p parameter.  Change
	prototype and callers.
	* pt.c (register_specialization): Add is_friend parameter.  Change
	all callers.
	(push_template_decl_real): Change is_friend parameter to bool.
	Change prototype and all callers.
	(tsubst_friend_class): Call pushdecl_top_level_maybe_friend
	instead of pushdecl_top_level.

testsuite/ChangeLog:
	PR g++/7874
	* g++.dg/lookup/friend7.C: New test.
	* g++.dg/lookup/friend8.C: New test.
	* g++.dg/parse/defarg4.C: Add a parameter to the friend function,
	so that it will be found via argument dependent lookup.
	* g++.old-deja/g++.brendan/crash56.C: Don't expect errors for
	friend functions which will no longer be found.
	* g++.old-deja/g++.jason/friend.C: Add a parameter to the friend
	function g, so that it will be found via argument dependent
	lookup.
	* g++.old-deja/g++.jason/scoping15.C: Use -ffriend-injection.
	* g++.old-deja/g++.mike/net43.C: Likewise.


Index: c.opt
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c.opt,v
retrieving revision 1.50
diff -p -u -r1.50 c.opt
--- c.opt	19 Jul 2005 20:19:12 -0000	1.50
+++ c.opt	10 Sep 2005 03:32:18 -0000
@@ -554,6 +554,10 @@ fimplicit-templates
 C++ ObjC++
 Emit implicit instantiations of templates
 
+ffriend-injection
+C++ Var(flag_friend_injection)
+Inject friend functions into enclosing namespace
+
 flabels-ok
 C++ ObjC++
 
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.551
diff -p -u -r1.551 call.c
--- cp/call.c	6 Sep 2005 14:55:03 -0000	1.551
+++ cp/call.c	10 Sep 2005 03:32:27 -0000
@@ -1309,10 +1309,10 @@ add_function_candidate (struct z_candida
   tree orig_arglist;
   int viable = 1;
 
-  /* Built-in functions that haven't been declared don't really
-     exist.  */
-  if (DECL_ANTICIPATED (fn))
-    return NULL;
+  /* At this point we should not see any functions which haven't been
+     explicitly declared, except for friend functions which will have
+     been found using argument dependent lookup.  */
+  gcc_assert (!DECL_ANTICIPATED (fn) || DECL_HIDDEN_FRIEND_P (fn));
 
   /* The `this', `in_chrg' and VTT arguments to constructors are not
      considered in overload resolution.  */
@@ -2758,7 +2758,7 @@ perform_overload_resolution (tree fn,
    or a static member function) with the ARGS.  */
 
 tree
-build_new_function_call (tree fn, tree args)
+build_new_function_call (tree fn, tree args, bool koenig_p)
 {
   struct z_candidate *candidates, *cand;
   bool any_viable_p;
@@ -2769,6 +2769,22 @@ build_new_function_call (tree fn, tree a
   if (args == error_mark_node)
     return error_mark_node;
 
+  /* If this function was found without using argument dependent
+     lookup, then we want to ignore any undeclared friend
+     functions.  */
+  if (!koenig_p)
+    {
+      tree orig_fn = fn;
+
+      fn = remove_hidden_names (fn);
+      if (!fn)
+	{
+	  error ("no matching function for call to %<%D(%A)%>",
+		 DECL_NAME (OVL_CURRENT (orig_fn)), args);
+	  return error_mark_node;
+	}
+    }
+
   /* Get the high-water mark for the CONVERSION_OBSTACK.  */
   p = conversion_obstack_alloc (0);
 
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.731
diff -p -u -r1.731 class.c
--- cp/class.c	15 Aug 2005 20:38:13 -0000	1.731
+++ cp/class.c	10 Sep 2005 03:32:28 -0000
@@ -5645,7 +5645,8 @@ resolve_address_of_overloaded_function (
 	       one, or vice versa.  */
 	    continue;
 
-	  /* Ignore anticipated decls of undeclared builtins.  */
+	  /* Ignore functions which haven't been explicitly
+	     declared.  */
 	  if (DECL_ANTICIPATED (fn))
 	    continue;
 
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1162
diff -p -u -r1.1162 cp-tree.h
--- cp/cp-tree.h	6 Sep 2005 14:55:03 -0000	1.1162
+++ cp/cp-tree.h	10 Sep 2005 03:32:29 -0000
@@ -1512,7 +1512,8 @@ struct lang_decl_flags GTY(())
   unsigned thunk_p : 1;
   unsigned this_thunk_p : 1;
   unsigned repo_available_p : 1;
-  unsigned dummy : 3;
+  unsigned hidden_friend_p : 1;
+  unsigned dummy : 2;
 
   union lang_decl_u {
     /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
@@ -1814,9 +1815,8 @@ struct lang_decl GTY(())
 #define DECL_INITIALIZED_IN_CLASS_P(DECL) \
  (DECL_LANG_SPECIFIC (DECL)->decl_flags.initialized_in_class)
 
-/* Nonzero for FUNCTION_DECL means that this decl is just a
-   friend declaration, and should not be added to the list of
-   member functions for this class.  */
+/* Nonzero for DECL means that this decl is just a friend declaration,
+   and should not be added to the list of members for this class.  */
 #define DECL_FRIEND_P(NODE) (DECL_LANG_SPECIFIC (NODE)->decl_flags.friend_attr)
 
 /* A TREE_LIST of the types which have befriended this FUNCTION_DECL.  */
@@ -2321,11 +2321,19 @@ extern void decl_shadowed_for_var_insert
 #define DECL_LOCAL_FUNCTION_P(NODE) \
   DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE))
 
-/* Nonzero if NODE is a FUNCTION_DECL for a built-in function, and we have
-   not yet seen a prototype for that function.  */
+/* Nonzero if NODE is a DECL which we know about but which has not
+   been explicitly declared, such as a built-in function or a friend
+   declared inside a class.  In the latter case DECL_HIDDEN_FRIEND_P
+   will be set.  */
 #define DECL_ANTICIPATED(NODE) \
   (DECL_LANG_SPECIFIC (DECL_COMMON_CHECK (NODE))->decl_flags.anticipated_p)
 
+/* Nonzero if NODE is a FUNCTION_DECL which was declared as a friend
+   within a class but has not been declared in the surrounding scope.
+   The function is invisible except via argument dependent lookup.  */
+#define DECL_HIDDEN_FRIEND_P(NODE) \
+  (DECL_LANG_SPECIFIC (DECL_COMMON_CHECK (NODE))->decl_flags.hidden_friend_p)
+
 /* Record whether a typedef for type `int' was actually `signed int'.  */
 #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
 
@@ -3644,7 +3652,7 @@ extern bool null_ptr_cst_p			(tree);
 extern bool sufficient_parms_p			(tree);
 extern tree type_decays_to			(tree);
 extern tree build_user_type_conversion		(tree, tree, int);
-extern tree build_new_function_call		(tree, tree);
+extern tree build_new_function_call		(tree, tree, bool);
 extern tree build_operator_new_call		(tree, tree, tree *, tree *);
 extern tree build_new_method_call		(tree, tree, tree, tree, int);
 extern tree build_special_member_call		(tree, tree, tree, tree, int);
@@ -3743,6 +3751,7 @@ extern void adjust_clone_args			(tree);
 extern tree poplevel				(int, int, int);
 extern void insert_block			(tree);
 extern tree pushdecl				(tree);
+extern tree pushdecl_maybe_friend		(tree, bool);
 extern void cxx_init_decl_processing		(void);
 enum cp_tree_node_structure_enum cp_tree_node_structure
 						(union lang_tree_node *);
@@ -3756,8 +3765,9 @@ extern void pop_switch				(void);
 extern tree pushtag				(tree, tree, tag_scope);
 extern tree make_anon_name			(void);
 extern int decls_match				(tree, tree);
-extern tree duplicate_decls			(tree, tree);
+extern tree duplicate_decls			(tree, tree, bool);
 extern tree pushdecl_top_level			(tree);
+extern tree pushdecl_top_level_maybe_friend	(tree, bool);
 extern tree pushdecl_top_level_and_finish	(tree, tree);
 extern tree push_using_decl			(tree, tree);
 extern tree declare_local_label			(tree);
@@ -3983,7 +3993,7 @@ extern tree end_template_parm_list		(tre
 extern void end_template_decl			(void);
 extern tree current_template_args		(void);
 extern tree push_template_decl			(tree);
-extern tree push_template_decl_real		(tree, int);
+extern tree push_template_decl_real		(tree, bool);
 extern void redeclare_class_template		(tree, tree);
 extern tree lookup_template_class		(tree, tree, tree, tree,
 						 int, tsubst_flags_t);
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1423
diff -p -u -r1.1423 decl.c
--- cp/decl.c	6 Sep 2005 10:30:09 -0000	1.1423
+++ cp/decl.c	10 Sep 2005 03:32:30 -0000
@@ -1008,13 +1008,15 @@ warn_extern_redeclared_static (tree newd
    error_mark_node is returned.  Otherwise, OLDDECL is returned.
 
    If NEWDECL is not a redeclaration of OLDDECL, NULL_TREE is
-   returned.  */
+   returned.
+
+   NEWDECL_IS_FRIEND is true if NEWDECL was declared as a friend.  */
 
 tree
-duplicate_decls (tree newdecl, tree olddecl)
+duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 {
   unsigned olddecl_uid = DECL_UID (olddecl);
-  int olddecl_friend = 0, types_match = 0;
+  int olddecl_friend = 0, types_match = 0, hidden_friend = 0;
   int new_defines_function = 0;
 
   if (newdecl == olddecl)
@@ -1068,9 +1070,11 @@ duplicate_decls (tree newdecl, tree oldd
   if (TREE_CODE (olddecl) == FUNCTION_DECL
       && DECL_ARTIFICIAL (olddecl))
     {
+      gcc_assert (!DECL_HIDDEN_FRIEND_P (olddecl));
       if (TREE_CODE (newdecl) != FUNCTION_DECL)
 	{
-	  /* Avoid warnings redeclaring anticipated built-ins.  */
+	  /* Avoid warnings redeclaring built-ins which have not been
+	     explicitly declared.  */
 	  if (DECL_ANTICIPATED (olddecl))
 	    return NULL_TREE;
 
@@ -1101,7 +1105,8 @@ duplicate_decls (tree newdecl, tree oldd
 	}
       else if (!types_match)
 	{
-	  /* Avoid warnings redeclaring anticipated built-ins.  */
+	  /* Avoid warnings redeclaring built-ins which have not been
+	     explicitly declared.  */
 	  if (DECL_ANTICIPATED (olddecl))
 	    {
 	      /* Deal with fileptr_type_node.  FILE type is not known
@@ -1130,7 +1135,8 @@ duplicate_decls (tree newdecl, tree oldd
 			  = TYPE_ARG_TYPES (TREE_TYPE (newdecl));
 			types_match = decls_match (newdecl, olddecl);
 			if (types_match)
-			  return duplicate_decls (newdecl, olddecl);
+			  return duplicate_decls (newdecl, olddecl,
+						  newdecl_is_friend);
 			TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs;
 		      }
 		  }
@@ -1162,8 +1168,9 @@ duplicate_decls (tree newdecl, tree oldd
 	  /* Replace the old RTL to avoid problems with inlining.  */
 	  COPY_DECL_RTL (newdecl, olddecl);
 	}
-      /* Even if the types match, prefer the new declarations type
-	 for anticipated built-ins, for exception lists, etc...  */
+      /* Even if the types match, prefer the new declarations type for
+	 built-ins which have not been explicitly declared, for
+	 exception lists, etc...  */
       else if (DECL_ANTICIPATED (olddecl))
 	{
 	  tree type = TREE_TYPE (newdecl);
@@ -1459,7 +1466,7 @@ duplicate_decls (tree newdecl, tree oldd
 	  /* Don't warn about extern decl followed by definition.  */
 	  && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))
 	  /* Don't warn about friends, let add_friend take care of it.  */
-	  && ! (DECL_FRIEND_P (newdecl) || DECL_FRIEND_P (olddecl)))
+	  && ! (newdecl_is_friend || DECL_FRIEND_P (olddecl)))
 	{
 	  warning (0, "redundant redeclaration of %qD in same scope", newdecl);
 	  warning (0, "previous declaration of %q+D", olddecl);
@@ -1684,6 +1691,9 @@ duplicate_decls (tree newdecl, tree oldd
       DECL_INITIALIZED_IN_CLASS_P (newdecl)
 	|= DECL_INITIALIZED_IN_CLASS_P (olddecl);
       olddecl_friend = DECL_FRIEND_P (olddecl);
+      hidden_friend = (DECL_ANTICIPATED (olddecl)
+		       && DECL_HIDDEN_FRIEND_P (olddecl)
+		       && newdecl_is_friend);
 
       /* Only functions have DECL_BEFRIENDING_CLASSES.  */
       if (TREE_CODE (newdecl) == FUNCTION_DECL
@@ -1897,6 +1907,11 @@ duplicate_decls (tree newdecl, tree oldd
   DECL_UID (olddecl) = olddecl_uid;
   if (olddecl_friend)
     DECL_FRIEND_P (olddecl) = 1;
+  if (hidden_friend)
+    {
+      DECL_ANTICIPATED (olddecl) = 1;
+      DECL_HIDDEN_FRIEND_P (olddecl) = 1;
+    }
 
   /* NEWDECL contains the merged attribute lists.
      Update OLDDECL to be the same.  */
@@ -3141,7 +3156,7 @@ cp_make_fname_decl (tree id, int type_de
       struct cp_binding_level *b = current_binding_level;
       while (b->level_chain->kind != sk_function_parms)
 	b = b->level_chain;
-      pushdecl_with_scope (decl, b);
+      pushdecl_with_scope (decl, b, /*is_friend=*/false);
       cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
     }
   else
@@ -3184,8 +3199,9 @@ builtin_function_1 (const char* name,
   if (libname)
     SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname));
 
-  /* Warn if a function in the namespace for users
-     is used without an occasion to consider it declared.  */
+  /* A function in the user's namespace should have an explicit
+     declaration before it is used.  Mark the built-in function as
+     anticipated but not actually declared.  */
   if (name[0] != '_' || name[1] != '_')
     DECL_ANTICIPATED (decl) = 1;
 
@@ -3719,7 +3735,7 @@ start_decl (const cp_declarator *declara
 	      if (DECL_INITIAL (decl) 
 		  && DECL_INITIALIZED_IN_CLASS_P (field))
 		error ("duplicate initialization of %qD", decl);
-	      if (duplicate_decls (decl, field))
+	      if (duplicate_decls (decl, field, /*newdecl_is_friend=*/false))
 		decl = field;
 	    }
 	}
@@ -3730,7 +3746,8 @@ start_decl (const cp_declarator *declara
 				       > template_class_depth (context))
 				      ? current_template_parms
 				      : NULL_TREE);
-	  if (field && duplicate_decls (decl, field))
+	  if (field && duplicate_decls (decl, field,
+					/*newdecl_is_friend=*/false))
 	    decl = field;
 	}
 
@@ -5870,7 +5887,7 @@ grokfndecl (tree ctype,
 	  /* Attempt to merge the declarations.  This can fail, in
 	     the case of some invalid specialization declarations.  */
 	  pushed_scope = push_scope (ctype);
-	  ok = duplicate_decls (decl, old_decl);
+	  ok = duplicate_decls (decl, old_decl, friendp);
 	  if (pushed_scope)
 	    pop_scope (pushed_scope);
 	  if (!ok)
Index: cp/friend.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/friend.c,v
retrieving revision 1.109
diff -p -u -r1.109 friend.c
--- cp/friend.c	2 Jul 2005 10:54:49 -0000	1.109
+++ cp/friend.c	10 Sep 2005 03:32:31 -0000
@@ -480,7 +480,7 @@ do_friend (tree ctype, tree declarator, 
 	  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);
+	    decl = push_template_decl_real (decl, /*is_friend=*/true);
 	  else
 	    decl = check_classfn (ctype, decl,
 				  template_member_p
@@ -527,13 +527,13 @@ do_friend (tree ctype, tree declarator, 
 	       general, such a declaration depends on template
 	       parameters.  Instead, we call pushdecl when the class
 	       is instantiated.  */
-	    decl = push_template_decl_real (decl, /*is_friend=*/1);
+	    decl = push_template_decl_real (decl, /*is_friend=*/true);
 	  else if (current_function_decl)
 	    /* This must be a local class, so pushdecl will be ok, and
 	       insert an unqualified friend into the local scope
 	       (rather than the containing namespace scope, which the
 	       next choice will do).  */
-	    decl = pushdecl (decl);
+	    decl = pushdecl_maybe_friend (decl, /*is_friend=*/true);
 	  else
 	    {
 	      /* We can't use pushdecl, as we might be in a template
@@ -543,7 +543,7 @@ do_friend (tree ctype, tree declarator, 
 	      tree ns = decl_namespace_context (decl);
 
 	      push_nested_namespace (ns);
-	      decl = pushdecl_namespace_level (decl);
+	      decl = pushdecl_namespace_level (decl, /*is_friend=*/true);
 	      pop_nested_namespace (ns);
 	    }
 
Index: cp/name-lookup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.c,v
retrieving revision 1.139
diff -p -u -r1.139 name-lookup.c
--- cp/name-lookup.c	30 Aug 2005 16:22:00 -0000	1.139
+++ cp/name-lookup.c	10 Sep 2005 03:32:32 -0000
@@ -44,7 +44,7 @@ static cxx_scope *innermost_nonclass_lev
 static tree select_decl (const struct scope_binding *, int);
 static cxx_binding *binding_for_name (cxx_scope *, tree);
 static tree lookup_name_innermost_nonclass_level (tree);
-static tree push_overloaded_decl (tree, int);
+static tree push_overloaded_decl (tree, int, bool);
 static bool lookup_using_namespace (tree, struct scope_binding *, tree,
 				    tree, int);
 static bool qualified_lookup_using_namespace (tree, tree,
@@ -437,10 +437,11 @@ supplement_binding (cxx_binding *binding
 	      error recovery purpose, pretend this was the intended
 	      declaration for that name.  */
 	   || bval == error_mark_node
-	   /* If BVAL is a built-in that has not yet been declared,
+	   /* If BVAL is anticipated but has not yet been declared,
 	      pretend it is not there at all.  */
 	   || (TREE_CODE (bval) == FUNCTION_DECL
-	       && DECL_ANTICIPATED (bval)))
+	       && DECL_ANTICIPATED (bval)
+	       && !DECL_HIDDEN_FRIEND_P (bval)))
     binding->value = decl;
   else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval))
     {
@@ -487,7 +488,7 @@ supplement_binding (cxx_binding *binding
 	   && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval)
 	   && !DECL_CLASS_SCOPE_P (decl))
     {
-      duplicate_decls (decl, binding->value);
+      duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false);
       ok = false;
     }
   else if (TREE_CODE (decl) == NAMESPACE_DECL
@@ -551,14 +552,15 @@ add_decl_to_level (tree decl, cxx_scope 
 
 /* Record a decl-node X as belonging to the current lexical scope.
    Check for errors (such as an incompatible declaration for the same
-   name already seen in the same scope).
+   name already seen in the same scope).  IS_FRIEND is true if X is
+   declared as a friend.
 
    Returns either X or an old decl for the same name.
    If an old decl is returned, it may have been smashed
    to agree with what X says.  */
 
 tree
-pushdecl (tree x)
+pushdecl_maybe_friend (tree x, bool is_friend)
 {
   tree t;
   tree name;
@@ -679,7 +681,7 @@ pushdecl (tree x)
 	      gcc_assert (DECL_CONTEXT (t));
 
 	      /* Check for duplicate params.  */
-	      if (duplicate_decls (x, t))
+	      if (duplicate_decls (x, t, is_friend))
 		POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
 	    }
 	  else if ((DECL_EXTERN_C_FUNCTION_P (x)
@@ -697,7 +699,7 @@ pushdecl (tree x)
 	    }
 	  else
 	    {
-	      tree olddecl = duplicate_decls (x, t);
+	      tree olddecl = duplicate_decls (x, t, is_friend);
 
 	      /* If the redeclaration failed, we can stop at this
 		 point.  */
@@ -742,7 +744,7 @@ pushdecl (tree x)
 
       if (DECL_NON_THUNK_FUNCTION_P (x) && ! DECL_FUNCTION_MEMBER_P (x))
 	{
-	  t = push_overloaded_decl (x, PUSH_LOCAL);
+	  t = push_overloaded_decl (x, PUSH_LOCAL, is_friend);
 	  if (t != x)
 	    POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
 	  if (!namespace_bindings_p ())
@@ -753,7 +755,7 @@ pushdecl (tree x)
 	}
       else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
 	{
-	  t = push_overloaded_decl (x, PUSH_GLOBAL);
+	  t = push_overloaded_decl (x, PUSH_GLOBAL, is_friend);
 	  if (t == x)
 	    add_decl_to_level (x, NAMESPACE_LEVEL (CP_DECL_CONTEXT (t)));
 	  POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
@@ -815,6 +817,16 @@ pushdecl (tree x)
 	    }
 	}
 
+      if (TREE_CODE (x) == FUNCTION_DECL
+	  && is_friend
+	  && !flag_friend_injection)
+	{
+	  /* This is a new declaration of a friend function, so hide
+	     it from ordinary function lookup.  */
+	  DECL_ANTICIPATED (x) = 1;
+	  DECL_HIDDEN_FRIEND_P (x) = 1;
+	}
+
       /* This name is new in its binding level.
 	 Install the new declaration and return it.  */
       if (namespace_bindings_p ())
@@ -998,6 +1010,14 @@ pushdecl (tree x)
   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);
 }
 
+/* Record a decl-node X as belonging to the current lexical scope.  */
+
+tree
+pushdecl (tree x)
+{
+  return pushdecl_maybe_friend (x, false);
+}
+
 /* Enter DECL into the symbol table, if that's appropriate.  Returns
    DECL, or a modified version thereof.  */
 
@@ -1796,7 +1816,7 @@ push_using_decl (tree scope, tree name)
    caller to set DECL_CONTEXT properly.  */
 
 tree
-pushdecl_with_scope (tree x, cxx_scope *level)
+pushdecl_with_scope (tree x, cxx_scope *level, bool is_friend)
 {
   struct cp_binding_level *b;
   tree function_decl = current_function_decl;
@@ -1814,7 +1834,7 @@ pushdecl_with_scope (tree x, cxx_scope *
     {
       b = current_binding_level;
       current_binding_level = level;
-      x = pushdecl (x);
+      x = pushdecl_maybe_friend (x, is_friend);
       current_binding_level = b;
     }
   current_function_decl = function_decl;
@@ -1836,12 +1856,14 @@ pushdecl_with_scope (tree x, cxx_scope *
      PUSH_USING: DECL is being pushed as the result of a using
 		 declaration.
 
+   IS_FRIEND is true if this is a friend declaration.
+
    The value returned may be a previous declaration if we guessed wrong
    about what language DECL should belong to (C or C++).  Otherwise,
    it's always DECL (and never something that's not a _DECL).  */
 
 static tree
-push_overloaded_decl (tree decl, int flags)
+push_overloaded_decl (tree decl, int flags, bool is_friend)
 {
   tree name = DECL_NAME (decl);
   tree old;
@@ -1881,7 +1903,7 @@ push_overloaded_decl (tree decl, int fla
 		error ("%q#D conflicts with previous using declaration %q#D",
 		       decl, fn);
 
-	      if (duplicate_decls (decl, fn) == fn)
+	      if (duplicate_decls (decl, fn, is_friend) == fn)
 		POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, fn);
 	    }
 
@@ -1889,7 +1911,8 @@ push_overloaded_decl (tree decl, int fla
 	     may fail to merge the decls if the new decl is e.g. a
 	     template function.  */
 	  if (TREE_CODE (old) == FUNCTION_DECL
-	      && DECL_ANTICIPATED (old))
+	      && DECL_ANTICIPATED (old)
+	      && !DECL_HIDDEN_FRIEND_P (old))
 	    old = NULL;
 	}
       else if (old == error_mark_node)
@@ -2038,7 +2061,8 @@ do_nonmember_using_decl (tree scope, tre
      is a built-in, then we can just pretend it isn't there.  */
   if (oldval
       && TREE_CODE (oldval) == FUNCTION_DECL
-      && DECL_ANTICIPATED (oldval))
+      && DECL_ANTICIPATED (oldval)
+      && !DECL_HIDDEN_FRIEND_P (oldval))
     oldval = NULL_TREE;
 
   /* Check for using functions.  */
@@ -2076,7 +2100,8 @@ do_nonmember_using_decl (tree scope, tre
 	      else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (new_fn)),
 				  TYPE_ARG_TYPES (TREE_TYPE (old_fn))))
 		{
-		  gcc_assert (!DECL_ANTICIPATED (old_fn));
+		  gcc_assert (!DECL_ANTICIPATED (old_fn)
+			      || DECL_HIDDEN_FRIEND_P (old_fn));
 
 		  /* There was already a non-using declaration in
 		     this scope with the same parameter types. If both
@@ -2169,7 +2194,8 @@ do_local_using_decl (tree decl, tree sco
 	  for (fn = newval; fn && OVL_CURRENT (fn) != term;
 	       fn = OVL_NEXT (fn))
 	    push_overloaded_decl (OVL_CURRENT (fn),
-				  PUSH_LOCAL | PUSH_USING);
+				  PUSH_LOCAL | PUSH_USING,
+				  false);
 	}
       else
 	push_local_binding (name, newval, PUSH_USING);
@@ -3059,13 +3085,13 @@ do_namespace_alias (tree alias, tree nam
    if appropriate.  */
 
 tree
-pushdecl_namespace_level (tree x)
+pushdecl_namespace_level (tree x, bool is_friend)
 {
   struct cp_binding_level *b = current_binding_level;
   tree t;
 
   timevar_push (TV_NAME_LOOKUP);
-  t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace));
+  t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace), is_friend);
 
   /* Now, the type_shadowed stack may screw us.  Munge it so it does
      what we want.  */
@@ -3248,11 +3274,11 @@ parse_using_directive (tree namespace, t
    *INIT, if INIT is non-NULL.  */
 
 static tree
-pushdecl_top_level_1 (tree x, tree *init)
+pushdecl_top_level_1 (tree x, tree *init, bool is_friend)
 {
   timevar_push (TV_NAME_LOOKUP);
   push_to_top_level ();
-  x = pushdecl_namespace_level (x);
+  x = pushdecl_namespace_level (x, is_friend);
   if (init)
     cp_finish_decl (x, *init, NULL_TREE, 0);
   pop_from_top_level ();
@@ -3264,7 +3290,15 @@ pushdecl_top_level_1 (tree x, tree *init
 tree
 pushdecl_top_level (tree x)
 {
-  return pushdecl_top_level_1 (x, NULL);
+  return pushdecl_top_level_1 (x, NULL, false);
+}
+
+/* Like pushdecl_top_level, but adding the IS_FRIEND parameter.  */
+
+tree
+pushdecl_top_level_maybe_friend (tree x, bool is_friend)
+{
+  return pushdecl_top_level_1 (x, NULL, is_friend);
 }
 
 /* Like pushdecl, only it places X in the global scope if
@@ -3274,7 +3308,7 @@ pushdecl_top_level (tree x)
 tree
 pushdecl_top_level_and_finish (tree x, tree init)
 {
-  return pushdecl_top_level_1 (x, &init);
+  return pushdecl_top_level_1 (x, &init, false);
 }
 
 /* Combines two sets of overloaded functions into an OVERLOAD chain, removing
@@ -3441,7 +3475,7 @@ qualify_lookup (tree val, int flags)
 }
 
 /* Given a lookup that returned VAL, decide if we want to ignore it or
-   not based on DECL_ANTICIPATED_P.  */
+   not based on DECL_ANTICIPATED.  */
 
 bool
 hidden_name_p (tree val)
@@ -3453,6 +3487,38 @@ hidden_name_p (tree val)
   return false;
 }
 
+/* Remove any hidden friend functions from a possibly overloaded set
+   of functions.  */
+
+tree
+remove_hidden_names (tree fns)
+{
+  if (!fns)
+    return fns;
+
+  if (TREE_CODE (fns) == FUNCTION_DECL && hidden_name_p (fns))
+    fns = NULL_TREE;
+  else if (TREE_CODE (fns) == OVERLOAD)
+    {
+      tree o;
+
+      for (o = fns; o; o = OVL_NEXT (o))
+	if (hidden_name_p (OVL_CURRENT (o)))
+	  break;
+      if (o)
+	{
+	  tree n = NULL_TREE;
+
+	  for (o = fns; o; o = OVL_NEXT (o))
+	    if (!hidden_name_p (OVL_CURRENT (o)))
+	      n = build_overload (OVL_CURRENT (o), n);
+	  fns = n;
+	}
+    }
+
+  return fns;
+}
+
 /* Look up NAME in the NAMESPACE.  */
 
 tree
@@ -4113,6 +4179,7 @@ lookup_type_current_level (tree name)
 struct arg_lookup
 {
   tree name;
+  tree args;
   tree namespaces;
   tree classes;
   tree functions;
@@ -4191,6 +4258,53 @@ is_associated_namespace (tree current, t
     }
 }
 
+/* Return whether FN is a friend of an associated class of ARG.  */
+
+static bool
+friend_of_associated_class_p (tree arg, tree fn)
+{
+  tree type;
+
+  if (TYPE_P (arg))
+    type = arg;
+  else if (type_unknown_p (arg))
+    return false;
+  else
+    type = TREE_TYPE (arg);
+
+  /* If TYPE is a class, the class itself and all base classes are
+     associated classes.  */
+  if (CLASS_TYPE_P (type))
+    {
+      if (is_friend (type, fn))
+	return true;
+
+      if (TYPE_BINFO (type))
+	{
+	  tree binfo, base_binfo;
+	  int i;
+
+	  for (binfo = TYPE_BINFO (type), i = 0;
+	       BINFO_BASE_ITERATE (binfo, i, base_binfo);
+	       i++)
+	    if (is_friend (BINFO_TYPE (base_binfo), fn))
+	      return true;
+	}
+    }
+
+  /* If TYPE is a class member, the class of which it is a member is
+     an associated class.  */
+  if ((CLASS_TYPE_P (type)
+       || TREE_CODE (type) == UNION_TYPE
+       || TREE_CODE (type) == ENUMERAL_TYPE)
+      && TYPE_CONTEXT (type)
+      && CLASS_TYPE_P (TYPE_CONTEXT (type))
+      && is_friend (TYPE_CONTEXT (type), fn))
+    return true;
+
+  return false;
+}
+
 /* Add functions of a namespace to the lookup structure.
    Returns true on error.  */
 
@@ -4214,8 +4328,25 @@ arg_assoc_namespace (struct arg_lookup *
     return false;
 
   for (; value; value = OVL_NEXT (value))
-    if (add_function (k, OVL_CURRENT (value)))
-      return true;
+    {
+      /* We don't want to find arbitrary hidden functions via argument
+	 dependent lookup.  We only want to find friends of associated
+	 classes.  */
+      if (hidden_name_p (OVL_CURRENT (value)))
+	{
+	  tree args;
+
+	  for (args = k->args; args; args = TREE_CHAIN (args))
+	    if (friend_of_associated_class_p (TREE_VALUE (args),
+					      OVL_CURRENT (value)))
+	      break;
+	  if (!args)
+	    continue;
+	}
+
+      if (add_function (k, OVL_CURRENT (value)))
+	return true;
+    }
 
   return false;
 }
@@ -4486,7 +4617,14 @@ lookup_arg_dependent (tree name, tree fn
   struct arg_lookup k;
 
   timevar_push (TV_NAME_LOOKUP);
+
+  /* Remove any hidden friend functions from the list of functions
+     found so far.  They will be added back by arg_assoc_class as
+     appropriate.  */
+  fns = remove_hidden_names (fns);
+
   k.name = name;
+  k.args = args;
   k.functions = fns;
   k.classes = NULL_TREE;
 
@@ -4700,7 +4838,7 @@ pushtag (tree name, tree type, tag_scope
 	    pushdecl_class_level (decl);
 	}
       else if (b->kind != sk_template_parms)
-	decl = pushdecl_with_scope (decl, b);
+	decl = pushdecl_with_scope (decl, b, /*is_friend=*/false);
 
       TYPE_CONTEXT (type) = DECL_CONTEXT (decl);
 
Index: cp/name-lookup.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.h,v
retrieving revision 1.44
diff -p -u -r1.44 name-lookup.h
--- cp/name-lookup.h	25 Jun 2005 00:58:12 -0000	1.44
+++ cp/name-lookup.h	10 Sep 2005 03:32:32 -0000
@@ -311,20 +311,21 @@ extern void push_nested_namespace (tree)
 extern void pop_nested_namespace (tree);
 extern void pushlevel_class (void);
 extern void poplevel_class (void);
-extern tree pushdecl_with_scope (tree, cxx_scope *);
+extern tree pushdecl_with_scope (tree, cxx_scope *, bool);
 extern tree lookup_name	(tree, int);
 extern tree lookup_name_real (tree, int, int, bool, int, int);
 extern tree lookup_type_scope (tree, tag_scope);
 extern tree namespace_binding (tree, tree);
 extern void set_namespace_binding (tree, tree, tree);
 extern bool hidden_name_p (tree);
+extern tree remove_hidden_names (tree);
 extern tree lookup_namespace_name (tree, tree);
 extern tree lookup_qualified_name (tree, tree, bool, bool);
 extern tree lookup_name_nonclass (tree);
 extern tree lookup_function_nonclass (tree, tree, bool);
 extern void push_local_binding (tree, tree, int);
 extern bool pushdecl_class_level (tree);
-extern tree pushdecl_namespace_level (tree);
+extern tree pushdecl_namespace_level (tree, bool);
 extern bool push_class_level_binding (tree, tree);
 extern tree getdecls (void);
 extern tree cp_namespace_decls (tree);
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.1029
diff -p -u -r1.1029 pt.c
--- cp/pt.c	5 Sep 2005 16:12:13 -0000	1.1029
+++ cp/pt.c	10 Sep 2005 03:32:34 -0000
@@ -1114,11 +1114,12 @@ is_specialization_of_friend (tree decl, 
 }
 
 /* Register the specialization SPEC as a specialization of TMPL with
-   the indicated ARGS.  Returns SPEC, or an equivalent prior
-   declaration, if available.  */
+   the indicated ARGS.  IS_FRIEND indicates whether the specialization
+   is actually just a friend declaration.  Returns SPEC, or an
+   equivalent prior declaration, if available.  */
 
 static tree
-register_specialization (tree spec, tree tmpl, tree args)
+register_specialization (tree spec, tree tmpl, tree args, bool is_friend)
 {
   tree fn;
 
@@ -1185,14 +1186,14 @@ register_specialization (tree spec, tree
 		 for the specialization, we want this to look as if
 		 there were no definition, and vice versa.  */
 	      DECL_INITIAL (fn) = NULL_TREE;
-	      duplicate_decls (spec, fn);
+	      duplicate_decls (spec, fn, is_friend);
 
 	      return fn;
 	    }
 	}
       else if (DECL_TEMPLATE_SPECIALIZATION (fn))
 	{
-	  if (!duplicate_decls (spec, fn) && DECL_INITIAL (spec))
+	  if (!duplicate_decls (spec, fn, is_friend) && DECL_INITIAL (spec))
 	    /* Dup decl failed, but this is a new definition. Set the
 	       line number so any errors match this new
 	       definition.  */
@@ -2108,7 +2109,7 @@ check_explicit_specialization (tree decl
 
 	  /* Register this specialization so that we can find it
 	     again.  */
-	  decl = register_specialization (decl, gen_tmpl, targs);
+	  decl = register_specialization (decl, gen_tmpl, targs, is_friend);
 	}
     }
 
@@ -2882,10 +2883,10 @@ template_parm_this_level_p (tree t, void
    previously existing one, if appropriate.  Returns the DECL, or an
    equivalent one, if it is replaced via a call to duplicate_decls.
 
-   If IS_FRIEND is nonzero, DECL is a friend declaration.  */
+   If IS_FRIEND is true, DECL is a friend declaration.  */
 
 tree
-push_template_decl_real (tree decl, int is_friend)
+push_template_decl_real (tree decl, bool is_friend)
 {
   tree tmpl;
   tree args;
@@ -2906,7 +2907,8 @@ push_template_decl_real (tree decl, int 
 		&& TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
 		&& CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
 
-  is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
+  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl))
+    is_friend = true;
 
   if (is_friend)
     /* For a friend, we want the context of the friend function, not
@@ -3081,7 +3083,8 @@ push_template_decl_real (tree decl, int 
 
 	  register_specialization (new_tmpl,
 				   most_general_template (tmpl),
-				   args);
+				   args,
+				   is_friend);
 	  return decl;
 	}
 
@@ -3132,7 +3135,7 @@ push_template_decl_real (tree decl, int 
   if (new_template_p && !ctx
       && !(is_friend && template_class_depth (current_class_type) > 0))
     {
-      tmpl = pushdecl_namespace_level (tmpl);
+      tmpl = pushdecl_namespace_level (tmpl, is_friend);
       if (tmpl == error_mark_node)
 	return error_mark_node;
 
@@ -3187,7 +3190,7 @@ push_template_decl_real (tree decl, int 
 tree
 push_template_decl (tree decl)
 {
-  return push_template_decl_real (decl, 0);
+  return push_template_decl_real (decl, false);
 }
 
 /* Called when a class template TYPE is redeclared with the indicated
@@ -5175,7 +5178,7 @@ tsubst_friend_function (tree decl, tree 
 	 into the namespace of the template.  */
       ns = decl_namespace_context (new_friend);
       push_nested_namespace (ns);
-      old_decl = pushdecl_namespace_level (new_friend);
+      old_decl = pushdecl_namespace_level (new_friend, /*is_friend=*/true);
       pop_nested_namespace (ns);
 
       if (old_decl != new_friend)
@@ -5387,7 +5390,7 @@ tsubst_friend_class (tree friend_tmpl, t
 	= INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)));
 
       /* Inject this template into the global scope.  */
-      friend_type = TREE_TYPE (pushdecl_top_level (tmpl));
+      friend_type = TREE_TYPE (pushdecl_top_level_maybe_friend (tmpl, true));
     }
 
   if (context)
@@ -6302,7 +6305,8 @@ tsubst_decl (tree t, tree args, tsubst_f
 	if (TREE_CODE (decl) != TYPE_DECL)
 	  /* Record this non-type partial instantiation.  */
 	  register_specialization (r, t,
-				   DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)));
+				   DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
+				   false);
       }
       break;
 
@@ -6477,7 +6481,7 @@ tsubst_decl (tree t, tree args, tsubst_f
 	    DECL_TEMPLATE_INFO (r)
 	      = tree_cons (gen_tmpl, argvec, NULL_TREE);
 	    SET_DECL_IMPLICIT_INSTANTIATION (r);
-	    register_specialization (r, gen_tmpl, argvec);
+	    register_specialization (r, gen_tmpl, argvec, false);
 
 	    /* We're not supposed to instantiate default arguments
 	       until they are called, for a template.  But, for a
@@ -6699,7 +6703,7 @@ tsubst_decl (tree t, tree args, tsubst_f
 	       processing here.  */
 	    DECL_EXTERNAL (r) = 1;
 
-	    register_specialization (r, gen_tmpl, argvec);
+	    register_specialization (r, gen_tmpl, argvec, false);
 	    DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
 	    SET_DECL_IMPLICIT_INSTANTIATION (r);
 	  }
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.486
diff -p -u -r1.486 semantics.c
--- cp/semantics.c	6 Sep 2005 02:12:30 -0000	1.486
+++ cp/semantics.c	10 Sep 2005 03:32:35 -0000
@@ -1820,7 +1820,7 @@ finish_call_expr (tree fn, tree args, bo
 
       if (!result)
 	/* A call to a namespace-scope function.  */
-	result = build_new_function_call (fn, args);
+	result = build_new_function_call (fn, args, koenig_p);
     }
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
     {
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.676
diff -p -u -r1.676 invoke.texi
--- doc/invoke.texi	6 Sep 2005 10:59:50 -0000	1.676
+++ doc/invoke.texi	10 Sep 2005 03:32:38 -0000
@@ -171,7 +171,7 @@ in the following sections.
 @item C++ Language Options
 @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
 @gccoptlist{-fabi-version=@var{n}  -fno-access-control  -fcheck-new @gol
--fconserve-space  -fno-const-strings @gol
+-fconserve-space  -ffriend-injection  -fno-const-strings @gol
 -fno-elide-constructors @gol
 -fno-enforce-eh-specs @gol
 -ffor-scope  -fno-for-scope  -fno-gnu-keywords @gol
@@ -1425,6 +1425,20 @@ two definitions were merged.
 This option is no longer useful on most targets, now that support has
 been added for putting variables into BSS without making them common.
 
+@item -ffriend-injection
+@opindex ffriend-injection
+Inject friend functions into the enclosing namespace, so that they are
+visible outside the scope of the class in which they are declared.
+Friend functions were documented to work this way in the old Annotated
+C++ Reference Manual, and versions of G++ before 4.1 always worked
+that way.  However, in ISO C++ a friend function which is not declared
+in an enclosing scope can only be found using argument dependent
+lookup.  This option causes friends to be injected as they were in
+earlier releases.
+
+This option is for compatibility, and may be removed in a future
+release of G++.
+
 @item -fno-const-strings
 @opindex fno-const-strings
 Give string constants type @code{char *} instead of type @code{const
Index: testsuite/g++.dg/lookup/friend7.C
===================================================================
RCS file: testsuite/g++.dg/lookup/friend7.C
diff -N testsuite/g++.dg/lookup/friend7.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/g++.dg/lookup/friend7.C	10 Sep 2005 03:32:49 -0000
@@ -0,0 +1,19 @@
+// { dg-do compile }
+// PR c++/7874: Don't inject friend functions into global name space.
+
+namespace N { template<typename T> struct A { friend void f(A) { }; }; }
+int main()
+{
+   N::A<int> a;
+   N::f(a);		// { dg-error "not a member" }
+}
+
+struct S { friend void g(); friend void h(S); };
+struct T { friend void g(); friend void h(T); };
+void i() {
+  g();			// { dg-error "not declared" }
+  S s;
+  h(s);
+  T t;
+  h(t);
+}
Index: testsuite/g++.dg/lookup/friend8.C
===================================================================
RCS file: testsuite/g++.dg/lookup/friend8.C
diff -N testsuite/g++.dg/lookup/friend8.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/g++.dg/lookup/friend8.C	10 Sep 2005 03:32:49 -0000
@@ -0,0 +1,12 @@
+// Test that we look up a friend declared at top level ahead of an
+// undeclared friend found by argument dependent lookup.
+
+// { dg-do run }
+
+int f(int) { return 0; }
+
+struct S {
+  friend int f(char) { return 1; }
+};
+
+int main () { return f('a'); }
Index: testsuite/g++.dg/parse/defarg4.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/parse/defarg4.C,v
retrieving revision 1.1
diff -p -u -r1.1 defarg4.C
--- testsuite/g++.dg/parse/defarg4.C	3 Jul 2003 16:10:52 -0000	1.1
+++ testsuite/g++.dg/parse/defarg4.C	10 Sep 2005 03:32:50 -0000
@@ -6,9 +6,10 @@
 // PR c++ 9162. default args got left unprocessed
 
 struct S {
-  friend int foo (int = 100);
+  friend int foo (const S&, int = 100);
 };
-int i = foo ();
+S s;
+int i = foo (s);
 
 struct R
 {
Index: testsuite/g++.old-deja/g++.brendan/crash56.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C,v
retrieving revision 1.9
diff -p -u -r1.9 crash56.C
--- testsuite/g++.old-deja/g++.brendan/crash56.C	23 Sep 2004 21:27:19 -0000	1.9
+++ testsuite/g++.old-deja/g++.brendan/crash56.C	10 Sep 2005 03:32:53 -0000
@@ -20,15 +20,15 @@ public:
     class Vix {
     public:
 	Vix();
-	friend int operator==(void *v, const Vix& x) // { dg-error "operator==" }
+	friend int operator==(void *v, const Vix& x)
 	    { return v == x.item; }
-	friend int operator==(const Vix& x, void *v) // { dg-error "operator==" }
+	friend int operator==(const Vix& x, void *v)
 	    { return v == x.item; }
 	friend int operator!=(void *v, const Vix& x)
 	    { return v != x.item; }
 	friend int operator!=(const Vix& x, void *v)
 	    { return v != x.item; }
-	friend int operator==(const Vix& x1, const Vix& x2) // { dg-error "operator==" }
+	friend int operator==(const Vix& x1, const Vix& x2)
 	    { return x1.owner == x2.owner && x1.item == x2.item; }
 	friend int operator!=(const Vix& x1, const Vix& x2)
 	    { return x1.owner != x2.owner || x1.item != x2.item; }
Index: testsuite/g++.old-deja/g++.jason/friend.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.jason/friend.C,v
retrieving revision 1.4
diff -p -u -r1.4 friend.C
--- testsuite/g++.old-deja/g++.jason/friend.C	1 May 2003 02:02:40 -0000	1.4
+++ testsuite/g++.old-deja/g++.jason/friend.C	10 Sep 2005 03:32:53 -0000
@@ -10,10 +10,11 @@ struct A {
 
 struct B {
   static void f () { exit (0); }
-  friend void g () { f (); }
+  friend void g (B) { f (); }
 };
 
 int main ()
 {
-  g ();
+  B b;
+  g (b);
 }
Index: testsuite/g++.old-deja/g++.jason/scoping15.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.jason/scoping15.C,v
retrieving revision 1.3
diff -p -u -r1.3 scoping15.C
--- testsuite/g++.old-deja/g++.jason/scoping15.C	1 May 2003 02:02:41 -0000	1.3
+++ testsuite/g++.old-deja/g++.jason/scoping15.C	10 Sep 2005 03:32:53 -0000
@@ -1,4 +1,5 @@
 // { dg-do assemble  }
+// { dg-options "-ffriend-injection" }
 // Bug: g++ ignores the :: qualification and dies trying to treat an integer
 // variable as a list of functions.
 
Index: testsuite/g++.old-deja/g++.mike/net43.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.mike/net43.C,v
retrieving revision 1.4
diff -p -u -r1.4 net43.C
--- testsuite/g++.old-deja/g++.mike/net43.C	1 May 2003 02:02:45 -0000	1.4
+++ testsuite/g++.old-deja/g++.mike/net43.C	10 Sep 2005 03:32:53 -0000
@@ -1,4 +1,5 @@
 // { dg-do assemble  }
+// { dg-options "-ffriend-injection" }
 
 class foo {
  public:


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