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