mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-04 01:30:02 +08:00
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
This commit is contained in:
parent
4e6a144034
commit
25aab5d0ad
@ -1,3 +1,12 @@
|
||||
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>
|
||||
|
||||
* class.c (finish_struct): Remove unused variable.
|
||||
|
137
gcc/cp/decl.c
137
gcc/cp/decl.c
@ -12323,6 +12323,7 @@ xref_tag (code_type_node, name, globalize)
|
||||
struct binding_level *b = current_binding_level;
|
||||
int got_type = 0;
|
||||
tree attributes = NULL_TREE;
|
||||
tree context = NULL_TREE;
|
||||
|
||||
/* If we are called from the parser, code_type_node will sometimes be a
|
||||
TREE_LIST. This indicates that the user wrote
|
||||
@ -12375,72 +12376,87 @@ xref_tag (code_type_node, name, globalize)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (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 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)
|
||||
{
|
||||
if (t)
|
||||
{
|
||||
/* [dcl.type.elab] If the identifier resolves to a
|
||||
typedef-name or a template type-parameter, the
|
||||
elaborated-type-specifier is ill-formed. */
|
||||
if (t != TYPE_MAIN_VARIANT (t)
|
||||
|| (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t)))
|
||||
cp_pedwarn ("using typedef-name `%D' after `%s'",
|
||||
TYPE_NAME (t), tag_name (tag_code));
|
||||
else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
|
||||
cp_error ("using template type parameter `%T' after `%s'",
|
||||
t, tag_name (tag_code));
|
||||
/* [dcl.type.elab] If the identifier resolves to a
|
||||
typedef-name or a template type-parameter, the
|
||||
elaborated-type-specifier is ill-formed. */
|
||||
if (t != TYPE_MAIN_VARIANT (t)
|
||||
|| (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t)))
|
||||
cp_pedwarn ("using typedef-name `%D' after `%s'",
|
||||
TYPE_NAME (t), tag_name (tag_code));
|
||||
else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
|
||||
cp_error ("using template type parameter `%T' after `%s'",
|
||||
t, tag_name (tag_code));
|
||||
|
||||
ref = t;
|
||||
}
|
||||
else
|
||||
ref = lookup_tag (code, name, b, 0);
|
||||
ref = t;
|
||||
}
|
||||
else
|
||||
ref = lookup_tag (code, name, b, 0);
|
||||
|
||||
if (! ref)
|
||||
{
|
||||
/* Try finding it as a type declaration. If that wins,
|
||||
use it. */
|
||||
ref = lookup_name (name, 1);
|
||||
if (! ref)
|
||||
{
|
||||
/* Try finding it as a type declaration. If that wins,
|
||||
use it. */
|
||||
ref = lookup_name (name, 1);
|
||||
|
||||
if (ref != NULL_TREE
|
||||
&& processing_template_decl
|
||||
&& DECL_CLASS_TEMPLATE_P (ref)
|
||||
&& template_class_depth (current_class_type) == 0)
|
||||
/* Since GLOBALIZE is true, we're declaring a global
|
||||
if (ref != NULL_TREE
|
||||
&& processing_template_decl
|
||||
&& DECL_CLASS_TEMPLATE_P (ref)
|
||||
&& template_class_depth (current_class_type) == 0)
|
||||
/* Since GLOBALIZE is true, we're declaring a global
|
||||
template, so we want this type. */
|
||||
ref = DECL_RESULT (ref);
|
||||
ref = DECL_RESULT (ref);
|
||||
|
||||
if (ref && TREE_CODE (ref) == TYPE_DECL
|
||||
&& TREE_CODE (TREE_TYPE (ref)) == code)
|
||||
ref = TREE_TYPE (ref);
|
||||
else
|
||||
ref = NULL_TREE;
|
||||
}
|
||||
if (ref && TREE_CODE (ref) == TYPE_DECL
|
||||
&& TREE_CODE (TREE_TYPE (ref)) == code)
|
||||
ref = TREE_TYPE (ref);
|
||||
else
|
||||
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)
|
||||
struct binding_level *old_b = class_binding_level;
|
||||
|
||||
ref = make_lang_type (code);
|
||||
TYPE_CONTEXT (ref) = context;
|
||||
|
||||
if (tag_code == signature_type)
|
||||
{
|
||||
|
52
gcc/cp/pt.c
52
gcc/cp/pt.c
@ -1281,7 +1281,6 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
||||
|
||||
if (specialization || member_specialization || explicit_instantiation)
|
||||
{
|
||||
tree gen_tmpl;
|
||||
tree tmpl = NULL_TREE;
|
||||
tree targs = NULL_TREE;
|
||||
|
||||
@ -1435,13 +1434,34 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
||||
return error_mark_node;
|
||||
else
|
||||
{
|
||||
gen_tmpl = most_general_template (tmpl);
|
||||
tree gen_tmpl = most_general_template (tmpl);
|
||||
|
||||
if (explicit_instantiation)
|
||||
{
|
||||
/* We don't set DECL_EXPLICIT_INSTANTIATION here; that
|
||||
is done by do_decl_instantiation later. */
|
||||
decl = instantiate_template (tmpl, innermost_args (targs));
|
||||
is done by do_decl_instantiation later. */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4583,11 +4603,29 @@ tsubst_friend_class (friend_tmpl, args)
|
||||
tree args;
|
||||
{
|
||||
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:
|
||||
|
||||
if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl))
|
||||
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 && DECL_CLASS_TEMPLATE_P (tmpl))
|
||||
{
|
||||
/* The friend template has already been declared. Just
|
||||
check to see that the declarations match, and install any new
|
||||
|
21
gcc/testsuite/g++.old-deja/g++.pt/friend41.C
Normal file
21
gcc/testsuite/g++.old-deja/g++.pt/friend41.C
Normal file
@ -0,0 +1,21 @@
|
||||
// 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();
|
Loading…
Reference in New Issue
Block a user