Commit 2eb25c98 by Dodji Seketeli Committed by Dodji Seketeli

re PR c++/40007 (specialization causes access problem in primary template)

Fix PR c++/40007

    gcc/cp/ChangeLog:
    	PR c++/40007
    	* cp-tree.h (MEMBER_TYPES_NEEDING_ACCESS_CHECK): Remove this accessor.
    	(TI_TYPEDEFS_NEEDING_ACCESS_CHECKING): New accessor.
    	(get_types_needing_access_check): Declare new entry point.
    	* pt.c (append_type_to_template_for_access_check_1,
    	get_types_needing_access_check): New functions.
    	(perform_typedefs_access_check): Accept FUNCTION_DECLs and
    	RECORD_TYPEs rather than TEMPLATE_DECLs. Use the new
    	get_types_needing_access_check, no more
    	MEMBER_TYPES_NEEDING_ACCESS_CHECK.
    	(instantiate_class_template): Set input_location to the source
    	location of the most specialized template definition.
    	Perform access check using the RECORD_TYPE of the template, not its
    	associated most generic TEMPLATE_DECL.
    	(append_type_to_template_for_access_check): Augment function
    	comments. Use the new get_types_needing_access_check, not
    	MEMBER_TYPE_NEEDING_ACCESS_CHECK. Use the new
    	append_type_to_template_for_access_check_1 subroutine.

    gcc/testsuite/ChangeLog:
    	PR c++/40007
    	* g++.dg/template/typedef18.C: New test.
    	* g++.dg/template/typedef19.C: Likewise.
    	* g++.dg/template/typedef20.C: Likewise.
    	* g++.dg/template/access11.C: Adjust.

