This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PR c++/141777


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]