aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>2003-01-08 14:42:39 +0000
committerKriang Lerdsuwanakij <lerdsuwa@gcc.gnu.org>2003-01-08 14:42:39 +0000
commit2b59fc25c6e31acae34c6ab5c108941e5d31e5b4 (patch)
treeb20f75bc20fe6a1ea780fb19af201a2a9529519e
parentc5e7ce43a58f9ed299a496f3c3487a7ce7b32de3 (diff)
downloadgcc-2b59fc25c6e31acae34c6ab5c108941e5d31e5b4.zip
gcc-2b59fc25c6e31acae34c6ab5c108941e5d31e5b4.tar.gz
gcc-2b59fc25c6e31acae34c6ab5c108941e5d31e5b4.tar.bz2
re PR c++/9030 (Template friends and access to local classes)
PR c++/9030 * decl.c (make_typename_type): Check access only when tf_error. (make_unbound_class_template): Likewise. * pt.c (saved_access_scope): New variable. (push_access_scope_real): New function. (push_access_scope): Likewise. (pop_access_scope): Likewise. (tsubst_default_argument): Use them. (instantiate_template): Likewise. (regenerate_decl_from_template): Likewise. (instantiate_decl): Likewise. (get_mostly_instantiated_function_type): Likewise. * g++.dg/template/friend12.C: New test. * g++.dg/template/friend13.C: Likewise. * g++.old-deja/g++.eh/spec6.C: Add missing error message. From-SVN: r61046
-rw-r--r--gcc/cp/ChangeLog15
-rw-r--r--gcc/cp/decl.c33
-rw-r--r--gcc/cp/pt.c127
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/template/friend12.C24
-rw-r--r--gcc/testsuite/g++.dg/template/friend13.C21
-rw-r--r--gcc/testsuite/g++.old-deja/g++.eh/spec6.C2
7 files changed, 187 insertions, 42 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 9b7f67a..26207b7 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,18 @@
+2003-01-08 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ PR c++/9030
+ * decl.c (make_typename_type): Check access only when tf_error.
+ (make_unbound_class_template): Likewise.
+ * pt.c (saved_access_scope): New variable.
+ (push_access_scope_real): New function.
+ (push_access_scope): Likewise.
+ (pop_access_scope): Likewise.
+ (tsubst_default_argument): Use them.
+ (instantiate_template): Likewise.
+ (regenerate_decl_from_template): Likewise.
+ (instantiate_decl): Likewise.
+ (get_mostly_instantiated_function_type): Likewise.
+
2003-01-07 Nathanael Nerode <neroden@gcc.gnu.org>
* tree.c: Delete bogus #if 0 code.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f814182..538519e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5671,10 +5671,13 @@ make_typename_type (context, name, complain)
return error_mark_node;
}
- if (complain & tf_parsing)
- type_access_control (context, tmpl);
- else
- enforce_access (context, tmpl);
+ if (complain & tf_error)
+ {
+ if (complain & tf_parsing)
+ type_access_control (context, tmpl);
+ else
+ enforce_access (context, tmpl);
+ }
return lookup_template_class (tmpl,
TREE_OPERAND (fullname, 1),
@@ -5703,10 +5706,13 @@ make_typename_type (context, name, complain)
return error_mark_node;
}
- if (complain & tf_parsing)
- type_access_control (context, t);
- else
- enforce_access (context, t);
+ if (complain & tf_error)
+ {
+ if (complain & tf_parsing)
+ type_access_control (context, t);
+ else
+ enforce_access (context, t);
+ }
if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
t = TREE_TYPE (t);
@@ -5774,10 +5780,13 @@ make_unbound_class_template (context, name, complain)
return error_mark_node;
}
- if (complain & tf_parsing)
- type_access_control (context, tmpl);
- else
- enforce_access (context, tmpl);
+ if (complain & tf_error)
+ {
+ if (complain & tf_parsing)
+ type_access_control (context, tmpl);
+ else
+ enforce_access (context, tmpl);
+ }
return tmpl;
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f7a9114..b63443b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -67,6 +67,8 @@ static size_t inline_parm_levels_used;
static GTY(()) tree current_tinst_level;
+static GTY(()) tree saved_access_scope;
+
/* A map from local variable declarations in the body of the template
presently being instantiated to the corresponding instantiated
local variables. */
@@ -88,6 +90,9 @@ static htab_t local_specializations;
#define GTB_IGNORE_TYPE 2 /* We don't need to try to unify the current
type with the desired type. */
+static void push_access_scope_real PARAMS ((tree, tree, tree));
+static void push_access_scope PARAMS ((tree));
+static void pop_access_scope PARAMS ((tree));
static int resolve_overloaded_unification PARAMS ((tree, tree, tree, tree,
unification_kind_t, int));
static int try_one_overload PARAMS ((tree, tree, tree, tree, tree,
@@ -168,6 +173,80 @@ static int invalid_nontype_parm_type_p PARAMS ((tree, tsubst_flags_t));
static int eq_local_specializations (const void *, const void *);
static tree template_for_substitution (tree);
+/* Make the current scope suitable for access checking when we are
+ processing T. T can be FUNCTION_DECL for instantiated function
+ template, TEMPLATE_DECL for uninstantiated one, or VAR_DECL for
+ static member variable (need by instantiate_decl). ARGS is the
+ template argument for TEMPLATE_DECL. If CONTEXT is not NULL_TREE,
+ this is used instead of the context of T. */
+
+void
+push_access_scope_real (t, args, context)
+ tree t, args, context;
+{
+ if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t))
+ {
+ /* When we are processing specialization `foo<Outer>' for code like
+
+ template <class U> typename U::Inner foo ();
+ class Outer {
+ struct Inner {};
+ friend Outer::Inner foo<Outer> ();
+ };
+
+ `T' is a TEMPLATE_DECL, but `Outer' is only a friend of one of
+ its specialization. We can get the FUNCTION_DECL with the right
+ information because this specialization has already been
+ registered by the friend declaration above. */
+
+ if (DECL_FUNCTION_TEMPLATE_P (t) && args)
+ {
+ tree full_args = tsubst_template_arg_vector
+ (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t)), args, tf_none);
+ tree spec = NULL_TREE;
+ if (full_args != error_mark_node)
+ spec = retrieve_specialization (t, full_args);
+ if (spec)
+ t = spec;
+ }
+
+ saved_access_scope = tree_cons
+ (NULL_TREE, current_function_decl, saved_access_scope);
+ current_function_decl = t;
+ }
+
+ if (!context)
+ context = DECL_CONTEXT (t);
+ if (context && TYPE_P (context))
+ push_nested_class (context, 2);
+}
+
+/* Like push_access_scope_real, but always uses DECL_CONTEXT. */
+
+void
+push_access_scope (t)
+ tree t;
+{
+ push_access_scope_real (t, NULL_TREE, NULL_TREE);
+}
+
+/* Restore the scope set up by push_access_scope. T is the node we
+ are processing. */
+
+void
+pop_access_scope (t)
+ tree t;
+{
+ if (DECL_CLASS_SCOPE_P (t))
+ pop_nested_class ();
+
+ if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t))
+ {
+ current_function_decl = TREE_VALUE (saved_access_scope);
+ saved_access_scope = TREE_CHAIN (saved_access_scope);
+ }
+}
+
/* Do any processing required when DECL (a member template
declaration) is finished. Returns the TEMPLATE_DECL corresponding
to DECL, unless it is a specialization, in which case the DECL
@@ -5733,14 +5812,14 @@ tsubst_default_argument (fn, type, arg)
??? current_class_type affects a lot more than name lookup. This is
very fragile. Fortunately, it will go away when we do 2-phase name
binding properly. */
- if (DECL_CLASS_SCOPE_P (fn))
- pushclass (DECL_CONTEXT (fn), 2);
+
+ /* FN is already the desired FUNCTION_DECL. */
+ push_access_scope (fn);
arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
tf_error | tf_warning, NULL_TREE);
- if (DECL_CLASS_SCOPE_P (fn))
- popclass ();
+ pop_access_scope (fn);
/* Make sure the default argument is reasonable. */
arg = check_default_argument (type, arg);
@@ -7873,17 +7952,17 @@ instantiate_template (tmpl, targ_ptr)
}
/* Make sure that we can see identifiers, and compute access
- correctly. */
- if (DECL_CLASS_SCOPE_P (gen_tmpl))
- pushclass (tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, tf_error,
- gen_tmpl), 1);
+ correctly. The desired FUNCTION_DECL for FNDECL may or may not be
+ created earlier. Let push_access_scope_real figure that out. */
+ push_access_scope_real
+ (gen_tmpl, targ_ptr, tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr,
+ tf_error, gen_tmpl));
/* substitute template parameters */
fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
targ_ptr, tf_error, gen_tmpl);
- if (DECL_CLASS_SCOPE_P (gen_tmpl))
- popclass ();
+ pop_access_scope (gen_tmpl);
/* The DECL_TI_TEMPLATE should always be the immediate parent
template, not the most general template. */
@@ -7955,7 +8034,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
int result;
my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
-
+
fntype = TREE_TYPE (fn);
if (explicit_targs)
{
@@ -9977,6 +10056,7 @@ regenerate_decl_from_template (decl, tmpl)
instantiation of a specialization, which it isn't: it's a full
instantiation. */
gen_tmpl = most_general_template (tmpl);
+ push_access_scope_real (gen_tmpl, args, DECL_CONTEXT (decl));
unregistered = unregister_specialization (decl, gen_tmpl);
/* If the DECL was not unregistered then something peculiar is
@@ -9984,12 +10064,6 @@ regenerate_decl_from_template (decl, tmpl)
register_specialization for it. */
my_friendly_assert (unregistered, 0);
- if (DECL_CLASS_SCOPE_P (decl))
- /* Make sure that we can see identifiers, and compute access
- correctly, for the class members used in the declaration of
- this static variable or function. */
- push_nested_class (DECL_CONTEXT (decl), 2);
-
/* Do the substitution to get the new declaration. */
new_decl = tsubst (code_pattern, args, tf_error, NULL_TREE);
@@ -10010,9 +10084,7 @@ regenerate_decl_from_template (decl, tmpl)
DECL_INITIAL (decl) = NULL_TREE;
}
- /* Pop the class context we pushed above. */
- if (DECL_CLASS_SCOPE_P (decl))
- pop_nested_class ();
+ pop_access_scope (decl);
/* The immediate parent of the new template is still whatever it was
before, even though tsubst sets DECL_TI_TEMPLATE up as the most
@@ -10218,9 +10290,9 @@ instantiate_decl (d, defer_ok)
tree type = TREE_TYPE (gen);
/* Make sure that we can see identifiers, and compute access
- correctly. */
- if (DECL_CLASS_SCOPE_P (d))
- pushclass (DECL_CONTEXT (d), 1);
+ correctly. D is already the target FUNCTION_DECL with the
+ right context. */
+ push_access_scope (d);
if (TREE_CODE (gen) == FUNCTION_DECL)
{
@@ -10235,8 +10307,7 @@ instantiate_decl (d, defer_ok)
}
tsubst (type, gen_args, tf_error | tf_warning, d);
- if (DECL_CLASS_SCOPE_P (d))
- popclass ();
+ pop_access_scope (d);
}
if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
@@ -10597,8 +10668,7 @@ get_mostly_instantiated_function_type (decl)
partial substitution here. It depends only on outer template
parameters, regardless of whether the innermost level is
specialized or not. */
- if (DECL_CLASS_SCOPE_P (decl))
- pushclass (DECL_CONTEXT (decl), 1);
+ push_access_scope (decl);
/* Now, do the (partial) substitution to figure out the
appropriate function type. */
@@ -10611,8 +10681,7 @@ get_mostly_instantiated_function_type (decl)
TREE_VEC_LENGTH (partial_args)--;
tparms = tsubst_template_parms (tparms, partial_args, tf_error);
- if (DECL_CLASS_SCOPE_P (decl))
- popclass ();
+ pop_access_scope (decl);
}
return fn_type;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ba32c50..848423d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2003-01-08 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ PR c++/9030
+ * g++.dg/template/friend12.C: New test.
+ * g++.dg/template/friend13.C: Likewise.
+ * g++.old-deja/g++.eh/spec6.C: Add missing error message.
+
Wed Jan 8 11:41:47 CET 2003 Jan Hubicka <jh@suse.cz>
* gcc.dg/i386-cadd.c: New test.
diff --git a/gcc/testsuite/g++.dg/template/friend12.C b/gcc/testsuite/g++.dg/template/friend12.C
new file mode 100644
index 0000000..0cd561b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend12.C
@@ -0,0 +1,24 @@
+// { dg-do compile }
+
+// Origin: Wolfgang Bangerth <bangerth@ticam.utexas.edu>
+
+// PR 9030. Perform access checking to parameter and return type of
+// function template correctly when the template is friend.
+
+template <class T> class Outer {
+ private:
+ struct Inner {};
+
+ template <class T_>
+ friend typename Outer<T_>::Inner foo ();
+};
+
+template <class T>
+typename Outer<T>::Inner
+foo () {
+ return typename Outer<T>::Inner();
+}
+
+void f() {
+ foo<int>();
+}
diff --git a/gcc/testsuite/g++.dg/template/friend13.C b/gcc/testsuite/g++.dg/template/friend13.C
new file mode 100644
index 0000000..6eebf6b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend13.C
@@ -0,0 +1,21 @@
+// { dg-do compile }
+
+// Perform access checking to parameter and return type of
+// function template correctly when only specialization is friend.
+
+template <class T>
+typename T::Inner
+foo () {
+ return typename T::Inner();
+}
+
+class Outer {
+ private:
+ struct Inner {};
+
+ friend Outer::Inner foo<Outer> ();
+};
+
+void f() {
+ foo<Outer>();
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.eh/spec6.C b/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
index 1bde4cb..d9d4edf 100644
--- a/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
+++ b/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
@@ -25,7 +25,7 @@ template<class T> void fnx(T *) throw(T){} // ERROR - invalid use of void expre
void fx()
{
fnx((int *)0);
- fnx((void *)0);
+ fnx((void *)0); // ERROR - instantiated from here
}
// [except.spec] 2, exception specifiers must be the same set of types (but