[PATCH] Fix PR c++/29475: Incomplete template diagnostics

Simon Martin simartin@users.sourceforge.net
Sun Nov 5 18:51:00 GMT 2006


Hi all.

Since version 3.4, when there is a call to an inaccessible member template, 
the error diagnostic is incomplete.

For example, for that piece of code:

  template<class T>
  class Foo {
    template<class U> void bar(U t) {}
  };
  int main() {
    Foo<char>().bar(2);
  }

we get the following error:
  template<class U> void Foo::bar(U) [with U = U, T = char]' is private
                            ^ (no <T>)     ^^^^^

The access check is done in 'build_over_call', where there is a big comment 
explaining that in that particular case, the DECL_ACCESS is not in the 
template instantiation ('fn' in the code) but in the primary template; as a 
consequence, one calls 'perform_or_defer_access_check' with 'DECL_TI_TEMPLATE 
(fn)' instead of 'fn', hence the incomplete diagnostic when the access check 
fails.

The attached patch fixes the diagnostic by "temporarily fixing" 'fn' so that 
one can call 'perform_or_defer_access_check' with it instead of its 
DECL_TI_TEMPLATE. More precisely, 'fn's DECL_ACCESS is set with the one of 
its DECL_TI_TEMPLATE before the call to 'perform_or_defer_access_check' and 
restored afterwards.

With that patch, the error message becomes:
  void Foo<T>::bar(U) [with U = int, T = char]' is private

I had to change testsuite/g++.old-deja/g++.other/access11.C, which involves 
the specialization of a private member function: the error diagnostic now uses 
the number of the line where the specialization is defined, whereas it used 
the number of the line where the primary template is defined.

This has been successfully regtested with no new regressions on 
i686-pc-linux-gnu. Is it OK? If so, could someone commit it for 
me please?

Best regards,
Simon

:ADDPATCH c++:
-------------- next part --------------
2006-11-05  Simon Martin  <simartin@users.sourceforge.net>

	PR c++/29475
	* call.c (build_over_call): Always call perform_or_defer_access_check with
	the declaration of the function member being called to have a proper
	diagnostic in case it is not accessible. When the member is a member
	template, the DECL_ACCESS to use is in the primary template; FN is
	temporarily altered accordingly.
-------------- next part --------------
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(revision 118476)
+++ gcc/cp/call.c	(working copy)
@@ -4761,7 +4761,8 @@ build_over_call (struct z_candidate *can
 
 	 In case #1 where `A::f' is a member template, DECL_ACCESS is
 	 recorded in the primary template but not in its specialization.
-	 We check access of FN using its primary template.
+	 We set FN's DECL_ACCESS with the one of the primary template,
+	 do the access check and then restore FN's initial DECL_ACCESS.
 
 	 In case #2, where `B<int>::g' has a DECL_TEMPLATE_INFO simply
 	 because it is a member of class template B, DECL_ACCESS is
@@ -4770,8 +4771,12 @@ build_over_call (struct z_candidate *can
 	 different access.  */
       if (DECL_TEMPLATE_INFO (fn)
 	  && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
-	perform_or_defer_access_check (cand->access_path,
-				       DECL_TI_TEMPLATE (fn));
+	{
+	  tree saved_access = DECL_ACCESS (fn);
+	  DECL_ACCESS (fn) = DECL_ACCESS (DECL_TI_TEMPLATE (fn));
+	  perform_or_defer_access_check (cand->access_path, fn);
+	  DECL_ACCESS (fn) = saved_access;
+	}
       else
 	perform_or_defer_access_check (cand->access_path, fn);
     }
-------------- next part --------------
2006-11-05  Simon Martin  <simartin@users.sourceforge.net>

	PR c++/29475
	* g++.dg/template/access19.C: New test.
	* g++.old-deja/g++.other/access11.C: Adjusted the line where the error is
	reported.
-------------- next part --------------
Index: gcc/testsuite/g++.old-deja/g++.other/access11.C
===================================================================
--- gcc/testsuite/g++.old-deja/g++.other/access11.C	(revision 118476)
+++ gcc/testsuite/g++.old-deja/g++.other/access11.C	(working copy)
@@ -5,12 +5,12 @@
 class A
 {
 private:
-  template <class T> void g(T t)  {} // { dg-error "" } private
+  template <class T> void g(T t)  {}
   int i;
 };
 
 template <>
-void A::g<int>(int t) { i = 1; }
+void A::g<int>(int t) { i = 1; } // { dg-error "" } private
 
 int main()
 {
-------------- next part --------------
/* PR c++/29475 The error diagnostic contained "U = U" instead of "U = char" */
/* { dg-do "compile" } */

template< class T >
class explicit_t
{
public:
        explicit_t( const T& c ): value( c ) { }
        operator T&() { return value; }
private:
        template< class U >
        explicit_t( U t ); /* { dg-error "with U = char, T = int|is private" } */
        T value;
};

int foo( int x, explicit_t< int > y )
{
        return x + y;
}

int main()
{
        return foo( 5, 'c' ); /* { dg-error "this context" } */
}


More information about the Gcc-patches mailing list