On Fri, 27 Feb 2026, Arseniy Orlov wrote:

> 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.

Thanks for the patch!  I'm surprised no one ran into (and reported) this
access bug until now.

The patch looks good to me, and seems small enough to not require
copyright assignment or DCO (https://gcc.gnu.org/contribute.html#legal).
Merging it will have to wait until GCC 16 branches (so GCC 17 will
include the fix), since we're currently in the regression-only stage of
development and this bug doesn't appear to be a regression.  I've
queued it for merging once we branch (usually around mid April).

Thanks again!

> 
> 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
> 
> 

Reply via email to