./
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 12 Sep 2005 19:54:23 +0000 (19:54 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 12 Sep 2005 19:54:23 +0000 (19:54 +0000)
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/
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/
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@104188 138bc75d-0d04-0410-961f-82ee72b054a4

21 files changed:
gcc/ChangeLog
gcc/c.opt
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/friend.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lookup/friend7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lookup/friend8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/defarg4.C
gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
gcc/testsuite/g++.old-deja/g++.jason/friend.C
gcc/testsuite/g++.old-deja/g++.jason/scoping15.C
gcc/testsuite/g++.old-deja/g++.mike/net43.C

index 36dedc7..2e26c7d 100644 (file)
@@ -1,3 +1,10 @@
+2005-09-12  Ian Lance Taylor  <ian@airs.com>
+
+       PR g++/7874
+       * c.opt (ffriend-injection): New C++ option.
+       * doc/invoke.texi (Option Summary): Mention -ffriend-injection.
+       (C++ Dialect Options): Document -ffriend-injection.
+
 2005-09-12  Josh Conner  <jconner@apple.com>
 
        PR middle-end/23237
index 908efd6..d650f11 100644 (file)
--- a/gcc/c.opt
+++ b/gcc/c.opt
@@ -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 4ea174c..b0f70bc 100644 (file)
@@ -1,3 +1,54 @@
+2005-09-12  Ian Lance Taylor  <ian@airs.com>
+
+       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.
+
 2005-09-11  Richard Henderson  <rth@redhat.com>
 
        * decl2.c (build_anon_union_vars): Copy attributes from the base addr.
index fab01fc..e8f93c4 100644 (file)
@@ -1309,10 +1309,10 @@ add_function_candidate (struct z_candidate **candidates,
   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 args)
   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 98a8800..7fdeb87 100644 (file)
@@ -5645,7 +5645,8 @@ resolve_address_of_overloaded_function (tree target_type,
               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 cf24129..9e74d37 100644 (file)
@@ -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 (tree, tree);
 #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                (tree);
 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 f332761..9907292 100644 (file)
@@ -1009,13 +1009,15 @@ warn_extern_redeclared_static (tree newdecl, tree olddecl)
    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)
@@ -1069,9 +1071,11 @@ duplicate_decls (tree newdecl, tree olddecl)
   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;
 
@@ -1102,7 +1106,8 @@ duplicate_decls (tree newdecl, tree olddecl)
        }
       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
@@ -1131,7 +1136,8 @@ duplicate_decls (tree newdecl, tree olddecl)
                          = 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;
                      }
                  }
@@ -1163,8 +1169,9 @@ duplicate_decls (tree newdecl, tree olddecl)
          /* 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);
@@ -1460,7 +1467,7 @@ duplicate_decls (tree newdecl, tree olddecl)
          /* 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);
@@ -1685,6 +1692,9 @@ duplicate_decls (tree newdecl, tree olddecl)
       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
@@ -1898,6 +1908,11 @@ duplicate_decls (tree newdecl, tree olddecl)
   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.  */
@@ -3142,7 +3157,7 @@ cp_make_fname_decl (tree id, int type_dep)
       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
@@ -3185,8 +3200,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;
 
@@ -3720,7 +3736,7 @@ start_decl (const cp_declarator *declarator,
              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;
            }
        }
@@ -3731,7 +3747,8 @@ start_decl (const cp_declarator *declarator,
                                       > 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;
        }
 
@@ -5871,7 +5888,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 4e1a209..c71b90f 100644 (file)
@@ -480,7 +480,7 @@ do_friend (tree ctype, tree declarator, tree 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);
+           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, tree decl,
               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 decl,
              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 cba9393..9afde87 100644 (file)
@@ -44,7 +44,7 @@ static cxx_scope *innermost_nonclass_level (void);
 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, tree decl)
              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, tree decl)
           && 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 *b)
 
 /* 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 ())
@@ -997,6 +1009,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.  */
 
