This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
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