* 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).