[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