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
This commit is contained in:
Kriang Lerdsuwanakij 2003-01-08 14:42:39 +00:00 committed by Kriang Lerdsuwanakij
parent c5e7ce43a5
commit 2b59fc25c6
7 changed files with 187 additions and 42 deletions

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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.

View File

@ -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>();
}

View File

@ -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>();
}

View File

@ -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