Bug 58954 - [4.8/4.9 Regression] accessing a private member function in decltype of a friend class causes access control error
Summary: [4.8/4.9 Regression] accessing a private member function in decltype of a fri...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.8.1
: P2 normal
Target Milestone: 4.8.3
Assignee: Jason Merrill
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-11-01 04:16 UTC by George
Modified: 2013-12-27 22:06 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-11-01 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description George 2013-11-01 04:16:22 UTC
When trying to use decltype on a member function which has a late specified return type calling a private member function of a friend class I receive the below error.  My understanding is that the "friend struct base<derived>;" in derived should cause this error to not occur which is the case with clang.  

Adding "foo_argument<derived>" does cause the error to disappear.  

I apologize for the length of the example, but I've had difficulty reproducing it with fewer lines of code.

main.cpp: In instantiation of ‘struct foo_argument<derived>’:
main.cpp:43:47:   required from here
main.cpp:9:50: error: no matching function for call to ‘foo_argument<derived>::test(<unresolved overloaded function type>)’
     using type = decltype(test(&T::template foo<>));
                                                  ^
main.cpp:9:50: note: candidate is:
main.cpp:7:16: note: template<class Ret, class C, class Arg> static Arg foo_argument<T>::test(Ret (C::*)(Arg)) [with Ret = Ret; C = C; Arg = Arg; T = derived]
     static Arg test(Ret (C::*)(Arg));
                ^
main.cpp:7:16: note:   template argument deduction/substitution failed:
main.cpp:35:9: error: ‘int derived::foo_impl(int)’ is private
     int foo_impl(int i)
         ^
main.cpp:9:50: error: within this context
     using type = decltype(test(&T::template foo<>));

The below example can be seen at: http://coliru.stacked-crooked.com/a/3ffd6557434a3ab9

#include <utility>

template<class T>
struct foo_argument
{
    template<class Ret, class C, class Arg>
    static Arg test(Ret (C::*)(Arg));

    using type = decltype(test(&T::template foo<>));
};

template<class T, class D>
struct dependent { typedef T type; };

template<class T, class D>
using Dependent = typename dependent<T, D>::type;

template<class T>
struct base
{
    friend struct foo_argument<T>;

    template<class Ignore = void>
    auto foo(int i) -> decltype(std::declval<Dependent<T&, Ignore>>().foo_impl(i))
    {
        return static_cast<T&>(*this).foo_impl(i);
    }
};

struct derived : base<derived>
{
    friend struct base<derived>;
    //friend struct foo_argument<derived>;
  private:
    int foo_impl(int i)
    {
        return 123 + i;
    }
};

int main()
{
    using foo_arg_type = foo_argument<derived>::type;
}
Comment 1 Daniel Krügler 2013-11-01 06:53:31 UTC
This seems to be a regression, the example was accepted in gcc 4.7.3.

The following is a first attempt to reduce the complexity of the example, in particular by removing any library dependencies and any possible interaction with alias templates and alias typedefs, furthermore the additional friend declaration in template base is neither needed nor should it be relevant for this issue, therefore has been removed:

//---------------
template<class T>
T&& declval();

template<class T>
struct foo_argument
{
  template<class Ret, class C, class Arg>
  static Arg test(Ret (C::*)(Arg));

  typedef decltype(test(&T::template foo<>)) type;
};

template<class T, class>
struct dependent { typedef T type; };

template<class T>
struct base
{
  template<class Ignore = void>
  auto foo(int i) -> decltype(declval<
    typename dependent<T&, Ignore>::type
  >().foo_impl(i));
};

struct derived : base<derived>
{
  friend struct base<derived>;
private:
  int foo_impl(int i);
};

int main()
{
  foo_argument<derived>::type var = 0;
  return var;
}
//---------------
Comment 2 Paolo Carlini 2013-11-01 11:33:36 UTC
Thanks Daniel.
Comment 3 Jason Merrill 2013-12-13 03:58:51 UTC
Author: jason
Date: Fri Dec 13 03:58:48 2013
New Revision: 205952

URL: http://gcc.gnu.org/viewcvs?rev=205952&root=gcc&view=rev
Log:
	PR c++/58954
	* pt.c (resolve_overloaded_unification): Use instantiate_template.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/access02.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/pt.c
Comment 4 Jason Merrill 2013-12-13 03:59:12 UTC
Author: jason
Date: Fri Dec 13 03:59:10 2013
New Revision: 205954

URL: http://gcc.gnu.org/viewcvs?rev=205954&root=gcc&view=rev
Log:
	PR c++/58954
	* pt.c (resolve_overloaded_unification): Discard access checks.

Added:
    branches/gcc-4_8-branch/gcc/testsuite/g++.dg/cpp0x/access02.C
Modified:
    branches/gcc-4_8-branch/gcc/cp/ChangeLog
    branches/gcc-4_8-branch/gcc/cp/pt.c
Comment 5 Jason Merrill 2013-12-27 22:06:13 UTC
Fixed for 4.8.3/4.9.