Commit 25aab5d0 by Mark Mitchell Committed by Mark Mitchell

decl.c (xref_tag): Revise handling of nested template declarations.

	* decl.c (xref_tag): Revise handling of nested template
	declarations.
	* pt.c (check_explicit_specialization): Tweak handling of friend
	templates in template classes.
	(tsubst_friend_class): Handle friend declarations for nested
	member template classes.

From-SVN: r26520
parent 4e6a1440
1999-04-17 Mark Mitchell <mark@codesourcery.com>
* decl.c (xref_tag): Revise handling of nested template
declarations.
* pt.c (check_explicit_specialization): Tweak handling of friend
templates in template classes.
(tsubst_friend_class): Handle friend declarations for nested
member template classes.
1999-04-16 Mark Mitchell <mark@codesourcery.com> 1999-04-16 Mark Mitchell <mark@codesourcery.com>
* class.c (finish_struct): Remove unused variable. * class.c (finish_struct): Remove unused variable.
......
...@@ -12323,6 +12323,7 @@ xref_tag (code_type_node, name, globalize) ...@@ -12323,6 +12323,7 @@ xref_tag (code_type_node, name, globalize)
struct binding_level *b = current_binding_level; struct binding_level *b = current_binding_level;
int got_type = 0; int got_type = 0;
tree attributes = NULL_TREE; tree attributes = NULL_TREE;
tree context = NULL_TREE;
/* If we are called from the parser, code_type_node will sometimes be a /* If we are called from the parser, code_type_node will sometimes be a
TREE_LIST. This indicates that the user wrote TREE_LIST. This indicates that the user wrote
...@@ -12375,72 +12376,87 @@ xref_tag (code_type_node, name, globalize) ...@@ -12375,72 +12376,87 @@ xref_tag (code_type_node, name, globalize)
} }
else else
{ {
if (current_class_type if (t)
&& template_class_depth (current_class_type)
&& PROCESSING_REAL_TEMPLATE_DECL_P ())
/* Since GLOBALIZE is non-zero, we are not looking at a
definition of this tag. Since, in addition, we are currently
processing a (member) template declaration of a template
class, we don't want to do any lookup at all; consider:
template <class X>
struct S1
template <class U>
struct S2
{ template <class V>
friend struct S1; };
Here, the S2::S1 declaration should not be confused with the
outer declaration. In particular, the inner version should
have a template parameter of level 2, not level 1. This
would be particularly important if the member declaration
were instead:
template <class V = U> friend struct S1;
say, when we should tsubst into `U' when instantiating S2. */
ref = NULL_TREE;
else
{ {
if (t) /* [dcl.type.elab] If the identifier resolves to a
{ typedef-name or a template type-parameter, the
/* [dcl.type.elab] If the identifier resolves to a elaborated-type-specifier is ill-formed. */
typedef-name or a template type-parameter, the if (t != TYPE_MAIN_VARIANT (t)
elaborated-type-specifier is ill-formed. */ || (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t)))
if (t != TYPE_MAIN_VARIANT (t) cp_pedwarn ("using typedef-name `%D' after `%s'",
|| (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t))) TYPE_NAME (t), tag_name (tag_code));
cp_pedwarn ("using typedef-name `%D' after `%s'", else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
TYPE_NAME (t), tag_name (tag_code)); cp_error ("using template type parameter `%T' after `%s'",
else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) t, tag_name (tag_code));
cp_error ("using template type parameter `%T' after `%s'",
t, tag_name (tag_code)); ref = t;
}
ref = t; else
} ref = lookup_tag (code, name, b, 0);
else
ref = lookup_tag (code, name, b, 0);
if (! ref) if (! ref)
{ {
/* Try finding it as a type declaration. If that wins, /* Try finding it as a type declaration. If that wins,
use it. */ use it. */
ref = lookup_name (name, 1); ref = lookup_name (name, 1);
if (ref != NULL_TREE if (ref != NULL_TREE
&& processing_template_decl && processing_template_decl
&& DECL_CLASS_TEMPLATE_P (ref) && DECL_CLASS_TEMPLATE_P (ref)
&& template_class_depth (current_class_type) == 0) && template_class_depth (current_class_type) == 0)
/* Since GLOBALIZE is true, we're declaring a global /* Since GLOBALIZE is true, we're declaring a global
template, so we want this type. */ template, so we want this type. */
ref = DECL_RESULT (ref); ref = DECL_RESULT (ref);
if (ref && TREE_CODE (ref) == TYPE_DECL if (ref && TREE_CODE (ref) == TYPE_DECL
&& TREE_CODE (TREE_TYPE (ref)) == code) && TREE_CODE (TREE_TYPE (ref)) == code)
ref = TREE_TYPE (ref); ref = TREE_TYPE (ref);
else else
ref = NULL_TREE; ref = NULL_TREE;
} }
if (ref && current_class_type
&& template_class_depth (current_class_type)
&& PROCESSING_REAL_TEMPLATE_DECL_P ())
{
/* Since GLOBALIZE is non-zero, we are not looking at a
definition of this tag. Since, in addition, we are currently
processing a (member) template declaration of a template
class, we must be very careful; consider:
template <class X>
struct S1
template <class U>
struct S2
{ template <class V>
friend struct S1; };
Here, the S2::S1 declaration should not be confused with the
outer declaration. In particular, the inner version should
have a template parameter of level 2, not level 1. This
would be particularly important if the member declaration
were instead:
template <class V = U> friend struct S1;
say, when we should tsubst into `U' when instantiating
S2. On the other hand, when presented with:
template <class T>
struct S1 {
template <class U>
struct S2 {};
template <class U>
friend struct S2;
};
we must find the inner binding eventually. We
accomplish this by making sure that the new type we
create to represent this declaration has the right
TYPE_CONTEXT. */
context = TYPE_CONTEXT (ref);
ref = NULL_TREE;
} }
} }
...@@ -12487,6 +12503,7 @@ xref_tag (code_type_node, name, globalize) ...@@ -12487,6 +12503,7 @@ xref_tag (code_type_node, name, globalize)
struct binding_level *old_b = class_binding_level; struct binding_level *old_b = class_binding_level;
ref = make_lang_type (code); ref = make_lang_type (code);
TYPE_CONTEXT (ref) = context;
if (tag_code == signature_type) if (tag_code == signature_type)
{ {
......
...@@ -1281,7 +1281,6 @@ check_explicit_specialization (declarator, decl, template_count, flags) ...@@ -1281,7 +1281,6 @@ check_explicit_specialization (declarator, decl, template_count, flags)
if (specialization || member_specialization || explicit_instantiation) if (specialization || member_specialization || explicit_instantiation)
{ {
tree gen_tmpl;
tree tmpl = NULL_TREE; tree tmpl = NULL_TREE;
tree targs = NULL_TREE; tree targs = NULL_TREE;
...@@ -1435,13 +1434,34 @@ check_explicit_specialization (declarator, decl, template_count, flags) ...@@ -1435,13 +1434,34 @@ check_explicit_specialization (declarator, decl, template_count, flags)
return error_mark_node; return error_mark_node;
else else
{ {
gen_tmpl = most_general_template (tmpl); tree gen_tmpl = most_general_template (tmpl);
if (explicit_instantiation) if (explicit_instantiation)
{ {
/* We don't set DECL_EXPLICIT_INSTANTIATION here; that /* We don't set DECL_EXPLICIT_INSTANTIATION here; that
is done by do_decl_instantiation later. */ is done by do_decl_instantiation later. */
decl = instantiate_template (tmpl, innermost_args (targs));
int arg_depth = TMPL_ARGS_DEPTH (targs);
int parm_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
if (arg_depth > parm_depth)
{
/* If TMPL is not the most general template (for
example, if TMPL is a friend template that is
injected into namespace scope), then there will
be too many levels fo TARGS. Remove some of them
here. */
int i;
tree new_targs;
new_targs = make_temp_vec (parm_depth);
for (i = arg_depth - parm_depth; i < arg_depth; ++i)
TREE_VEC_ELT (new_targs, i - (arg_depth - parm_depth))
= TREE_VEC_ELT (targs, i);
targs = new_targs;
}
decl = instantiate_template (tmpl, targs);
return decl; return decl;
} }
...@@ -4583,11 +4603,29 @@ tsubst_friend_class (friend_tmpl, args) ...@@ -4583,11 +4603,29 @@ tsubst_friend_class (friend_tmpl, args)
tree args; tree args;
{ {
tree friend_type; tree friend_type;
tree tmpl = lookup_name (DECL_NAME (friend_tmpl), 1); tree tmpl;
tmpl = maybe_get_template_decl_from_type_decl (tmpl); /* First, we look for a class template. */
tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/0);
/* But, if we don't find one, it might be because we're in a
situation like this:
template <class T>
struct S {
template <class U>
friend struct S;
};
Here, in the scope of (say) S<int>, `S' is bound to a TYPE_DECL
for `S<int>', not the TEMPLATE_DECL. */
if (!DECL_CLASS_TEMPLATE_P (tmpl))
{
tmpl = lookup_name (DECL_NAME (friend_tmpl), /*prefer_type=*/1);
tmpl = maybe_get_template_decl_from_type_decl (tmpl);
}
if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl)) if (tmpl && DECL_CLASS_TEMPLATE_P (tmpl))
{ {
/* The friend template has already been declared. Just /* The friend template has already been declared. Just
check to see that the declarations match, and install any new check to see that the declarations match, and install any new
......
// Build don't link:
// Origin: Mark Mitchell <mark@codesourcery.com>
template <class T>
class S {
public:
template <class U>
class C {
public:
void f() { S::i = 3; }
};
template <class U>
friend class C;
private:
static int i;
};
template void S<int>::C<double>::f();
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