aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-03-18 22:52:32 -0400
committerJason Merrill <jason@redhat.com>2022-05-15 12:43:30 -0400
commit4df735e01e319997841574f353d2aa076a0335c2 (patch)
tree5d8ff6e326d0233e450a1e59d7ecc30404424fa1
parent87e1f023aae945aedd7ea046e06b4f52318913f7 (diff)
downloadgcc-4df735e01e319997841574f353d2aa076a0335c2.zip
gcc-4df735e01e319997841574f353d2aa076a0335c2.tar.gz
gcc-4df735e01e319997841574f353d2aa076a0335c2.tar.bz2
c++: hidden friend access [DR1699]
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.
-rw-r--r--gcc/cp/friend.cc2
-rw-r--r--gcc/cp/search.cc7
-rw-r--r--gcc/testsuite/g++.dg/lookup/friend23.C17
-rw-r--r--gcc/testsuite/g++.dg/template/access37.C8
-rw-r--r--gcc/testsuite/g++.dg/template/friend69.C4
5 files changed, 27 insertions, 11 deletions
diff --git a/gcc/cp/friend.cc b/gcc/cp/friend.cc
index 124ed4f..bf37dad 100644
--- a/gcc/cp/friend.cc
+++ b/gcc/cp/friend.cc
@@ -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;
}
diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index b86b3a2..10863a4 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -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
index 0000000..f7b26c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/friend23.C
@@ -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);
+}
+
diff --git a/gcc/testsuite/g++.dg/template/access37.C b/gcc/testsuite/g++.dg/template/access37.C
index 5be532c..407a7dc 100644
--- a/gcc/testsuite/g++.dg/template/access37.C
+++ b/gcc/testsuite/g++.dg/template/access37.C
@@ -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_;
}
};
diff --git a/gcc/testsuite/g++.dg/template/friend69.C b/gcc/testsuite/g++.dg/template/friend69.C
index f3086a9..9bec6ba 100644
--- a/gcc/testsuite/g++.dg/template/friend69.C
+++ b/gcc/testsuite/g++.dg/template/friend69.C
@@ -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();
}
};