PR c++/141777
Dodji Seketeli
dodji@redhat.com
Mon Nov 16 22:13:00 GMT 2009
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> ();
More information about the Gcc-patches
mailing list