mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-19 06:40:31 +08:00
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:
parent
c5e7ce43a5
commit
2b59fc25c6
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
127
gcc/cp/pt.c
127
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;
|
||||
|
@ -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.
|
||||
|
24
gcc/testsuite/g++.dg/template/friend12.C
Normal file
24
gcc/testsuite/g++.dg/template/friend12.C
Normal 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>();
|
||||
}
|
21
gcc/testsuite/g++.dg/template/friend13.C
Normal file
21
gcc/testsuite/g++.dg/template/friend13.C
Normal 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>();
|
||||
}
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user