Commit 2b59fc25 by Kriang Lerdsuwanakij Committed by Kriang Lerdsuwanakij

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
parent c5e7ce43
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> 2003-01-07 Nathanael Nerode <neroden@gcc.gnu.org>
* tree.c: Delete bogus #if 0 code. * tree.c: Delete bogus #if 0 code.
......
...@@ -5671,10 +5671,13 @@ make_typename_type (context, name, complain) ...@@ -5671,10 +5671,13 @@ make_typename_type (context, name, complain)
return error_mark_node; return error_mark_node;
} }
if (complain & tf_parsing) if (complain & tf_error)
type_access_control (context, tmpl); {
else if (complain & tf_parsing)
enforce_access (context, tmpl); type_access_control (context, tmpl);
else
enforce_access (context, tmpl);
}
return lookup_template_class (tmpl, return lookup_template_class (tmpl,
TREE_OPERAND (fullname, 1), TREE_OPERAND (fullname, 1),
...@@ -5703,10 +5706,13 @@ make_typename_type (context, name, complain) ...@@ -5703,10 +5706,13 @@ make_typename_type (context, name, complain)
return error_mark_node; return error_mark_node;
} }
if (complain & tf_parsing) if (complain & tf_error)
type_access_control (context, t); {
else if (complain & tf_parsing)
enforce_access (context, t); type_access_control (context, t);
else
enforce_access (context, t);
}
if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
t = TREE_TYPE (t); t = TREE_TYPE (t);
...@@ -5774,10 +5780,13 @@ make_unbound_class_template (context, name, complain) ...@@ -5774,10 +5780,13 @@ make_unbound_class_template (context, name, complain)
return error_mark_node; return error_mark_node;
} }
if (complain & tf_parsing) if (complain & tf_error)
type_access_control (context, tmpl); {
else if (complain & tf_parsing)
enforce_access (context, tmpl); type_access_control (context, tmpl);
else
enforce_access (context, tmpl);
}
return tmpl; return tmpl;
} }
......
...@@ -67,6 +67,8 @@ static size_t inline_parm_levels_used; ...@@ -67,6 +67,8 @@ static size_t inline_parm_levels_used;
static GTY(()) tree current_tinst_level; static GTY(()) tree current_tinst_level;
static GTY(()) tree saved_access_scope;
/* A map from local variable declarations in the body of the template /* A map from local variable declarations in the body of the template
presently being instantiated to the corresponding instantiated presently being instantiated to the corresponding instantiated
local variables. */ local variables. */
...@@ -88,6 +90,9 @@ static htab_t local_specializations; ...@@ -88,6 +90,9 @@ static htab_t local_specializations;
#define GTB_IGNORE_TYPE 2 /* We don't need to try to unify the current #define GTB_IGNORE_TYPE 2 /* We don't need to try to unify the current
type with the desired type. */ 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, static int resolve_overloaded_unification PARAMS ((tree, tree, tree, tree,
unification_kind_t, int)); unification_kind_t, int));
static int try_one_overload PARAMS ((tree, tree, tree, tree, tree, 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)); ...@@ -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 int eq_local_specializations (const void *, const void *);
static tree template_for_substitution (tree); 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 /* Do any processing required when DECL (a member template
declaration) is finished. Returns the TEMPLATE_DECL corresponding declaration) is finished. Returns the TEMPLATE_DECL corresponding
to DECL, unless it is a specialization, in which case the DECL to DECL, unless it is a specialization, in which case the DECL
...@@ -5733,14 +5812,14 @@ tsubst_default_argument (fn, type, arg) ...@@ -5733,14 +5812,14 @@ tsubst_default_argument (fn, type, arg)
??? current_class_type affects a lot more than name lookup. This is ??? 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 very fragile. Fortunately, it will go away when we do 2-phase name
binding properly. */ 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), arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
tf_error | tf_warning, NULL_TREE); tf_error | tf_warning, NULL_TREE);
if (DECL_CLASS_SCOPE_P (fn)) pop_access_scope (fn);
popclass ();
/* Make sure the default argument is reasonable. */ /* Make sure the default argument is reasonable. */
arg = check_default_argument (type, arg); arg = check_default_argument (type, arg);
...@@ -7873,17 +7952,17 @@ instantiate_template (tmpl, targ_ptr) ...@@ -7873,17 +7952,17 @@ instantiate_template (tmpl, targ_ptr)
} }
/* Make sure that we can see identifiers, and compute access /* Make sure that we can see identifiers, and compute access
correctly. */ correctly. The desired FUNCTION_DECL for FNDECL may or may not be
if (DECL_CLASS_SCOPE_P (gen_tmpl)) created earlier. Let push_access_scope_real figure that out. */
pushclass (tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, tf_error, push_access_scope_real
gen_tmpl), 1); (gen_tmpl, targ_ptr, tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr,
tf_error, gen_tmpl));
/* substitute template parameters */ /* substitute template parameters */
fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl), fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
targ_ptr, tf_error, gen_tmpl); targ_ptr, tf_error, gen_tmpl);
if (DECL_CLASS_SCOPE_P (gen_tmpl)) pop_access_scope (gen_tmpl);
popclass ();
/* The DECL_TI_TEMPLATE should always be the immediate parent /* The DECL_TI_TEMPLATE should always be the immediate parent
template, not the most general template. */ template, not the most general template. */
...@@ -7955,7 +8034,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type, ...@@ -7955,7 +8034,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
int result; int result;
my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0); my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
fntype = TREE_TYPE (fn); fntype = TREE_TYPE (fn);
if (explicit_targs) if (explicit_targs)
{ {
...@@ -9977,6 +10056,7 @@ regenerate_decl_from_template (decl, tmpl) ...@@ -9977,6 +10056,7 @@ regenerate_decl_from_template (decl, tmpl)
instantiation of a specialization, which it isn't: it's a full instantiation of a specialization, which it isn't: it's a full
instantiation. */ instantiation. */
gen_tmpl = most_general_template (tmpl); gen_tmpl = most_general_template (tmpl);
push_access_scope_real (gen_tmpl, args, DECL_CONTEXT (decl));
unregistered = unregister_specialization (decl, gen_tmpl); unregistered = unregister_specialization (decl, gen_tmpl);
/* If the DECL was not unregistered then something peculiar is /* If the DECL was not unregistered then something peculiar is
...@@ -9984,12 +10064,6 @@ regenerate_decl_from_template (decl, tmpl) ...@@ -9984,12 +10064,6 @@ regenerate_decl_from_template (decl, tmpl)
register_specialization for it. */ register_specialization for it. */
my_friendly_assert (unregistered, 0); 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. */ /* Do the substitution to get the new declaration. */
new_decl = tsubst (code_pattern, args, tf_error, NULL_TREE); new_decl = tsubst (code_pattern, args, tf_error, NULL_TREE);
...@@ -10010,9 +10084,7 @@ regenerate_decl_from_template (decl, tmpl) ...@@ -10010,9 +10084,7 @@ regenerate_decl_from_template (decl, tmpl)
DECL_INITIAL (decl) = NULL_TREE; DECL_INITIAL (decl) = NULL_TREE;
} }
/* Pop the class context we pushed above. */ pop_access_scope (decl);
if (DECL_CLASS_SCOPE_P (decl))
pop_nested_class ();
/* The immediate parent of the new template is still whatever it was /* The immediate parent of the new template is still whatever it was
before, even though tsubst sets DECL_TI_TEMPLATE up as the most before, even though tsubst sets DECL_TI_TEMPLATE up as the most
...@@ -10218,9 +10290,9 @@ instantiate_decl (d, defer_ok) ...@@ -10218,9 +10290,9 @@ instantiate_decl (d, defer_ok)
tree type = TREE_TYPE (gen); tree type = TREE_TYPE (gen);
/* Make sure that we can see identifiers, and compute access /* Make sure that we can see identifiers, and compute access
correctly. */ correctly. D is already the target FUNCTION_DECL with the
if (DECL_CLASS_SCOPE_P (d)) right context. */
pushclass (DECL_CONTEXT (d), 1); push_access_scope (d);
if (TREE_CODE (gen) == FUNCTION_DECL) if (TREE_CODE (gen) == FUNCTION_DECL)
{ {
...@@ -10235,8 +10307,7 @@ instantiate_decl (d, defer_ok) ...@@ -10235,8 +10307,7 @@ instantiate_decl (d, defer_ok)
} }
tsubst (type, gen_args, tf_error | tf_warning, d); tsubst (type, gen_args, tf_error | tf_warning, d);
if (DECL_CLASS_SCOPE_P (d)) pop_access_scope (d);
popclass ();
} }
if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d) if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
...@@ -10597,8 +10668,7 @@ get_mostly_instantiated_function_type (decl) ...@@ -10597,8 +10668,7 @@ get_mostly_instantiated_function_type (decl)
partial substitution here. It depends only on outer template partial substitution here. It depends only on outer template
parameters, regardless of whether the innermost level is parameters, regardless of whether the innermost level is
specialized or not. */ specialized or not. */
if (DECL_CLASS_SCOPE_P (decl)) push_access_scope (decl);
pushclass (DECL_CONTEXT (decl), 1);
/* Now, do the (partial) substitution to figure out the /* Now, do the (partial) substitution to figure out the
appropriate function type. */ appropriate function type. */
...@@ -10611,8 +10681,7 @@ get_mostly_instantiated_function_type (decl) ...@@ -10611,8 +10681,7 @@ get_mostly_instantiated_function_type (decl)
TREE_VEC_LENGTH (partial_args)--; TREE_VEC_LENGTH (partial_args)--;
tparms = tsubst_template_parms (tparms, partial_args, tf_error); tparms = tsubst_template_parms (tparms, partial_args, tf_error);
if (DECL_CLASS_SCOPE_P (decl)) pop_access_scope (decl);
popclass ();
} }
return fn_type; return fn_type;
......
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> Wed Jan 8 11:41:47 CET 2003 Jan Hubicka <jh@suse.cz>
* gcc.dg/i386-cadd.c: New test. * gcc.dg/i386-cadd.c: New test.
......
// { 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>();
}
// { 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>();
}
...@@ -25,7 +25,7 @@ template<class T> void fnx(T *) throw(T){} // ERROR - invalid use of void expre ...@@ -25,7 +25,7 @@ template<class T> void fnx(T *) throw(T){} // ERROR - invalid use of void expre
void fx() void fx()
{ {
fnx((int *)0); 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 // [except.spec] 2, exception specifiers must be the same set of types (but
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment