]> gcc.gnu.org Git - gcc.git/commitdiff
c++: namespace-scoped friend in local class [PR69410]
authorJason Merrill <jason@redhat.com>
Fri, 17 Mar 2023 13:43:48 +0000 (09:43 -0400)
committerJason Merrill <jason@redhat.com>
Tue, 18 Apr 2023 20:44:27 +0000 (16:44 -0400)
do_friend was only considering class-qualified identifiers for the
qualified-id case, but we also need to skip local scope when there's an
explicit namespace scope.

PR c++/69410

gcc/cp/ChangeLog:

* friend.cc (do_friend): Handle namespace as scope argument.
* decl.cc (grokdeclarator): Pass down in_namespace.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/friend24.C: New test.

gcc/cp/decl.cc
gcc/cp/friend.cc
gcc/testsuite/g++.dg/lookup/friend24.C [new file with mode: 0644]

index dcb9f0c47034159361196e8d2e6f55753a5a32dd..cbb9f20b7a487bfa34c53624f9b2aedff21350a0 100644 (file)
@@ -14206,7 +14206,8 @@ grokdeclarator (const cp_declarator *declarator,
                      return error_mark_node;
                  }
 
-               decl = do_friend (ctype, unqualified_id, decl,
+               tree scope = ctype ? ctype : in_namespace;
+               decl = do_friend (scope, unqualified_id, decl,
                                  flags, funcdef_flag);
                return decl;
              }
index acbe0eccb8ed82788be89a60b816fc27b5524ef3..18c56cc67d25caa651a923a203a63391ef7148ef 100644 (file)
@@ -485,19 +485,32 @@ make_friend_class (tree type, tree friend_type, bool complain)
 }
 
 /* Record DECL (a FUNCTION_DECL) as a friend of the
-   CURRENT_CLASS_TYPE.  If DECL is a member function, CTYPE is the
+   CURRENT_CLASS_TYPE.  If DECL is a member function, SCOPE is the
    class of which it is a member, as named in the friend declaration.
+   If the friend declaration was explicitly namespace-qualified, SCOPE
+   is that namespace.
    DECLARATOR is the name of the friend.  FUNCDEF_FLAG is true if the
    friend declaration is a definition of the function.  FLAGS is as
    for grokclass fn.  */
 
 tree
-do_friend (tree ctype, tree declarator, tree decl,
+do_friend (tree scope, tree declarator, tree decl,
           enum overload_flags flags,
           bool funcdef_flag)
 {
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
-  gcc_assert (!ctype || MAYBE_CLASS_TYPE_P (ctype));
+
+  tree ctype = NULL_TREE;
+  tree in_namespace = NULL_TREE;
+  if (!scope)
+    ;
+  else if (MAYBE_CLASS_TYPE_P (scope))
+    ctype = scope;
+  else
+    {
+      gcc_checking_assert (TREE_CODE (scope) == NAMESPACE_DECL);
+      in_namespace = scope;
+    }
 
   /* Friend functions are unique, until proved otherwise.  */
   DECL_UNIQUE_FRIEND_P (decl) = 1;
@@ -617,7 +630,7 @@ do_friend (tree ctype, tree declarator, tree decl,
               parameters.  Instead, we call pushdecl when the class
               is instantiated.  */
            decl = push_template_decl (decl, /*is_friend=*/true);
-         else if (current_function_decl)
+         else if (current_function_decl && !in_namespace)
            /* pushdecl will check there's a local decl already.  */
            decl = pushdecl (decl, /*hiding=*/true);
          else
diff --git a/gcc/testsuite/g++.dg/lookup/friend24.C b/gcc/testsuite/g++.dg/lookup/friend24.C
new file mode 100644 (file)
index 0000000..9a45410
--- /dev/null
@@ -0,0 +1,9 @@
+// PR c++/69410
+
+void a();
+void f() {
+    class A {
+        friend void ::a();
+        friend class Z;
+    };
+}
This page took 0.089592 seconds and 5 git commands to generate.