@@ -1795,7 +1815,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;
@@ -1813,7 +1833,7 @@ pushdecl_with_scope (tree x, cxx_scope *level)
     {
       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;
@@ -1835,12 +1855,14 @@ pushdecl_with_scope (tree x, cxx_scope *level)
      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;
@@ -1880,7 +1902,7 @@ push_overloaded_decl (tree decl, int flags)
                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);
            }
 
@@ -1888,7 +1910,8 @@ push_overloaded_decl (tree decl, int flags)
             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)
@@ -2037,7 +2060,8 @@ do_nonmember_using_decl (tree scope, tree name, tree oldval, tree oldtype,
      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.  */
@@ -2075,7 +2099,8 @@ do_nonmember_using_decl (tree scope, tree name, tree oldval, tree oldtype,
              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
@@ -2168,7 +2193,8 @@ do_local_using_decl (tree decl, tree scope, tree name)
          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);
@@ -3058,13 +3084,13 @@ do_namespace_alias (tree alias, tree namespace)
    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.  */
@@ -3247,11 +3273,11 @@ parse_using_directive (tree namespace, tree attribs)
    *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 ();
@@ -3263,7 +3289,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
@@ -3273,7 +3307,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
@@ -3440,7 +3474,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)
@@ -3452,6 +3486,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
@@ -4112,6 +4178,7 @@ lookup_type_current_level (tree name)
 struct arg_lookup
 {
   tree name;
+  tree args;
   tree namespaces;
   tree classes;
   tree functions;
@@ -4190,6 +4257,53 @@ is_associated_namespace (tree current, tree scope)
     }
 }
 
+/* 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.  */
 
@@ -4213,8 +4327,25 @@ arg_assoc_namespace (struct arg_lookup *k, tree scope)
     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;
 }
@@ -4485,7 +4616,14 @@ lookup_arg_dependent (tree name, tree fns, tree args)
   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;
 
@@ -4699,7 +4837,7 @@ pushtag (tree name, tree type, tag_scope 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 2a0c4c4..fa2a760 100644 (file)
@@ -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 85e8cb8..3f74955 100644 (file)
@@ -1114,11 +1114,12 @@ is_specialization_of_friend (tree decl, tree friend)
 }
 
 /* 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 tmpl, tree args)
                 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 declarator,
 
          /* 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* data)
    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 is_friend)
                && 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 is_friend)
 
          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 is_friend)
   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 is_friend)
 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 args)
         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, tree args)
        = 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_flags_t complain)
        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_flags_t complain)
            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
@@ -6706,7 +6710,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
               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 0e926bf..c7392b0 100644 (file)
@@ -1822,7 +1822,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
 
       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 7dfa3a4..55cf558 100644 (file)
@@ -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 f8ba4db..cdea80a 100644 (file)
@@ -1,3 +1,18 @@
+2005-09-12  Ian Lance Taylor  <ian@airs.com>
+
+       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.
+
 2005-09-12  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/23691
diff --git a/gcc/testsuite/g++.dg/lookup/friend7.C b/gcc/testsuite/g++.dg/lookup/friend7.C
new file mode 100644 (file)
index 0000000..dd19c72
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/lookup/friend8.C b/gcc/testsuite/g++.dg/lookup/friend8.C
new file mode 100644 (file)
index 0000000..e9992cd
--- /dev/null
@@ -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 39d0a89..bafdadb 100644 (file)
@@ -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 57c7c11..d1cae6d 100644 (file)
@@ -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 e2cf7fe..9bcc814 100644 (file)
@@ -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 5485b29..cc34c5f 100644 (file)
@@ -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 234295f..aadd03d 100644 (file)
@@ -1,4 +1,5 @@
 // { dg-do assemble  }
+// { dg-options "-ffriend-injection" }
 
 class foo {
  public: