Friend accessibility check is wrong when at least 2-step inheritance is
present. Friendship check is done with the currently observed base instead of
the class for which the check is actually requested. This patch fixes that
issue.
PR c++/123228
gcc/cp/ChangeLog:
* search.cc (dfs_walk_once_accessible_r): Pass lookup initiation binfo
as a separate
parameter.
gcc/testsuite/ChangeLog:
* g++.dg/lookup/friend26.C: New test.
Tested on x86_64-pc-linux-gnu.
---
gcc/cp/search.cc | 11 ++++++-----
gcc/testsuite/g++.dg/lookup/friend26.C | 23 +++++++++++++++++++++++
2 files changed, 29 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/lookup/friend26.C
diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index 77b5b1da5..880e97639 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -1634,7 +1634,8 @@ dfs_walk_once (tree binfo, tree (*pre_fn) (tree, void *),
indicates whether bases should be marked during traversal. */
static tree
-dfs_walk_once_accessible_r (tree binfo, bool friends_p, hash_set<tree> *pset,
+dfs_walk_once_accessible_r (tree binfo, tree binfo_initial, bool friends_p,
+ hash_set<tree> *pset,
tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *), void *data)
{
@@ -1674,15 +1675,15 @@ dfs_walk_once_accessible_r (tree binfo, bool friends_p,
hash_set<tree> *pset,
scope = current_scope ();
if (!scope
|| TREE_CODE (scope) == NAMESPACE_DECL
- || !is_friend (BINFO_TYPE (binfo), scope))
+ || !is_friend (BINFO_TYPE (binfo_initial), scope))
continue;
}
if (mark)
pset->add (base_binfo);
- rval = dfs_walk_once_accessible_r (base_binfo, friends_p, pset,
- pre_fn, post_fn, data);
+ rval = dfs_walk_once_accessible_r (base_binfo, binfo_initial, friends_p,
+ pset, pre_fn, post_fn, data);
if (rval)
return rval;
}
@@ -1711,7 +1712,7 @@ dfs_walk_once_accessible (tree binfo, bool friends_p,
hash_set<tree> *pset = NULL;
if (CLASSTYPE_DIAMOND_SHAPED_P (BINFO_TYPE (binfo)))
pset = new hash_set<tree>;
- tree rval = dfs_walk_once_accessible_r (binfo, friends_p, pset,
+ tree rval = dfs_walk_once_accessible_r (binfo, binfo, friends_p, pset,
pre_fn, post_fn, data);
if (pset)
diff --git a/gcc/testsuite/g++.dg/lookup/friend26.C
b/gcc/testsuite/g++.dg/lookup/friend26.C
new file mode 100644
index 000000000..ffc422909
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/friend26.C
@@ -0,0 +1,23 @@
+// PR c++/123228
+
+struct A {
+ friend struct C;
+
+ A() : i(0) {}
+private:
+ int i;
+};
+
+struct B : protected A {
+};
+
+struct C : B {
+ void f() {
+ i = 1;
+ }
+};
+
+void foo() {
+ C c;
+ c.f();
+}
--
2.53.0