* PR c++/141777 @ 2009-11-16 22:13 Dodji Seketeli 2009-11-17 1:33 ` Jason Merrill 0 siblings, 1 reply; 11+ messages in thread From: Dodji Seketeli @ 2009-11-16 22:13 UTC (permalink / raw) To: gcc-patches; +Cc: jason Hello, In the example of the patch below we forget to perform access check of a typedef declared in a template. check_accessibility_of_qualified_id is the place where we mark template typedefs members in order to check their access at template instantiation time. I thought we should necessarily hit this function at parsing time (through cp_parser_lookup_name), but that was not correct. When the typedef is used through a typename like in the example of the patch, a typename is created directly using cp_parser_make_typename_type from e.g. cp_parser_elaborated_type_specifier and cp_parser_lookup_name is not called. This patch closes the gap by marking template typedefs members used through typename for access check. Tested against trunk on x86_64_unknown_linux_gnu. Dodji commit 21265331cd9714c849a1008c64febf5a239a7ed7 Author: Dodji Seketeli <dodji@redhat.com> Date: Mon Nov 16 22:29:06 2009 +0100 Fix PR c++/14777 gcc/cp/ChangeLog: PR c++/14777 * gcc/cp/semantics.c (add_typedef_to_current_template_for_access_check): Split from ... (check_accessibility_of_qualified_id): ... here. * gcc/cp/cp-tree.h (add_typedef_to_current_template_for_access_check)): Declare. * cp/decl.c (make_typename_type): Use it. gcc/testsuite/ChangeLog: PR c++/14777 * g++.dg/template/typedef22.C: New test. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a71dc73..8c5cd59 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5038,6 +5038,7 @@ extern void emit_associated_thunks (tree); extern void finish_mem_initializers (tree); extern tree check_template_template_default_arg (tree); extern void expand_or_defer_fn (tree); +extern void add_typedef_to_current_template_for_access_check (tree, tree); extern void check_accessibility_of_qualified_id (tree, tree, tree); extern tree finish_qualified_id_expr (tree, tree, bool, bool, bool, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 73bf995..1786f29 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3075,6 +3075,11 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, if (complain & tf_error) perform_or_defer_access_check (TYPE_BINFO (context), t, t); + /* If we are currently parsing a template and if T is a typedef accessed + through CONTEXT then we need to remember and check access of T at + template instantiation time. */ + add_typedef_to_current_template_for_access_check (t, context); + if (want_template) return lookup_template_class (t, TREE_OPERAND (fullname, 1), NULL_TREE, context, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c1df24b..a99b1ea 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1531,6 +1531,34 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) } } +/* If we are currently parsing a template and we encountered a typedef + TYPEDEF_DECL that is being accessed though CONTEXT, this function + adds the typedef to a list tied to the current template. + At tempate instantiatin time, that list is walked and access check + performed for each typedef. */ + +void +add_typedef_to_current_template_for_access_check (tree typedef_decl, + tree context) +{ + tree template_info = NULL; + tree cs = current_scope (); + + if (!is_typedef_decl (typedef_decl) + || !context + || !CLASS_TYPE_P (context) + || !cs) + return; + + if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL) + template_info = get_template_info (cs); + + if (template_info + && TI_TEMPLATE (template_info) + && !currently_open_class (context)) + append_type_to_template_for_access_check (cs, typedef_decl, context); +} + /* DECL was the declaration to which a qualified-id resolved. Issue an error message if it is not accessible. If OBJECT_TYPE is non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the @@ -1549,27 +1577,10 @@ check_accessibility_of_qualified_id (tree decl, add it to a list tied to the template. At template instantiation time, that list will be walked and access check performed. */ - if (is_typedef_decl (decl)) - { - /* This the scope through which type_decl is accessed. - It will be useful information later to do access check for - type_decl usage. */ - tree scope = nested_name_specifier - ? nested_name_specifier - : DECL_CONTEXT (decl); - tree templ_info = NULL; - tree cs = current_scope (); - - if (cs && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)) - templ_info = get_template_info (cs); - - if (templ_info - && TI_TEMPLATE (templ_info) - && scope - && CLASS_TYPE_P (scope) - && !currently_open_class (scope)) - append_type_to_template_for_access_check (current_scope (), decl, scope); - } + add_typedef_to_current_template_for_access_check (decl, + nested_name_specifier + ? nested_name_specifier + : DECL_CONTEXT (decl)); /* If we're not checking, return immediately. */ if (deferred_access_no_check) diff --git a/gcc/testsuite/g++.dg/template/typedef22.C b/gcc/testsuite/g++.dg/template/typedef22.C new file mode 100644 index 0000000..8c6edc3 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typedef22.C @@ -0,0 +1,18 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin: PR c++/14777 +// { dg-do compile } + +template <typename T> +struct B +{ +protected: + typedef int M; // { dg-error "protected" } +}; + +template <typename T> +struct A : B<T> { // { dg-error "context" } + typedef typename B<char>::M N; + A (int = N ()); +}; + +A<int> a = A<int> (); ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-16 22:13 PR c++/141777 Dodji Seketeli @ 2009-11-17 1:33 ` Jason Merrill 2009-11-17 13:23 ` Dodji Seketeli 0 siblings, 1 reply; 11+ messages in thread From: Jason Merrill @ 2009-11-17 1:33 UTC (permalink / raw) To: Dodji Seketeli; +Cc: gcc-patches Looks good, but could we also store the source location of the access so that the error message has the right line/column? Jason ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-17 1:33 ` Jason Merrill @ 2009-11-17 13:23 ` Dodji Seketeli 2009-11-17 20:48 ` Jason Merrill 0 siblings, 1 reply; 11+ messages in thread From: Dodji Seketeli @ 2009-11-17 13:23 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches On Mon, Nov 16, 2009 at 08:09:37PM -0500, Jason Merrill wrote: > Looks good, but could we also store the source location of the access so > that the error message has the right line/column? Sure. In the updated patch below, I did wrap the typedef decl in a dummy expr decl which sole purpose is to carry the source location of the typedef usage point. That seems a bit heavy to me, but I couldn't find a more direct (and elegant) way to store the location of the usage point as well as the location of the declaration point of the typedef. Any idea of a better way? Incidentally I had to adjust a couple of other tests now these error messages are reporting a more accurate line. FWIW I tested this on x86_64-unknown-linux-gnu. Thanks. commit 4b8f36e61ab35672bc17729bc632d0d43b74ada6 Author: Dodji Seketeli <dodji@redhat.com> Date: Mon Nov 16 22:29:06 2009 +0100 Fix PR c++/14777 gcc/cp/ChangeLog: PR c++/14777 * gcc/cp/semantics.c (add_typedef_to_current_template_for_access_check): Split from ... (check_accessibility_of_qualified_id): ... here. * gcc/cp/cp-tree.h (add_typedef_to_current_template_for_access_check)): Declare. (append_type_to_template_for_access_check): Add a location parameter. * cp/decl.c (make_typename_type): Use it. * pt.c (append_type_to_template_for_access_check_1): Record the location of the usage point of the typedef. (append_type_to_template_for_access_check): Add new location parameter. Pass it to append_type_to_template_for_access_check_1. (perform_typedefs_access_check): Temporarily set input_location to the usage point of the typedef we are checking access for. gcc/testsuite/ChangeLog: PR c++/14777 * g++.dg/template/typedef13.C: Adjust. * g++.dg/template/typedef19.C: Adjust. * g++.dg/template/typedef20.C: Adjust. * g++.dg/template/typedef22.C: New test. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a71dc73..6753587 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4775,7 +4775,8 @@ extern tree check_explicit_specialization (tree, tree, int, int); extern tree make_auto (void); extern tree do_auto_deduction (tree, tree, tree); extern tree type_uses_auto (tree); -extern void append_type_to_template_for_access_check (tree, tree, tree); +extern void append_type_to_template_for_access_check (tree, tree, tree, + location_t); extern tree splice_late_return_type (tree, tree); extern bool is_auto (const_tree); extern tree process_template_parm (tree, location_t, tree, @@ -5038,6 +5039,8 @@ extern void emit_associated_thunks (tree); extern void finish_mem_initializers (tree); extern tree check_template_template_default_arg (tree); extern void expand_or_defer_fn (tree); +extern void add_typedef_to_current_template_for_access_check (tree, tree, + location_t); extern void check_accessibility_of_qualified_id (tree, tree, tree); extern tree finish_qualified_id_expr (tree, tree, bool, bool, bool, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 73bf995..69be767 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3075,6 +3075,11 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, if (complain & tf_error) perform_or_defer_access_check (TYPE_BINFO (context), t, t); + /* If we are currently parsing a template and if T is a typedef accessed + through CONTEXT then we need to remember and check access of T at + template instantiation time. */ + add_typedef_to_current_template_for_access_check (t, context, input_location); + if (want_template) return lookup_template_class (t, TREE_OPERAND (fullname, 1), NULL_TREE, context, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b7d72c1..34ec331 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -189,7 +189,8 @@ static tree tsubst_copy (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 void perform_typedefs_access_check (tree tmpl, tree targs); -static void append_type_to_template_for_access_check_1 (tree, tree, tree); +static void append_type_to_template_for_access_check_1 (tree, tree, tree, + location_t); static hashval_t iterative_hash_template_arg (tree arg, hashval_t val); static tree listify (tree); static tree listify_autos (tree, tree); @@ -7341,6 +7342,7 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, static void perform_typedefs_access_check (tree tmpl, tree targs) { + location_t saved_location; tree t; if (!tmpl @@ -7348,11 +7350,24 @@ perform_typedefs_access_check (tree tmpl, tree targs) && TREE_CODE (tmpl) != FUNCTION_DECL)) return; + saved_location = input_location; for (t = get_types_needing_access_check (tmpl); t; t = TREE_CHAIN (t)) { - tree type_decl = TREE_PURPOSE (t); + tree type_decl; + tree dummy_expr = TREE_PURPOSE (t); tree type_scope = TREE_VALUE (t); + /* dummy_expr is a NOP_EXPR that wraps a TYPE_DECL representing + the typedef we want to check access for. + EXPR_LOCATION (dummy_expr) carries the source location of the + use of the typedef. + Read append_type_to_template_for_access_check_1 for details. */ + gcc_assert (dummy_expr + && TREE_CODE (dummy_expr) == NOP_EXPR + && TREE_TYPE (dummy_expr) == unknown_type_node); + + type_decl = TREE_OPERAND (dummy_expr, 0); + if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope)) continue; @@ -7361,9 +7376,13 @@ perform_typedefs_access_check (tree tmpl, tree targs) if (uses_template_parms (type_scope)) type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE); + /* Make access check error messages point to the location + of the use of the typedef. */ + input_location = EXPR_LOCATION (dummy_expr); perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl); } + input_location = saved_location; } tree @@ -18075,6 +18094,7 @@ get_types_needing_access_check (tree t) 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. + LOCATION is the location of the usage point of TYPE_DECL. This function is a subroutine of append_type_to_template_for_access_check. */ @@ -18082,9 +18102,10 @@ get_types_needing_access_check (tree t) static void append_type_to_template_for_access_check_1 (tree t, tree type_decl, - tree scope) + tree scope, + location_t location) { - tree ti; + tree ti, dummy_expr; if (!t || t == error_mark_node) return; @@ -18100,14 +18121,20 @@ append_type_to_template_for_access_check_1 (tree t, gcc_assert (TI_TEMPLATE (ti)); + /* Wrap typedef TYPE_DECL into a dummy NOP_EXPR which sole purpose is to + carry the source location of the use of the typedef. */ + dummy_expr = build1 (NOP_EXPR, unknown_type_node, type_decl); + SET_EXPR_LOCATION (dummy_expr, location); + TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti) = - tree_cons (type_decl, scope, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti)); + tree_cons (dummy_expr, scope, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti)); } /* Append TYPE_DECL to the template TEMPL. TEMPL is either a class type, a FUNCTION_DECL or a a TEMPLATE_DECL. At TEMPL instanciation time, TYPE_DECL will be checked to see if it can be accessed through SCOPE. + LOCATION is the location of the usage point of TYPE_DECL. e.g. consider the following code snippet: @@ -18118,7 +18145,7 @@ append_type_to_template_for_access_check_1 (tree t, template<class U> struct S { - C::myint mi; + C::myint mi; // <-- usage point of the typedef C::myint }; S<char> s; @@ -18135,7 +18162,8 @@ append_type_to_template_for_access_check_1 (tree t, void append_type_to_template_for_access_check (tree templ, tree type_decl, - tree scope) + tree scope, + location_t location) { tree node; @@ -18153,7 +18181,8 @@ append_type_to_template_for_access_check (tree templ, return; } - append_type_to_template_for_access_check_1 (templ, type_decl, scope); + append_type_to_template_for_access_check_1 (templ, type_decl, + scope, location); } /* Set up the hash tables for template instantiations. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c1df24b..c83b796 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1531,6 +1531,37 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) } } +/* If we are currently parsing a template and we encountered a typedef + TYPEDEF_DECL that is being accessed though CONTEXT, this function + adds the typedef to a list tied to the current template. + At tempate instantiatin time, that list is walked and access check + performed for each typedef. + LOCATION is the location of the usage point of TYPEDEF_DECL. */ + +void +add_typedef_to_current_template_for_access_check (tree typedef_decl, + tree context, + location_t location) +{ + tree template_info = NULL; + tree cs = current_scope (); + + if (!is_typedef_decl (typedef_decl) + || !context + || !CLASS_TYPE_P (context) + || !cs) + return; + + if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL) + template_info = get_template_info (cs); + + if (template_info + && TI_TEMPLATE (template_info) + && !currently_open_class (context)) + append_type_to_template_for_access_check (cs, typedef_decl, + context, location); +} + /* DECL was the declaration to which a qualified-id resolved. Issue an error message if it is not accessible. If OBJECT_TYPE is non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the @@ -1549,27 +1580,11 @@ check_accessibility_of_qualified_id (tree decl, add it to a list tied to the template. At template instantiation time, that list will be walked and access check performed. */ - if (is_typedef_decl (decl)) - { - /* This the scope through which type_decl is accessed. - It will be useful information later to do access check for - type_decl usage. */ - tree scope = nested_name_specifier - ? nested_name_specifier - : DECL_CONTEXT (decl); - tree templ_info = NULL; - tree cs = current_scope (); - - if (cs && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)) - templ_info = get_template_info (cs); - - if (templ_info - && TI_TEMPLATE (templ_info) - && scope - && CLASS_TYPE_P (scope) - && !currently_open_class (scope)) - append_type_to_template_for_access_check (current_scope (), decl, scope); - } + add_typedef_to_current_template_for_access_check (decl, + nested_name_specifier + ? nested_name_specifier + : DECL_CONTEXT (decl), + input_location); /* If we're not checking, return immediately. */ if (deferred_access_no_check) diff --git a/gcc/testsuite/g++.dg/template/typedef13.C b/gcc/testsuite/g++.dg/template/typedef13.C index aa8bb32..a22e1cb 100644 --- a/gcc/testsuite/g++.dg/template/typedef13.C +++ b/gcc/testsuite/g++.dg/template/typedef13.C @@ -8,8 +8,8 @@ class A }; template <class T> class B : public A -{ // { dg-error "within this context" } - mytype mem; +{ + mytype mem; // { dg-error "within this context" } }; B<int> b; // { dg-message "instantiated from here" } diff --git a/gcc/testsuite/g++.dg/template/typedef19.C b/gcc/testsuite/g++.dg/template/typedef19.C index f576d48..2fac20e 100644 --- a/gcc/testsuite/g++.dg/template/typedef19.C +++ b/gcc/testsuite/g++.dg/template/typedef19.C @@ -14,8 +14,8 @@ class B : public A template<class T> class B<T*> : public A -{ // { dg-error "within this context" } - mytype mem; +{ + mytype mem; // { dg-error "within this context" } }; B<int*> b; diff --git a/gcc/testsuite/g++.dg/template/typedef20.C b/gcc/testsuite/g++.dg/template/typedef20.C index a5cbdeb..c768ce0 100644 --- a/gcc/testsuite/g++.dg/template/typedef20.C +++ b/gcc/testsuite/g++.dg/template/typedef20.C @@ -18,9 +18,9 @@ struct y : public x template<typename T> struct y<T*> : public x -{ // { dg-error "within this context" } +{ typedef x::type good; - typedef x::privtype bad; + typedef x::privtype bad; // { dg-error "within this context" } }; template class y<int>; diff --git a/gcc/testsuite/g++.dg/template/typedef22.C b/gcc/testsuite/g++.dg/template/typedef22.C new file mode 100644 index 0000000..e3ecfcb --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typedef22.C @@ -0,0 +1,18 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin: PR c++/14777 +// { dg-do compile } + +template <typename T> +struct B +{ +protected: + typedef int M; // { dg-error "protected" } +}; + +template <typename T> +struct A : B<T> { + typedef typename B<char>::M N; // { dg-error "context" } + A (int = N ()); +}; + +A<int> a = A<int> (); Dodji ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-17 13:23 ` Dodji Seketeli @ 2009-11-17 20:48 ` Jason Merrill 2009-11-19 14:27 ` Dodji Seketeli 0 siblings, 1 reply; 11+ messages in thread From: Jason Merrill @ 2009-11-17 20:48 UTC (permalink / raw) To: Dodji Seketeli; +Cc: gcc-patches On 11/17/2009 08:04 AM, Dodji Seketeli wrote: > In the updated patch below, I did wrap the typedef decl in a dummy expr > decl which sole purpose is to carry the source location of the typedef > usage point. That seems a bit heavy to me, but I couldn't find a more > direct (and elegant) way to store the location of the usage point as well as > the location of the declaration point of the typedef. Any idea of a better way? Hmm...you could make DECL_ACCESS look through templates and take over lang_decl_min.u2 for TEMPLATE_DECL and use a custom VEC data structure. Jason ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-17 20:48 ` Jason Merrill @ 2009-11-19 14:27 ` Dodji Seketeli 2009-11-19 16:13 ` Jason Merrill 0 siblings, 1 reply; 11+ messages in thread From: Dodji Seketeli @ 2009-11-19 14:27 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches On Tue, Nov 17, 2009 at 03:41:16PM -0500, Jason Merrill wrote: > Hmm...you could make DECL_ACCESS look through templates and take over > lang_decl_min.u2 for TEMPLATE_DECL and use a custom VEC data structure. As you and I discussed this on IRC later, it's not appropriate to use the partial specializations don't have a TEMPLACE_DECL. So using the DECL_ACCESS of TEMPLATE_DECL to store the typedef access checking bits would not work for partial specializations. So I went ahead and tried the second approach we discussed on IRC, which is to create a new kind of tree node to store template_info bits, instead of the TREE_LIST it uses today. That new tree node is a TEMPLATE_INFO node. It contains the template decl, the template arguments, and a list of (typedef/context/use location) triplets that is needed (at template instantiation time) to check the access of member typedefs used in the template pattern. I augmented the patch to switch to using those new TEMPLATE_INFO nodes. Bootstrapped (incluing java) and tested against trunk on x86_64-unknown-linux-gnu. Dodji commit 9d0bcb9b6db72d5654c97d41f4a57699474606e2 Author: Dodji Seketeli <dodji@redhat.com> Date: Mon Nov 16 22:29:06 2009 +0100 Fix PR c++/14777 gcc/cp/ChangeLog: PR c++/14777 * cp-tree.def <TEMPLATE_INFO>: Declare new kind of tree node. * cp-tree.h (struct tree_template_info, struct qualified_typedef_usage_s, struct template_info_s): New. (cp_tree_node_structure_enum): add TS_CP_TEMPLATE_INFO. (union lang_tree_node): Add template_info. (TI_TEMPLATE, TI_ARGS, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING): Adjust. (build_template_info): Declare. (get_types_needing_access_check): Adjust return type. (add_typedef_to_current_template_for_access_check): Declare. * cp-objcp-common.c (cp_tree_size): Handle TEMPLATE_INFO. * semantics.c (add_typedef_to_current_template_for_access_check): Split from ... (check_accessibility_of_qualified_id): ... here. * decl.c (make_typename_type): Use it. * pt.c (build_template_info): Define. (check_explicit_specialization, find_parameter_packs_r, push_template_decl_real, lookup_template_class, for_each_template_parm_r, tsubst_decl, tsubst): Use build_template_info. (get_types_needing_access_check): Adjust return type. (append_type_to_template_for_access_check_1): Record the location of the usage point of the typedef. Adjust to TEMPLATE_INFO. (append_type_to_template_for_access_check): Add new location parameter. Pass it to append_type_to_template_for_access_check_1. Adjust to TEMPLATE_INFO. (perform_typedefs_access_check): Temporarily set input_location to the usage point of the typedef we are checking access for. Adjust to new TEMPLATE_INFO tree node. * tree.c (bind_template_template_parm): Use build_template_info. * call.c (add_template_candidate_real): Likewise. * decl.c (grokfndecl): Likewise. (cp_tree_node_structure): Handle TEMPLATE_INFO. gcc/testsuite/ChangeLog: PR c++/14777 * g++.dg/template/typedef13.C: Adjust. * g++.dg/template/typedef19.C: Adjust. * g++.dg/template/typedef20.C: Adjust. * g++.dg/template/typedef22.C: New test. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e4a6bca..137b4bb 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2579,7 +2579,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, for this will point at template <class T> template <> S<T>::f(int), so that we can find the definition. For the purposes of overload resolution, however, we want the original TMPL. */ - cand->template_decl = tree_cons (tmpl, targs, NULL_TREE); + cand->template_decl = build_template_info (tmpl, targs); else cand->template_decl = DECL_TEMPLATE_INFO (fn); diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index da6f829..f06ad5b 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -140,6 +140,8 @@ cp_tree_size (enum tree_code code) case LAMBDA_EXPR: return sizeof (struct tree_lambda_expr); + case TEMPLATE_INFO: return sizeof (struct tree_template_info); + default: gcc_unreachable (); } diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 28ecc5b..c71f94c 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -439,6 +439,16 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0) DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction. */ DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0) +/* Used to represent the template information stored by template + specializations. + The accessors are: + TI_TEMPLATE the template declaration associated to the specialization + TI_ARGS the arguments of the template specialization + TI_TYPEDEFS_NEEDING_ACCESS_CHECKING the vector of typedefs used in + the pattern of the template for which access check is needed at template + instantiation time. */ +DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0) + /* Local variables: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a71dc73..a81f115 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -600,6 +600,40 @@ struct GTY (()) tree_lambda_expr int discriminator; }; +/* A (typedef,context,usage location) triplet. + It represents a typedef used through a + context at a given source location. + e.g. + struct foo { + typedef int myint; + }; + + struct bar { + foo::myint v; // #1<-- this location. + }; + + In bar, the triplet will be (myint, foo, #1). + */ +struct GTY(()) qualified_typedef_usage_s { + tree typedef_decl; + tree context; + location_t locus; +}; +typedef struct qualified_typedef_usage_s qualified_typedef_usage_t; +DEF_VEC_O (qualified_typedef_usage_t); +DEF_VEC_ALLOC_O (qualified_typedef_usage_t,gc); + +struct GTY(()) template_info_s { + tree template_decl; + tree template_args; + VEC(qualified_typedef_usage_t,gc) *typedefs_needing_access_checking; +}; + +struct GTY(()) tree_template_info { + struct tree_common common; + struct template_info_s content; +}; + enum cp_tree_node_structure_enum { TS_CP_GENERIC, TS_CP_IDENTIFIER, @@ -614,6 +648,7 @@ enum cp_tree_node_structure_enum { TS_CP_ARGUMENT_PACK_SELECT, TS_CP_TRAIT_EXPR, TS_CP_LAMBDA_EXPR, + TS_CP_TEMPLATE_INFO, LAST_TS_CP_ENUM }; @@ -636,6 +671,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"), trait_expression; struct tree_lambda_expr GTY ((tag ("TS_CP_LAMBDA_EXPR"))) lambda_expression; + struct tree_template_info GTY ((tag ("TS_CP_TEMPLATE_INFO"))) + template_info; }; \f @@ -2408,12 +2445,20 @@ extern void decl_shadowed_for_var_insert (tree, tree); ? (ENUM_TEMPLATE_INFO (NODE) = (VAL)) \ : (CLASSTYPE_TEMPLATE_INFO (NODE) = (VAL))) -#define TI_TEMPLATE(NODE) (TREE_PURPOSE (NODE)) -#define TI_ARGS(NODE) (TREE_VALUE (NODE)) +#define TI_TEMPLATE(NODE) \ + ((struct tree_template_info*)TEMPLATE_INFO_CHECK \ + (NODE))->content.template_decl + +#define TI_ARGS(NODE) \ + ((struct tree_template_info*)TEMPLATE_INFO_CHECK \ + (NODE))->content.template_args + #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)) +#define TI_TYPEDEFS_NEEDING_ACCESS_CHECKING(NODE) \ + ((struct tree_template_info*)TEMPLATE_INFO_CHECK \ + (NODE))->content.typedefs_needing_access_checking /* We use TREE_VECs to hold template arguments. If there is only one level of template arguments, then the TREE_VEC contains the @@ -4775,7 +4820,8 @@ extern tree check_explicit_specialization (tree, tree, int, int); extern tree make_auto (void); extern tree do_auto_deduction (tree, tree, tree); extern tree type_uses_auto (tree); -extern void append_type_to_template_for_access_check (tree, tree, tree); +extern void append_type_to_template_for_access_check (tree, tree, tree, + location_t); extern tree splice_late_return_type (tree, tree); extern bool is_auto (const_tree); extern tree process_template_parm (tree, location_t, tree, @@ -4809,8 +4855,9 @@ extern bool function_parameter_pack_p (const_tree); extern bool function_parameter_expanded_from_pack_p (tree, tree); extern tree make_pack_expansion (tree); extern bool check_for_bare_parameter_packs (tree); +extern tree build_template_info (tree, tree); extern tree get_template_info (const_tree); -extern tree get_types_needing_access_check (tree); +extern VEC(qualified_typedef_usage_t,gc)* get_types_needing_access_check (tree); extern int template_class_depth (tree); extern int is_specialization_of (tree, tree); extern bool is_specialization_of_friend (tree, tree); @@ -5038,6 +5085,8 @@ extern void emit_associated_thunks (tree); extern void finish_mem_initializers (tree); extern tree check_template_template_default_arg (tree); extern void expand_or_defer_fn (tree); +extern void add_typedef_to_current_template_for_access_check (tree, tree, + location_t); extern void check_accessibility_of_qualified_id (tree, tree, tree); extern tree finish_qualified_id_expr (tree, tree, bool, bool, bool, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 73bf995..73a836f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3075,6 +3075,11 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, if (complain & tf_error) perform_or_defer_access_check (TYPE_BINFO (context), t, t); + /* If we are currently parsing a template and if T is a typedef accessed + through CONTEXT then we need to remember and check access of T at + template instantiation time. */ + add_typedef_to_current_template_for_access_check (t, context, input_location); + if (want_template) return lookup_template_class (t, TREE_OPERAND (fullname, 1), NULL_TREE, context, @@ -6696,7 +6701,7 @@ grokfndecl (tree ctype, } gcc_assert (TREE_CODE (fns) == IDENTIFIER_NODE || TREE_CODE (fns) == OVERLOAD); - DECL_TEMPLATE_INFO (decl) = tree_cons (fns, args, NULL_TREE); + DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args); for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t) @@ -12838,6 +12843,7 @@ cp_tree_node_structure (union lang_tree_node * t) case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT; case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR; + case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO; default: return TS_CP_GENERIC; } } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b7d72c1..e54c32e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -189,7 +189,8 @@ static tree tsubst_copy (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 void perform_typedefs_access_check (tree tmpl, tree targs); -static void append_type_to_template_for_access_check_1 (tree, tree, tree); +static void append_type_to_template_for_access_check_1 (tree, tree, tree, + location_t); static hashval_t iterative_hash_template_arg (tree arg, hashval_t val); static tree listify (tree); static tree listify_autos (tree, tree); @@ -286,6 +287,18 @@ finish_member_template_decl (tree decl) return error_mark_node; } +/* Create a template info node. */ + +tree +build_template_info (tree template_decl, tree template_args) +{ + tree result = make_node (TEMPLATE_INFO); + TREE_TYPE (result) = unknown_type_node; + TI_TEMPLATE (result) = template_decl; + TI_ARGS (result) = template_args; + return result; +} + /* Return the template info node corresponding to T, whatever T is. */ tree @@ -2492,7 +2505,7 @@ check_explicit_specialization (tree declarator, } /* Set up the DECL_TEMPLATE_INFO for DECL. */ - DECL_TEMPLATE_INFO (decl) = tree_cons (tmpl, targs, NULL_TREE); + DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs); /* Inherit default function arguments from the template DECL is specializing. */ @@ -2900,7 +2913,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) case UNION_TYPE: case ENUMERAL_TYPE: if (TYPE_TEMPLATE_INFO (t)) - cp_walk_tree (&TREE_VALUE (TYPE_TEMPLATE_INFO (t)), + cp_walk_tree (&TI_ARGS (TYPE_TEMPLATE_INFO (t)), &find_parameter_packs_r, ppd, ppd->visited); *walk_subtrees = 0; @@ -4352,7 +4365,7 @@ push_template_decl_real (tree decl, bool is_friend) DECL_TI_TEMPLATE (decl) = new_tmpl; SET_DECL_TEMPLATE_SPECIALIZATION (new_tmpl); DECL_TEMPLATE_INFO (new_tmpl) - = tree_cons (tmpl, args, NULL_TREE); + = build_template_info (tmpl, args); register_specialization (new_tmpl, most_general_template (tmpl), @@ -4471,7 +4484,7 @@ template arguments to %qD do not match original template %qD", if (DECL_TEMPLATE_INFO (tmpl)) args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args); - info = tree_cons (tmpl, args, NULL_TREE); + info = build_template_info (tmpl, args); if (DECL_IMPLICIT_TYPEDEF_P (decl)) SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info); @@ -6409,7 +6422,7 @@ lookup_template_class (tree d1, found = CLASSTYPE_TI_TEMPLATE (found); } - SET_TYPE_TEMPLATE_INFO (t, tree_cons (found, arglist, NULL_TREE)); + SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist)); elt.spec = t; slot = (spec_entry **) htab_find_slot_with_hash (type_specializations, @@ -6485,7 +6498,7 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) case ENUMERAL_TYPE: if (!TYPE_TEMPLATE_INFO (t)) *walk_subtrees = 0; - else if (for_each_template_parm (TREE_VALUE (TYPE_TEMPLATE_INFO (t)), + else if (for_each_template_parm (TI_ARGS (TYPE_TEMPLATE_INFO (t)), fn, data, pfd->visited, pfd->include_nondeduced_p)) return error_mark_node; @@ -7341,17 +7354,24 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, static void perform_typedefs_access_check (tree tmpl, tree targs) { - tree t; + location_t saved_location; + int i; + qualified_typedef_usage_t *iter; if (!tmpl || (!CLASS_TYPE_P (tmpl) && TREE_CODE (tmpl) != FUNCTION_DECL)) return; - for (t = get_types_needing_access_check (tmpl); t; t = TREE_CHAIN (t)) + saved_location = input_location; + for (i = 0; + VEC_iterate (qualified_typedef_usage_t, + get_types_needing_access_check (tmpl), + i, iter); + ++i) { - tree type_decl = TREE_PURPOSE (t); - tree type_scope = TREE_VALUE (t); + tree type_decl = iter->typedef_decl; + tree type_scope = iter->context; if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope)) continue; @@ -7361,9 +7381,13 @@ perform_typedefs_access_check (tree tmpl, tree targs) if (uses_template_parms (type_scope)) type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE); + /* Make access check error messages point to the location + of the use of the typedef. */ + input_location = iter->locus; perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl); } + input_location = saved_location; } tree @@ -8615,7 +8639,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) gcc_assert (DECL_LANG_SPECIFIC (r) != 0); TREE_CHAIN (r) = NULL_TREE; - DECL_TEMPLATE_INFO (r) = build_tree_list (t, args); + DECL_TEMPLATE_INFO (r) = build_template_info (t, args); if (TREE_CODE (decl) == TYPE_DECL) { @@ -8844,7 +8868,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (gen_tmpl) { DECL_TEMPLATE_INFO (r) - = tree_cons (gen_tmpl, argvec, NULL_TREE); + = build_template_info (gen_tmpl, argvec); SET_DECL_IMPLICIT_INSTANTIATION (r); register_specialization (r, gen_tmpl, argvec, false, hash); @@ -9258,7 +9282,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_EXTERNAL (r) = 1; register_specialization (r, gen_tmpl, argvec, false, hash); - DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE); + DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec); SET_DECL_IMPLICIT_INSTANTIATION (r); } else if (cp_unevaluated_operand) @@ -9867,7 +9891,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (r) - = tree_cons (TYPE_TI_TEMPLATE (t), argvec, NULL_TREE); + = build_template_info (TYPE_TI_TEMPLATE (t), argvec); } } break; @@ -18040,28 +18064,29 @@ type_uses_auto (tree type) return NULL_TREE; } -/* For a given template T, return the list of typedefs referenced +/* For a given template T, return the vector 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 +VEC(qualified_typedef_usage_t,gc)* get_types_needing_access_check (tree t) { - tree ti, result = NULL_TREE; + tree ti; + VEC(qualified_typedef_usage_t,gc) *result = NULL; if (!t || t == error_mark_node) - return t; + return NULL; if (!(ti = get_template_info (t))) - return NULL_TREE; + return NULL; if (CLASS_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL) { if (!TI_TEMPLATE (ti)) - return NULL_TREE; + return NULL; result = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti); } @@ -18075,6 +18100,7 @@ get_types_needing_access_check (tree t) 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. + LOCATION is the location of the usage point of TYPE_DECL. This function is a subroutine of append_type_to_template_for_access_check. */ @@ -18082,8 +18108,10 @@ get_types_needing_access_check (tree t) static void append_type_to_template_for_access_check_1 (tree t, tree type_decl, - tree scope) + tree scope, + location_t location) { + qualified_typedef_usage_t typedef_usage; tree ti; if (!t || t == error_mark_node) @@ -18100,14 +18128,20 @@ append_type_to_template_for_access_check_1 (tree t, gcc_assert (TI_TEMPLATE (ti)); - TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti) = - tree_cons (type_decl, scope, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti)); + typedef_usage.typedef_decl = type_decl; + typedef_usage.context = scope; + typedef_usage.locus = location; + + VEC_safe_push (qualified_typedef_usage_t, gc, + TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), + &typedef_usage); } /* Append TYPE_DECL to the template TEMPL. TEMPL is either a class type, a FUNCTION_DECL or a a TEMPLATE_DECL. At TEMPL instanciation time, TYPE_DECL will be checked to see if it can be accessed through SCOPE. + LOCATION is the location of the usage point of TYPE_DECL. e.g. consider the following code snippet: @@ -18118,7 +18152,7 @@ append_type_to_template_for_access_check_1 (tree t, template<class U> struct S { - C::myint mi; + C::myint mi; // <-- usage point of the typedef C::myint }; S<char> s; @@ -18135,25 +18169,25 @@ append_type_to_template_for_access_check_1 (tree t, void append_type_to_template_for_access_check (tree templ, tree type_decl, - tree scope) + tree scope, + location_t location) { - tree node; + qualified_typedef_usage_t *iter; + int i; gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL)); /* Make sure we don't append the type to the template twice. */ - for (node = get_types_needing_access_check (templ); - node; - node = TREE_CHAIN (node)) - { - tree decl = TREE_PURPOSE (node); - tree type_scope = TREE_VALUE (node); - - if (decl == type_decl && type_scope == scope) - return; - } + for (i = 0; + VEC_iterate (qualified_typedef_usage_t, + get_types_needing_access_check (templ), + i, iter); + ++i) + if (iter->typedef_decl == type_decl && scope == iter->context) + return; - append_type_to_template_for_access_check_1 (templ, type_decl, scope); + append_type_to_template_for_access_check_1 (templ, type_decl, + scope, location); } /* Set up the hash tables for template instantiations. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c1df24b..c83b796 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1531,6 +1531,37 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) } } +/* If we are currently parsing a template and we encountered a typedef + TYPEDEF_DECL that is being accessed though CONTEXT, this function + adds the typedef to a list tied to the current template. + At tempate instantiatin time, that list is walked and access check + performed for each typedef. + LOCATION is the location of the usage point of TYPEDEF_DECL. */ + +void +add_typedef_to_current_template_for_access_check (tree typedef_decl, + tree context, + location_t location) +{ + tree template_info = NULL; + tree cs = current_scope (); + + if (!is_typedef_decl (typedef_decl) + || !context + || !CLASS_TYPE_P (context) + || !cs) + return; + + if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL) + template_info = get_template_info (cs); + + if (template_info + && TI_TEMPLATE (template_info) + && !currently_open_class (context)) + append_type_to_template_for_access_check (cs, typedef_decl, + context, location); +} + /* DECL was the declaration to which a qualified-id resolved. Issue an error message if it is not accessible. If OBJECT_TYPE is non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the @@ -1549,27 +1580,11 @@ check_accessibility_of_qualified_id (tree decl, add it to a list tied to the template. At template instantiation time, that list will be walked and access check performed. */ - if (is_typedef_decl (decl)) - { - /* This the scope through which type_decl is accessed. - It will be useful information later to do access check for - type_decl usage. */ - tree scope = nested_name_specifier - ? nested_name_specifier - : DECL_CONTEXT (decl); - tree templ_info = NULL; - tree cs = current_scope (); - - if (cs && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)) - templ_info = get_template_info (cs); - - if (templ_info - && TI_TEMPLATE (templ_info) - && scope - && CLASS_TYPE_P (scope) - && !currently_open_class (scope)) - append_type_to_template_for_access_check (current_scope (), decl, scope); - } + add_typedef_to_current_template_for_access_check (decl, + nested_name_specifier + ? nested_name_specifier + : DECL_CONTEXT (decl), + input_location); /* If we're not checking, return immediately. */ if (deferred_access_no_check) diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index f9e1cd7..d431b31 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1490,8 +1490,7 @@ bind_template_template_parm (tree t, tree newargs) TEMPLATE_TYPE_PARM_INDEX (t2) = copy_node (TEMPLATE_TYPE_PARM_INDEX (t)); TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (t2)) = decl; TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2) - = tree_cons (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), - newargs, NULL_TREE); + = build_template_info (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), newargs); TREE_TYPE (decl) = t2; TYPE_NAME (t2) = decl; diff --git a/gcc/testsuite/g++.dg/template/typedef13.C b/gcc/testsuite/g++.dg/template/typedef13.C index aa8bb32..a22e1cb 100644 --- a/gcc/testsuite/g++.dg/template/typedef13.C +++ b/gcc/testsuite/g++.dg/template/typedef13.C @@ -8,8 +8,8 @@ class A }; template <class T> class B : public A -{ // { dg-error "within this context" } - mytype mem; +{ + mytype mem; // { dg-error "within this context" } }; B<int> b; // { dg-message "instantiated from here" } diff --git a/gcc/testsuite/g++.dg/template/typedef19.C b/gcc/testsuite/g++.dg/template/typedef19.C index f576d48..2fac20e 100644 --- a/gcc/testsuite/g++.dg/template/typedef19.C +++ b/gcc/testsuite/g++.dg/template/typedef19.C @@ -14,8 +14,8 @@ class B : public A template<class T> class B<T*> : public A -{ // { dg-error "within this context" } - mytype mem; +{ + mytype mem; // { dg-error "within this context" } }; B<int*> b; diff --git a/gcc/testsuite/g++.dg/template/typedef20.C b/gcc/testsuite/g++.dg/template/typedef20.C index a5cbdeb..c768ce0 100644 --- a/gcc/testsuite/g++.dg/template/typedef20.C +++ b/gcc/testsuite/g++.dg/template/typedef20.C @@ -18,9 +18,9 @@ struct y : public x template<typename T> struct y<T*> : public x -{ // { dg-error "within this context" } +{ typedef x::type good; - typedef x::privtype bad; + typedef x::privtype bad; // { dg-error "within this context" } }; template class y<int>; diff --git a/gcc/testsuite/g++.dg/template/typedef22.C b/gcc/testsuite/g++.dg/template/typedef22.C new file mode 100644 index 0000000..e3ecfcb --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typedef22.C @@ -0,0 +1,18 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin: PR c++/14777 +// { dg-do compile } + +template <typename T> +struct B +{ +protected: + typedef int M; // { dg-error "protected" } +}; + +template <typename T> +struct A : B<T> { + typedef typename B<char>::M N; // { dg-error "context" } + A (int = N ()); +}; + +A<int> a = A<int> (); ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-19 14:27 ` Dodji Seketeli @ 2009-11-19 16:13 ` Jason Merrill 2009-11-19 18:16 ` Dodji Seketeli 2009-11-19 18:27 ` Dodji Seketeli 0 siblings, 2 replies; 11+ messages in thread From: Jason Merrill @ 2009-11-19 16:13 UTC (permalink / raw) To: Dodji Seketeli; +Cc: gcc-patches On 11/19/2009 09:19 AM, Dodji Seketeli wrote: > So I went ahead and tried the second approach we discussed on IRC, which is > to create a new kind of tree node to store template_info bits, instead of > the TREE_LIST it uses today. I was thinking that we didn't need a new tree node, just change the template_info fields in lang_decl_min and lang_type_class to be a new type, i.e. a pointer to your template_info_s. Jason ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-19 16:13 ` Jason Merrill @ 2009-11-19 18:16 ` Dodji Seketeli 2009-11-19 18:27 ` Dodji Seketeli 1 sibling, 0 replies; 11+ messages in thread From: Dodji Seketeli @ 2009-11-19 18:16 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches On Thu, Nov 19, 2009 at 11:11:38AM -0500, Jason Merrill wrote: > I was thinking that we didn't need a new tree node, just change the > template_info fields in lang_decl_min and lang_type_class to be a new > type, i.e. a pointer to your template_info_s. The reason why I went for a tree node instead is that it integrates more easily with the rest of the code. It seems quite some places expect the template_info to be a tree so I thought maybe such a big change wasn't necessarily desirable. Dodji ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-19 16:13 ` Jason Merrill 2009-11-19 18:16 ` Dodji Seketeli @ 2009-11-19 18:27 ` Dodji Seketeli 2009-11-19 20:26 ` Jason Merrill 1 sibling, 1 reply; 11+ messages in thread From: Dodji Seketeli @ 2009-11-19 18:27 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches On Thu, Nov 19, 2009 at 11:11:38AM -0500, Jason Merrill wrote: > I was thinking that we didn't need a new tree node, just change the > template_info fields in lang_decl_min and lang_type_class to be a new > type, i.e. a pointer to your template_info_s. The reason why I went for a tree node is that quite some places expect template_info to be a tree. So it was much easier to just wrap it in a tree. Should I go ahead nevertheless and use template_info_s instead? Dodji ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-19 18:27 ` Dodji Seketeli @ 2009-11-19 20:26 ` Jason Merrill 2009-11-20 8:37 ` Dodji Seketeli 0 siblings, 1 reply; 11+ messages in thread From: Jason Merrill @ 2009-11-19 20:26 UTC (permalink / raw) To: Dodji Seketeli; +Cc: gcc-patches On 11/19/2009 01:15 PM, Dodji Seketeli wrote: > The reason why I went for a tree node is that quite some places expect > template_info to be a tree. So it was much easier to just wrap it in a tree. > Should I go ahead nevertheless and use template_info_s instead? Please. Jason ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-19 20:26 ` Jason Merrill @ 2009-11-20 8:37 ` Dodji Seketeli 2009-11-20 15:00 ` Jason Merrill 0 siblings, 1 reply; 11+ messages in thread From: Dodji Seketeli @ 2009-11-20 8:37 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches On Thu, Nov 19, 2009 at 03:18:32PM -0500, Jason Merrill wrote: > On 11/19/2009 01:15 PM, Dodji Seketeli wrote: >> The reason why I went for a tree node is that quite some places expect >> template_info to be a tree. So it was much easier to just wrap it in a tree. >> Should I go ahead nevertheless and use template_info_s instead? > > Please. While trying to go that route, it appeared that template_info for enums (accessed using ENUM_TEMPLATE_INFO) are stored in TYPE_LANG_SLOT_1 which is TREE_NODE::type.binfo. Changing that to a struct template_info_s would be quite disruptive, so I believe it argues in favour of the TEMPLATE_INFO tree route instead. As we discussed on IRC I have updated the patch to slim the tree_template_info struct by using TREE_TYPE and TREE_CHAIN of the TEMPLATE_INFO to store the template decl and args. Tested against trunk on x86_64-unknown-linux-gnu. Dodji commit 2c259705ed231fd887a074ed14c1b06ac071d102 Author: Dodji Seketeli <dodji@redhat.com> Date: Mon Nov 16 22:29:06 2009 +0100 Fix PR c++/14777 gcc/cp/ChangeLog: PR c++/14777 * cp-tree.def <TEMPLATE_INFO>: Declare new kind of tree node. * cp-tree.h (struct tree_template_info, struct qualified_typedef_usage_s): New. (cp_tree_node_structure_enum): add TS_CP_TEMPLATE_INFO. (union lang_tree_node): Add template_info. (TI_TEMPLATE, TI_ARGS, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING): Adjust. (build_template_info): Declare. (get_types_needing_access_check): Adjust return type. (add_typedef_to_current_template_for_access_check): Declare. * cp-objcp-common.c (cp_tree_size): Handle TEMPLATE_INFO. * semantics.c (add_typedef_to_current_template_for_access_check): Split from ... (check_accessibility_of_qualified_id): ... here. * decl.c (make_typename_type): Use it. * pt.c (build_template_info): Define. (check_explicit_specialization, find_parameter_packs_r, push_template_decl_real, lookup_template_class, for_each_template_parm_r, tsubst_decl, tsubst): Use build_template_info. (get_types_needing_access_check): Adjust return type. (append_type_to_template_for_access_check_1): Record the location of the usage point of the typedef. Adjust to TEMPLATE_INFO. (append_type_to_template_for_access_check): Add new location parameter. Pass it to append_type_to_template_for_access_check_1. Adjust to TEMPLATE_INFO. (perform_typedefs_access_check): Temporarily set input_location to the usage point of the typedef we are checking access for. Adjust to new TEMPLATE_INFO tree node. * tree.c (bind_template_template_parm): Use build_template_info. * call.c (add_template_candidate_real): Likewise. * decl.c (grokfndecl): Likewise. (cp_tree_node_structure): Handle TEMPLATE_INFO. gcc/testsuite/ChangeLog: PR c++/14777 * g++.dg/template/typedef13.C: Adjust. * g++.dg/template/typedef19.C: Adjust. * g++.dg/template/typedef20.C: Adjust. * g++.dg/template/typedef22.C: New test. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e4a6bca..137b4bb 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2579,7 +2579,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, for this will point at template <class T> template <> S<T>::f(int), so that we can find the definition. For the purposes of overload resolution, however, we want the original TMPL. */ - cand->template_decl = tree_cons (tmpl, targs, NULL_TREE); + cand->template_decl = build_template_info (tmpl, targs); else cand->template_decl = DECL_TEMPLATE_INFO (fn); diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index da6f829..f06ad5b 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -140,6 +140,8 @@ cp_tree_size (enum tree_code code) case LAMBDA_EXPR: return sizeof (struct tree_lambda_expr); + case TEMPLATE_INFO: return sizeof (struct tree_template_info); + default: gcc_unreachable (); } diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 28ecc5b..c71f94c 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -439,6 +439,16 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0) DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction. */ DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0) +/* Used to represent the template information stored by template + specializations. + The accessors are: + TI_TEMPLATE the template declaration associated to the specialization + TI_ARGS the arguments of the template specialization + TI_TYPEDEFS_NEEDING_ACCESS_CHECKING the vector of typedefs used in + the pattern of the template for which access check is needed at template + instantiation time. */ +DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0) + /* Local variables: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a71dc73..f6ac5b6 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -600,6 +600,34 @@ struct GTY (()) tree_lambda_expr int discriminator; }; +/* A (typedef,context,usage location) triplet. + It represents a typedef used through a + context at a given source location. + e.g. + struct foo { + typedef int myint; + }; + + struct bar { + foo::myint v; // #1<-- this location. + }; + + In bar, the triplet will be (myint, foo, #1). + */ +struct GTY(()) qualified_typedef_usage_s { + tree typedef_decl; + tree context; + location_t locus; +}; +typedef struct qualified_typedef_usage_s qualified_typedef_usage_t; +DEF_VEC_O (qualified_typedef_usage_t); +DEF_VEC_ALLOC_O (qualified_typedef_usage_t,gc); + +struct GTY(()) tree_template_info { + struct tree_common common; + VEC(qualified_typedef_usage_t,gc) *typedefs_needing_access_checking; +}; + enum cp_tree_node_structure_enum { TS_CP_GENERIC, TS_CP_IDENTIFIER, @@ -614,6 +642,7 @@ enum cp_tree_node_structure_enum { TS_CP_ARGUMENT_PACK_SELECT, TS_CP_TRAIT_EXPR, TS_CP_LAMBDA_EXPR, + TS_CP_TEMPLATE_INFO, LAST_TS_CP_ENUM }; @@ -636,6 +665,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"), trait_expression; struct tree_lambda_expr GTY ((tag ("TS_CP_LAMBDA_EXPR"))) lambda_expression; + struct tree_template_info GTY ((tag ("TS_CP_TEMPLATE_INFO"))) + template_info; }; \f @@ -2408,12 +2439,14 @@ extern void decl_shadowed_for_var_insert (tree, tree); ? (ENUM_TEMPLATE_INFO (NODE) = (VAL)) \ : (CLASSTYPE_TEMPLATE_INFO (NODE) = (VAL))) -#define TI_TEMPLATE(NODE) (TREE_PURPOSE (NODE)) -#define TI_ARGS(NODE) (TREE_VALUE (NODE)) +#define TI_TEMPLATE(NODE) TREE_TYPE (TEMPLATE_INFO_CHECK (NODE)) +#define TI_ARGS(NODE) TREE_CHAIN (TEMPLATE_INFO_CHECK (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)) +#define TI_TYPEDEFS_NEEDING_ACCESS_CHECKING(NODE) \ + ((struct tree_template_info*)TEMPLATE_INFO_CHECK \ + (NODE))->typedefs_needing_access_checking /* We use TREE_VECs to hold template arguments. If there is only one level of template arguments, then the TREE_VEC contains the @@ -4775,7 +4808,8 @@ extern tree check_explicit_specialization (tree, tree, int, int); extern tree make_auto (void); extern tree do_auto_deduction (tree, tree, tree); extern tree type_uses_auto (tree); -extern void append_type_to_template_for_access_check (tree, tree, tree); +extern void append_type_to_template_for_access_check (tree, tree, tree, + location_t); extern tree splice_late_return_type (tree, tree); extern bool is_auto (const_tree); extern tree process_template_parm (tree, location_t, tree, @@ -4809,8 +4843,9 @@ extern bool function_parameter_pack_p (const_tree); extern bool function_parameter_expanded_from_pack_p (tree, tree); extern tree make_pack_expansion (tree); extern bool check_for_bare_parameter_packs (tree); +extern tree build_template_info (tree, tree); extern tree get_template_info (const_tree); -extern tree get_types_needing_access_check (tree); +extern VEC(qualified_typedef_usage_t,gc)* get_types_needing_access_check (tree); extern int template_class_depth (tree); extern int is_specialization_of (tree, tree); extern bool is_specialization_of_friend (tree, tree); @@ -5038,6 +5073,8 @@ extern void emit_associated_thunks (tree); extern void finish_mem_initializers (tree); extern tree check_template_template_default_arg (tree); extern void expand_or_defer_fn (tree); +extern void add_typedef_to_current_template_for_access_check (tree, tree, + location_t); extern void check_accessibility_of_qualified_id (tree, tree, tree); extern tree finish_qualified_id_expr (tree, tree, bool, bool, bool, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 73bf995..73a836f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3075,6 +3075,11 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, if (complain & tf_error) perform_or_defer_access_check (TYPE_BINFO (context), t, t); + /* If we are currently parsing a template and if T is a typedef accessed + through CONTEXT then we need to remember and check access of T at + template instantiation time. */ + add_typedef_to_current_template_for_access_check (t, context, input_location); + if (want_template) return lookup_template_class (t, TREE_OPERAND (fullname, 1), NULL_TREE, context, @@ -6696,7 +6701,7 @@ grokfndecl (tree ctype, } gcc_assert (TREE_CODE (fns) == IDENTIFIER_NODE || TREE_CODE (fns) == OVERLOAD); - DECL_TEMPLATE_INFO (decl) = tree_cons (fns, args, NULL_TREE); + DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args); for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t) @@ -12838,6 +12843,7 @@ cp_tree_node_structure (union lang_tree_node * t) case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT; case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR; + case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO; default: return TS_CP_GENERIC; } } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b7d72c1..f332d10 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -189,7 +189,8 @@ static tree tsubst_copy (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 void perform_typedefs_access_check (tree tmpl, tree targs); -static void append_type_to_template_for_access_check_1 (tree, tree, tree); +static void append_type_to_template_for_access_check_1 (tree, tree, tree, + location_t); static hashval_t iterative_hash_template_arg (tree arg, hashval_t val); static tree listify (tree); static tree listify_autos (tree, tree); @@ -286,6 +287,17 @@ finish_member_template_decl (tree decl) return error_mark_node; } +/* Create a template info node. */ + +tree +build_template_info (tree template_decl, tree template_args) +{ + tree result = make_node (TEMPLATE_INFO); + TI_TEMPLATE (result) = template_decl; + TI_ARGS (result) = template_args; + return result; +} + /* Return the template info node corresponding to T, whatever T is. */ tree @@ -2492,7 +2504,7 @@ check_explicit_specialization (tree declarator, } /* Set up the DECL_TEMPLATE_INFO for DECL. */ - DECL_TEMPLATE_INFO (decl) = tree_cons (tmpl, targs, NULL_TREE); + DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs); /* Inherit default function arguments from the template DECL is specializing. */ @@ -2900,7 +2912,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) case UNION_TYPE: case ENUMERAL_TYPE: if (TYPE_TEMPLATE_INFO (t)) - cp_walk_tree (&TREE_VALUE (TYPE_TEMPLATE_INFO (t)), + cp_walk_tree (&TI_ARGS (TYPE_TEMPLATE_INFO (t)), &find_parameter_packs_r, ppd, ppd->visited); *walk_subtrees = 0; @@ -4352,7 +4364,7 @@ push_template_decl_real (tree decl, bool is_friend) DECL_TI_TEMPLATE (decl) = new_tmpl; SET_DECL_TEMPLATE_SPECIALIZATION (new_tmpl); DECL_TEMPLATE_INFO (new_tmpl) - = tree_cons (tmpl, args, NULL_TREE); + = build_template_info (tmpl, args); register_specialization (new_tmpl, most_general_template (tmpl), @@ -4471,7 +4483,7 @@ template arguments to %qD do not match original template %qD", if (DECL_TEMPLATE_INFO (tmpl)) args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args); - info = tree_cons (tmpl, args, NULL_TREE); + info = build_template_info (tmpl, args); if (DECL_IMPLICIT_TYPEDEF_P (decl)) SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info); @@ -6409,7 +6421,7 @@ lookup_template_class (tree d1, found = CLASSTYPE_TI_TEMPLATE (found); } - SET_TYPE_TEMPLATE_INFO (t, tree_cons (found, arglist, NULL_TREE)); + SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist)); elt.spec = t; slot = (spec_entry **) htab_find_slot_with_hash (type_specializations, @@ -6485,7 +6497,7 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) case ENUMERAL_TYPE: if (!TYPE_TEMPLATE_INFO (t)) *walk_subtrees = 0; - else if (for_each_template_parm (TREE_VALUE (TYPE_TEMPLATE_INFO (t)), + else if (for_each_template_parm (TI_ARGS (TYPE_TEMPLATE_INFO (t)), fn, data, pfd->visited, pfd->include_nondeduced_p)) return error_mark_node; @@ -7341,17 +7353,24 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, static void perform_typedefs_access_check (tree tmpl, tree targs) { - tree t; + location_t saved_location; + int i; + qualified_typedef_usage_t *iter; if (!tmpl || (!CLASS_TYPE_P (tmpl) && TREE_CODE (tmpl) != FUNCTION_DECL)) return; - for (t = get_types_needing_access_check (tmpl); t; t = TREE_CHAIN (t)) + saved_location = input_location; + for (i = 0; + VEC_iterate (qualified_typedef_usage_t, + get_types_needing_access_check (tmpl), + i, iter); + ++i) { - tree type_decl = TREE_PURPOSE (t); - tree type_scope = TREE_VALUE (t); + tree type_decl = iter->typedef_decl; + tree type_scope = iter->context; if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope)) continue; @@ -7361,9 +7380,13 @@ perform_typedefs_access_check (tree tmpl, tree targs) if (uses_template_parms (type_scope)) type_scope = tsubst (type_scope, targs, tf_error, NULL_TREE); + /* Make access check error messages point to the location + of the use of the typedef. */ + input_location = iter->locus; perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl); } + input_location = saved_location; } tree @@ -8615,7 +8638,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) gcc_assert (DECL_LANG_SPECIFIC (r) != 0); TREE_CHAIN (r) = NULL_TREE; - DECL_TEMPLATE_INFO (r) = build_tree_list (t, args); + DECL_TEMPLATE_INFO (r) = build_template_info (t, args); if (TREE_CODE (decl) == TYPE_DECL) { @@ -8844,7 +8867,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (gen_tmpl) { DECL_TEMPLATE_INFO (r) - = tree_cons (gen_tmpl, argvec, NULL_TREE); + = build_template_info (gen_tmpl, argvec); SET_DECL_IMPLICIT_INSTANTIATION (r); register_specialization (r, gen_tmpl, argvec, false, hash); @@ -9258,7 +9281,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_EXTERNAL (r) = 1; register_specialization (r, gen_tmpl, argvec, false, hash); - DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE); + DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec); SET_DECL_IMPLICIT_INSTANTIATION (r); } else if (cp_unevaluated_operand) @@ -9867,7 +9890,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (r) - = tree_cons (TYPE_TI_TEMPLATE (t), argvec, NULL_TREE); + = build_template_info (TYPE_TI_TEMPLATE (t), argvec); } } break; @@ -18040,28 +18063,29 @@ type_uses_auto (tree type) return NULL_TREE; } -/* For a given template T, return the list of typedefs referenced +/* For a given template T, return the vector 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 +VEC(qualified_typedef_usage_t,gc)* get_types_needing_access_check (tree t) { - tree ti, result = NULL_TREE; + tree ti; + VEC(qualified_typedef_usage_t,gc) *result = NULL; if (!t || t == error_mark_node) - return t; + return NULL; if (!(ti = get_template_info (t))) - return NULL_TREE; + return NULL; if (CLASS_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL) { if (!TI_TEMPLATE (ti)) - return NULL_TREE; + return NULL; result = TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti); } @@ -18075,6 +18099,7 @@ get_types_needing_access_check (tree t) 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. + LOCATION is the location of the usage point of TYPE_DECL. This function is a subroutine of append_type_to_template_for_access_check. */ @@ -18082,8 +18107,10 @@ get_types_needing_access_check (tree t) static void append_type_to_template_for_access_check_1 (tree t, tree type_decl, - tree scope) + tree scope, + location_t location) { + qualified_typedef_usage_t typedef_usage; tree ti; if (!t || t == error_mark_node) @@ -18100,14 +18127,20 @@ append_type_to_template_for_access_check_1 (tree t, gcc_assert (TI_TEMPLATE (ti)); - TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti) = - tree_cons (type_decl, scope, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti)); + typedef_usage.typedef_decl = type_decl; + typedef_usage.context = scope; + typedef_usage.locus = location; + + VEC_safe_push (qualified_typedef_usage_t, gc, + TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (ti), + &typedef_usage); } /* Append TYPE_DECL to the template TEMPL. TEMPL is either a class type, a FUNCTION_DECL or a a TEMPLATE_DECL. At TEMPL instanciation time, TYPE_DECL will be checked to see if it can be accessed through SCOPE. + LOCATION is the location of the usage point of TYPE_DECL. e.g. consider the following code snippet: @@ -18118,7 +18151,7 @@ append_type_to_template_for_access_check_1 (tree t, template<class U> struct S { - C::myint mi; + C::myint mi; // <-- usage point of the typedef C::myint }; S<char> s; @@ -18135,25 +18168,25 @@ append_type_to_template_for_access_check_1 (tree t, void append_type_to_template_for_access_check (tree templ, tree type_decl, - tree scope) + tree scope, + location_t location) { - tree node; + qualified_typedef_usage_t *iter; + int i; gcc_assert (type_decl && (TREE_CODE (type_decl) == TYPE_DECL)); /* Make sure we don't append the type to the template twice. */ - for (node = get_types_needing_access_check (templ); - node; - node = TREE_CHAIN (node)) - { - tree decl = TREE_PURPOSE (node); - tree type_scope = TREE_VALUE (node); - - if (decl == type_decl && type_scope == scope) - return; - } + for (i = 0; + VEC_iterate (qualified_typedef_usage_t, + get_types_needing_access_check (templ), + i, iter); + ++i) + if (iter->typedef_decl == type_decl && scope == iter->context) + return; - append_type_to_template_for_access_check_1 (templ, type_decl, scope); + append_type_to_template_for_access_check_1 (templ, type_decl, + scope, location); } /* Set up the hash tables for template instantiations. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c1df24b..c83b796 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1531,6 +1531,37 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) } } +/* If we are currently parsing a template and we encountered a typedef + TYPEDEF_DECL that is being accessed though CONTEXT, this function + adds the typedef to a list tied to the current template. + At tempate instantiatin time, that list is walked and access check + performed for each typedef. + LOCATION is the location of the usage point of TYPEDEF_DECL. */ + +void +add_typedef_to_current_template_for_access_check (tree typedef_decl, + tree context, + location_t location) +{ + tree template_info = NULL; + tree cs = current_scope (); + + if (!is_typedef_decl (typedef_decl) + || !context + || !CLASS_TYPE_P (context) + || !cs) + return; + + if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL) + template_info = get_template_info (cs); + + if (template_info + && TI_TEMPLATE (template_info) + && !currently_open_class (context)) + append_type_to_template_for_access_check (cs, typedef_decl, + context, location); +} + /* DECL was the declaration to which a qualified-id resolved. Issue an error message if it is not accessible. If OBJECT_TYPE is non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the @@ -1549,27 +1580,11 @@ check_accessibility_of_qualified_id (tree decl, add it to a list tied to the template. At template instantiation time, that list will be walked and access check performed. */ - if (is_typedef_decl (decl)) - { - /* This the scope through which type_decl is accessed. - It will be useful information later to do access check for - type_decl usage. */ - tree scope = nested_name_specifier - ? nested_name_specifier - : DECL_CONTEXT (decl); - tree templ_info = NULL; - tree cs = current_scope (); - - if (cs && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL)) - templ_info = get_template_info (cs); - - if (templ_info - && TI_TEMPLATE (templ_info) - && scope - && CLASS_TYPE_P (scope) - && !currently_open_class (scope)) - append_type_to_template_for_access_check (current_scope (), decl, scope); - } + add_typedef_to_current_template_for_access_check (decl, + nested_name_specifier + ? nested_name_specifier + : DECL_CONTEXT (decl), + input_location); /* If we're not checking, return immediately. */ if (deferred_access_no_check) diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index f9e1cd7..d431b31 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1490,8 +1490,7 @@ bind_template_template_parm (tree t, tree newargs) TEMPLATE_TYPE_PARM_INDEX (t2) = copy_node (TEMPLATE_TYPE_PARM_INDEX (t)); TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (t2)) = decl; TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2) - = tree_cons (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), - newargs, NULL_TREE); + = build_template_info (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), newargs); TREE_TYPE (decl) = t2; TYPE_NAME (t2) = decl; diff --git a/gcc/testsuite/g++.dg/template/typedef13.C b/gcc/testsuite/g++.dg/template/typedef13.C index aa8bb32..a22e1cb 100644 --- a/gcc/testsuite/g++.dg/template/typedef13.C +++ b/gcc/testsuite/g++.dg/template/typedef13.C @@ -8,8 +8,8 @@ class A }; template <class T> class B : public A -{ // { dg-error "within this context" } - mytype mem; +{ + mytype mem; // { dg-error "within this context" } }; B<int> b; // { dg-message "instantiated from here" } diff --git a/gcc/testsuite/g++.dg/template/typedef19.C b/gcc/testsuite/g++.dg/template/typedef19.C index f576d48..2fac20e 100644 --- a/gcc/testsuite/g++.dg/template/typedef19.C +++ b/gcc/testsuite/g++.dg/template/typedef19.C @@ -14,8 +14,8 @@ class B : public A template<class T> class B<T*> : public A -{ // { dg-error "within this context" } - mytype mem; +{ + mytype mem; // { dg-error "within this context" } }; B<int*> b; diff --git a/gcc/testsuite/g++.dg/template/typedef20.C b/gcc/testsuite/g++.dg/template/typedef20.C index a5cbdeb..c768ce0 100644 --- a/gcc/testsuite/g++.dg/template/typedef20.C +++ b/gcc/testsuite/g++.dg/template/typedef20.C @@ -18,9 +18,9 @@ struct y : public x template<typename T> struct y<T*> : public x -{ // { dg-error "within this context" } +{ typedef x::type good; - typedef x::privtype bad; + typedef x::privtype bad; // { dg-error "within this context" } }; template class y<int>; diff --git a/gcc/testsuite/g++.dg/template/typedef22.C b/gcc/testsuite/g++.dg/template/typedef22.C new file mode 100644 index 0000000..e3ecfcb --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typedef22.C @@ -0,0 +1,18 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin: PR c++/14777 +// { dg-do compile } + +template <typename T> +struct B +{ +protected: + typedef int M; // { dg-error "protected" } +}; + +template <typename T> +struct A : B<T> { + typedef typename B<char>::M N; // { dg-error "context" } + A (int = N ()); +}; + +A<int> a = A<int> (); ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: PR c++/141777 2009-11-20 8:37 ` Dodji Seketeli @ 2009-11-20 15:00 ` Jason Merrill 0 siblings, 0 replies; 11+ messages in thread From: Jason Merrill @ 2009-11-20 15:00 UTC (permalink / raw) To: Dodji Seketeli; +Cc: gcc-patches OK. Jason ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2009-11-20 14:53 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-11-16 22:13 PR c++/141777 Dodji Seketeli 2009-11-17 1:33 ` Jason Merrill 2009-11-17 13:23 ` Dodji Seketeli 2009-11-17 20:48 ` Jason Merrill 2009-11-19 14:27 ` Dodji Seketeli 2009-11-19 16:13 ` Jason Merrill 2009-11-19 18:16 ` Dodji Seketeli 2009-11-19 18:27 ` Dodji Seketeli 2009-11-19 20:26 ` Jason Merrill 2009-11-20 8:37 ` Dodji Seketeli 2009-11-20 15:00 ` Jason Merrill
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).