From 4df735e01e319997841574f353d2aa076a0335c2 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 18 Mar 2022 22:52:32 -0400 Subject: [PATCH] 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. --- gcc/cp/friend.cc | 2 ++ gcc/cp/search.cc | 7 ++----- gcc/testsuite/g++.dg/lookup/friend23.C | 17 +++++++++++++++++ gcc/testsuite/g++.dg/template/access37.C | 8 ++++---- gcc/testsuite/g++.dg/template/friend69.C | 4 ++-- 5 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/friend23.C diff --git a/gcc/cp/friend.cc b/gcc/cp/friend.cc index 124ed4f3962d..bf37dadeb622 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 b86b3a24080e..10863a40b116 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 000000000000..f7b26c9e3ae3 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/friend23.C @@ -0,0 +1,17 @@ +template +struct base { + friend void bar(Derived& d) { + d.bar(); // access in inline friend of friend, ok? + } +}; + +class derived : base { + friend class base; + 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 5be532c75b09..407a7dc0f2dc 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 f3086a9f980a..9bec6ba5846f 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(); } }; -- 2.47.2