c++: hidden friend access [DR1699]
authorJason Merrill <jason@redhat.com>
Sat, 19 Mar 2022 02:52:32 +0000 (22:52 -0400)
committerJason Merrill <jason@redhat.com>
Sun, 15 May 2022 16:43:30 +0000 (12:43 -0400)
It has come up several times that Clang considers hidden friends of a class
to be sufficiently memberly to be covered by a friend declaration naming the
class.  This is somewhat unclear in the standard: [class.friend] says
"Declaring a class to be a friend implies that private and protected members
of the class granting friendship can be named in the base-specifiers and
member declarations of the befriended class."

A hidden friend is a syntactic member-declaration, but is it a "member
declaration"?  CWG was ambivalent, and referred the question to EWG as a
design choice.  But recently Patrick mentioned that the current G++ choice
not to treat it as a "member declaration" was making his library work
significantly more cumbersome, so let's go ahead and vote the other way.

This means that the testcases for 100502 and 58993 are now accepted.

DR1699
PR c++/100502
PR c++/58993

gcc/cp/ChangeLog:

* friend.cc (is_friend): Hidden friends count as members.
* search.cc (friend_accessible_p): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/template/access37.C: Now OK.
* g++.dg/template/friend69.C: Now OK.
* g++.dg/lookup/friend23.C: New test.

gcc/cp/friend.cc
gcc/cp/search.cc
gcc/testsuite/g++.dg/lookup/friend23.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/access37.C
gcc/testsuite/g++.dg/template/friend69.C

index 124ed4f3962d82a44c8a2a699afdb80eb1bb7929..bf37dadeb6223b2901f9cc8922ba797131dfa7b5 100644 (file)
@@ -131,6 +131,8 @@ is_friend (tree type, tree supplicant)
     {
       if (DECL_FUNCTION_MEMBER_P (supplicant))
        context = DECL_CONTEXT (supplicant);
+      else if (tree fc = DECL_FRIEND_CONTEXT (supplicant))
+       context = fc;
       else
        context = NULL_TREE;
     }
index b86b3a24080eb09241e6aa61a53e15f2d169ba7a..10863a40b116c0a2fd6df07f21a94175e66fe01d 100644 (file)
@@ -734,12 +734,9 @@ friend_accessible_p (tree scope, tree decl, tree type, tree otype)
          && friend_accessible_p (DECL_CONTEXT (scope), decl, type, otype))
        return 1;
       /* Perhaps SCOPE is a friend function defined inside a class from which
-        DECL is accessible.  Checking this is necessary only when the class
-        is dependent, for otherwise add_friend will already have added the
-        class to SCOPE's DECL_BEFRIENDING_CLASSES.  */
+        DECL is accessible.  */
       if (tree fctx = DECL_FRIEND_CONTEXT (scope))
-       if (dependent_type_p (fctx)
-           && protected_accessible_p (decl, fctx, type, otype))
+       if (friend_accessible_p (fctx, decl, type, otype))
          return 1;
     }
 
diff --git a/gcc/testsuite/g++.dg/lookup/friend23.C b/gcc/testsuite/g++.dg/lookup/friend23.C
new file mode 100644 (file)
index 0000000..f7b26c9
--- /dev/null
@@ -0,0 +1,17 @@
+template <class Derived>
+struct base {
+  friend void bar(Derived& d) {
+    d.bar(); // access in inline friend of friend, ok?
+  }
+};
+
+class derived : base<derived> {
+  friend class base<derived>;
+  void bar() {}
+};
+
+int main() {
+  derived d;
+  bar(d);
+}
+
index 5be532c75b09c6567533959e75e1cdf26ebbc5ff..407a7dc0f2dca1a4e9c2924662b20d35543bd83d 100644 (file)
@@ -6,10 +6,10 @@ struct EnumeratorRange {
     EnumeratorRange range_;
 
     friend void f(Iterator i) {
-      i.range_.end_reached_; // { dg-error "private" }
-      i.range_.EnumeratorRange::end_reached_; // { dg-error "private" }
-      &i.range_.end_reached_; // { dg-error "private" }
-      &i.range_.EnumeratorRange::end_reached_; // { dg-error "private" }
+      i.range_.end_reached_;
+      i.range_.EnumeratorRange::end_reached_;
+      &i.range_.end_reached_;
+      &i.range_.EnumeratorRange::end_reached_;
     }
   };
 
index f3086a9f980ae0030b0b32bba62c0baa5a7c5cbd..9bec6ba5846fcda3ffe5fcff5fc246c9f53b7412 100644 (file)
@@ -12,7 +12,7 @@ protected:
 
 struct A {
   friend void g(A) {
-    B::f(); // { dg-error "private" }
-    B::g(); // { dg-error "protected" }
+    B::f();
+    B::g();
   }
 };