From-SVN: r147866
parent 52c3075d
2009-05-26 Dodji Seketeli <dodji@redhat.com>
PR c++/40007
* cp-tree.h (MEMBER_TYPES_NEEDING_ACCESS_CHECK): Remove this accessor.
(TI_TYPEDEFS_NEEDING_ACCESS_CHECKING): New accessor.
(get_types_needing_access_check): Declare new entry point.
* pt.c (append_type_to_template_for_access_check_1,
get_types_needing_access_check): New functions.
(perform_typedefs_access_check): Accept FUNCTION_DECLs and
RECORD_TYPEs rather than TEMPLATE_DECLs. Use the new
get_types_needing_access_check, no more
MEMBER_TYPES_NEEDING_ACCESS_CHECK.
(instantiate_class_template): Set input_location to the source
location of the most specialized template definition.
Perform access check using the RECORD_TYPE of the template, not its
associated most generic TEMPLATE_DECL.
(append_type_to_template_for_access_check): Augment function
comments. Use the new get_types_needing_access_check, not
MEMBER_TYPE_NEEDING_ACCESS_CHECK. Use the new
append_type_to_template_for_access_check_1 subroutine.
2009-05-22 Jason Merrill <jason@redhat.com> 2009-05-22 Jason Merrill <jason@redhat.com>
PR c++/38064 PR c++/38064
......
...@@ -2232,6 +2232,9 @@ extern void decl_shadowed_for_var_insert (tree, tree); ...@@ -2232,6 +2232,9 @@ extern void decl_shadowed_for_var_insert (tree, tree);
#define TI_TEMPLATE(NODE) (TREE_PURPOSE (NODE)) #define TI_TEMPLATE(NODE) (TREE_PURPOSE (NODE))
#define TI_ARGS(NODE) (TREE_VALUE (NODE)) #define TI_ARGS(NODE) (TREE_VALUE (NODE))
#define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE) #define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
/* The list of typedefs - used in the template - that need
access checking at template instantiation time. */
#define TI_TYPEDEFS_NEEDING_ACCESS_CHECKING(NODE) (TREE_CHAIN (NODE))
/* We use TREE_VECs to hold template arguments. If there is only one /* We use TREE_VECs to hold template arguments. If there is only one
level of template arguments, then the TREE_VEC contains the level of template arguments, then the TREE_VEC contains the
...@@ -3160,11 +3163,6 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -3160,11 +3163,6 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
&& TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL \ && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL \
&& !DECL_TEMPLATE_TEMPLATE_PARM_P (NODE)) && !DECL_TEMPLATE_TEMPLATE_PARM_P (NODE))
/* The chained list of typedefs that are referenced in templates.
These typedefs need to be access checked at template instantiation time.
There are put here at parsing time. */
#define MEMBER_TYPES_NEEDING_ACCESS_CHECK(NODE) DECL_ACCESS (NODE)
/* Nonzero if NODE which declares a type. */ /* Nonzero if NODE which declares a type. */
#define DECL_DECLARES_TYPE_P(NODE) \ #define DECL_DECLARES_TYPE_P(NODE) \
(TREE_CODE (NODE) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (NODE)) (TREE_CODE (NODE) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (NODE))
...@@ -4572,6 +4570,7 @@ extern bool template_parameter_pack_p (const_tree); ...@@ -4572,6 +4570,7 @@ extern bool template_parameter_pack_p (const_tree);
extern tree make_pack_expansion (tree); extern tree make_pack_expansion (tree);
extern bool check_for_bare_parameter_packs (tree); extern bool check_for_bare_parameter_packs (tree);
extern tree get_template_info (tree); extern tree get_template_info (tree);
extern tree get_types_needing_access_check (tree);
extern int template_class_depth (tree); extern int template_class_depth (tree);
extern int is_specialization_of (tree, tree); extern int is_specialization_of (tree, tree);
extern bool is_specialization_of_friend (tree, tree); extern bool is_specialization_of_friend (tree, tree);
......
...@@ -175,6 +175,7 @@ static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); ...@@ -175,6 +175,7 @@ static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree); static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
static tree tsubst_decl (tree, tree, tsubst_flags_t); static tree tsubst_decl (tree, tree, tsubst_flags_t);
static void perform_typedefs_access_check (tree tmpl, tree targs); static void perform_typedefs_access_check (tree tmpl, tree targs);
static void append_type_to_template_for_access_check_1 (tree, tree, tree);
/* Make the current scope suitable for access checking when we are /* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function processing T. T can be FUNCTION_DECL for instantiated function
...@@ -6941,10 +6942,12 @@ perform_typedefs_access_check (tree tmpl, tree targs) ...@@ -6941,10 +6942,12 @@ perform_typedefs_access_check (tree tmpl, tree targs)
{ {
tree t; tree t;
if (!tmpl || TREE_CODE (tmpl) != TEMPLATE_DECL) if (!tmpl
|| (TREE_CODE (tmpl) != RECORD_TYPE
&& TREE_CODE (tmpl) != FUNCTION_DECL))
return; return;
for (t = MEMBER_TYPES_NEEDING_ACCESS_CHECK (tmpl); t; t = TREE_CHAIN (t)) for (t = get_types_needing_access_check (tmpl); t; t = TREE_CHAIN (t))
{ {
tree type_decl = TREE_PURPOSE (t); tree type_decl = TREE_PURPOSE (t);
tree type_scope = TREE_VALUE (t); tree type_scope = TREE_VALUE (t);
...@@ -6957,7 +6960,8 @@ perform_typedefs_access_check (tree tmpl, tree targs) ...@@ -6957,7 +6960,8 @@ perform_typedefs_access_check (tree tmpl, tree targs)
if (uses_template_parms (type_scope)) if (uses_template_parms (type_scope))
type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE); type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE);
perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl); perform_or_defer_access_check (TYPE_BINFO (type_scope),
type_decl, type_decl);
} }
} }
...@@ -7031,9 +7035,9 @@ instantiate_class_template (tree type) ...@@ -7031,9 +7035,9 @@ instantiate_class_template (tree type)
SET_CLASSTYPE_INTERFACE_UNKNOWN (type); SET_CLASSTYPE_INTERFACE_UNKNOWN (type);
/* Set the input location to the template definition. This is needed /* Set the input location to the most specialized template definition.
if tsubsting causes an error. */ This is needed if tsubsting causes an error. */
typedecl = TYPE_MAIN_DECL (type); typedecl = TYPE_MAIN_DECL (pattern);
input_location = DECL_SOURCE_LOCATION (typedecl); input_location = DECL_SOURCE_LOCATION (typedecl);
TYPE_HAS_USER_CONSTRUCTOR (type) = TYPE_HAS_USER_CONSTRUCTOR (pattern); TYPE_HAS_USER_CONSTRUCTOR (type) = TYPE_HAS_USER_CONSTRUCTOR (pattern);
...@@ -7439,8 +7443,8 @@ instantiate_class_template (tree type) ...@@ -7439,8 +7443,8 @@ instantiate_class_template (tree type)
/* Some typedefs referenced from within the template code need to be access /* Some typedefs referenced from within the template code need to be access
checked at template instantiation time, i.e now. These types were checked at template instantiation time, i.e now. These types were
added to the template at parsing time. Let's get those and perform added to the template at parsing time. Let's get those and perform
the acces checks then. */ the access checks then. */
perform_typedefs_access_check (templ, args); perform_typedefs_access_check (pattern, args);
perform_deferred_access_checks (); perform_deferred_access_checks ();
pop_nested_class (); pop_nested_class ();
pop_from_top_level (); pop_from_top_level ();
...@@ -12163,7 +12167,7 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain) ...@@ -12163,7 +12167,7 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
checked at template instantiation time, i.e now. These types were checked at template instantiation time, i.e now. These types were
added to the template at parsing time. Let's get those and perfom added to the template at parsing time. Let's get those and perfom
the acces checks then. */ the acces checks then. */
perform_typedefs_access_check (tmpl, targ_ptr); perform_typedefs_access_check (DECL_TEMPLATE_RESULT (tmpl), targ_ptr);
perform_deferred_access_checks (); perform_deferred_access_checks ();
pop_access_scope (fndecl); pop_access_scope (fndecl);
pop_deferring_access_checks (); pop_deferring_access_checks ();
...@@ -17267,33 +17271,108 @@ type_uses_auto (tree type) ...@@ -17267,33 +17271,108 @@ type_uses_auto (tree type)
return NULL_TREE; return NULL_TREE;
} }
/* For a given template T, return the list of typedefs referenced
in T for which access check is needed at T instantiation time.
T is either a FUNCTION_DECL or a RECORD_TYPE.
Those typedefs were added to T by the function
append_type_to_template_for_access_check. */
tree
get_types_needing_access_check (tree t)
{
tree ti, result = NULL_TREE;
if (!t || t == error_mark_node)
return t;
if (!(ti = get_template_info (t)))
return NULL_TREE;
if (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == FUNCTION_DECL)
{
if (!TI_TEMPLATE (ti))
return NULL_TREE;
result = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti);
}
return result;
}
/* Append the typedef TYPE_DECL used in template T to a list of typedefs
tied to T. That list of typedefs will be access checked at
T instantiation time.
T is either a FUNCTION_DECL or a RECORD_TYPE.
TYPE_DECL is a TYPE_DECL node representing a typedef.
SCOPE is the scope through which TYPE_DECL is accessed.
This function is a subroutine of
append_type_to_template_for_access_check. */
static void
append_type_to_template_for_access_check_1 (tree t,
tree type_decl,
tree scope)
{
tree ti;
if (!t || t == error_mark_node)
return;
gcc_assert ((TREE_CODE (t) == FUNCTION_DECL
|| TREE_CODE (t) == RECORD_TYPE)
&& type_decl
&& TREE_CODE (type_decl) == TYPE_DECL
&& scope);
if (!(ti = get_template_info (t)))
return;
gcc_assert (TI_TEMPLATE (ti));
TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti) =
tree_cons (type_decl, scope, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti));
}
/* Append TYPE_DECL to the template TEMPL. /* Append TYPE_DECL to the template TEMPL.
TEMPL is either a class type or a FUNCTION_DECL associated TEMPL is either a class type, a FUNCTION_DECL or a a TEMPLATE_DECL.
to a TEMPLATE_DECL.
At TEMPL instanciation time, TYPE_DECL will be checked to see At TEMPL instanciation time, TYPE_DECL will be checked to see
if it can be accessed through SCOPE. */ if it can be accessed through SCOPE.
e.g. consider the following code snippet:
class C
{
typedef int myint;
};
template<class U> struct S
{
C::myint mi;
};
S<char> s;
At S<char> instantiation time, we need to check the access of C::myint
In other words, we need to check the access of the myint typedef through
the C scope. For that purpose, this function will add the myint typedef
and the scope C through which its being accessed to a list of typedefs
tied to the template S. That list will be walked at template instantiation
time and access check performed on each typedefs it contains.
Note that this particular code snippet should yield an error because
myint is private to C. */
void void
append_type_to_template_for_access_check (tree templ, append_type_to_template_for_access_check (tree templ,
tree type_decl, tree type_decl,
tree scope) tree scope)
{ {
tree node, templ_decl; tree node;
gcc_assert (templ
&& get_template_info (templ)
&& TI_TEMPLATE (get_template_info (templ))
&& type_decl
&& (TREE_CODE (type_decl) == TYPE_DECL));
templ_decl = TI_TEMPLATE (get_template_info (templ)); gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL));
gcc_assert (templ_decl);
/* Make sure we don't append the type to the template twice. /* Make sure we don't append the type to the template twice. */
If this appears to be too slow, the for (node = get_types_needing_access_check (templ);
MEMBER_TYPE_NEEDING_ACCESS_CHECK property
of templ should be a hash table instead. */
for (node = MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ_decl);
node; node;
node = TREE_CHAIN (node)) node = TREE_CHAIN (node))
{ {
...@@ -17304,9 +17383,7 @@ append_type_to_template_for_access_check (tree templ, ...@@ -17304,9 +17383,7 @@ append_type_to_template_for_access_check (tree templ,
return; return;
} }
MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ_decl) = append_type_to_template_for_access_check_1 (templ, type_decl, scope);
tree_cons (type_decl, scope,
MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ_decl));
} }
#include "gt-cp-pt.h" #include "gt-cp-pt.h"
2009-05-26 Dodji Seketeli <dodji@redhat.com>
PR c++/40007
* g++.dg/template/typedef18.C: New test.
* g++.dg/template/typedef19.C: Likewise.
* g++.dg/template/typedef20.C: Likewise.
* g++.dg/template/access11.C: Adjust.
2009-05-26 Richard Guenther <rguenther@suse.de> 2009-05-26 Richard Guenther <rguenther@suse.de>
PR testsuite/40247 PR testsuite/40247
......
...@@ -17,7 +17,7 @@ template <> struct X::Y<int> { ...@@ -17,7 +17,7 @@ template <> struct X::Y<int> {
A::X x; // { dg-error "this context" } A::X x; // { dg-error "this context" }
}; };
template <typename T> struct X::Y { // { dg-error "this context" } template <typename T> struct X::Y {
typename T::X x; // { dg-error "this context" } typename T::X x; // { dg-error "this context" }
}; };
......
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/40007
// { dg-do compile }
template<typename T>
struct x
{
protected:
typedef int type;
};
template<typename T>
struct y : public x<T>
{
typename x<T>::type z;
};
template<>
struct y<void> : public x<void>
{
typedef x<void>::type z;
};
template class y<int>;
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/40007
// { dg-do compile }
class A
{
typedef int mytype; // { dg-error "'typedef int A::mytype' is private" }
};
template <class T>
class B : public A
{
};
template<class T>
class B<T*> : public A
{ // { dg-error "within this context" }
mytype mem;
};
B<int*> b;
// Contributed by Dodji Seketeli <dodji@redhat.com>
// Origin PR c++/40007
// { dg-do compile }
class x
{
typedef int privtype; // { dg-error "is private" }
protected:
typedef int type;
};
template<typename T>
struct y : public x
{
typename x::type z;
};
template<typename T>
struct y<T*> : public x
{ // { dg-error "within this context" }
typedef x::type good;
typedef x::privtype bad;
};
template class y<int>;
template class y<int*>;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment