cp-tree.h (CLASSTYPE_IS_TEMPLATE): New macro.

* cp-tree.h (CLASSTYPE_IS_TEMPLATE): New macro.
	(DECL_CLASS_TEMPLATE_P): Likewise.
	(DECL_PRIMARY_TEMPLATE): Likewise.
	(PRIMARY_TEMPLATE_P): Use it.
	(push_template_decl_real): New function.
	(redeclare_class_template): Take new template parameters as
	input.
	(is_specialization_of): New function.
	(comp_template_args): Declare.
	* decl.c (pushtag): Handle friend template classes.
	(xref_tag): Likewise.  Use new calling convention for
	redeclare_class_template.
	* decl2.c (grok_x_components): Handle friend templates.
	* friend.c (is_friend): Use is_specialization_of where
	appropriate.  Deal with friend class templates.
	(make_friend_class): Let a class template be friends with itself.
	* pt.c (comp_template_args): Remove declaration.
	(tsubst_friend_class): New function.
	(push_template_decl_real): New function.
	(push_template_decl): Use it.
	(redeclare_class_template): Adjust for new calling convention.
	(comp_template_args): Give it external linkage.
	(instantiate_class_type): Use tsubst_friend_class to deal
	with friend templates.
	* typeck.c (comptypes): Use comp_template_args, rather than
	expanding it inline.
	* parse.y (component_decl): Handle a nested template type
	like other component type declarations.

From-SVN: r19418
This commit is contained in:
Mark Mitchell 1998-04-26 16:30:11 +00:00 committed by Mark Mitchell
parent 7bf407413f
commit 6757edfe65
15 changed files with 786 additions and 417 deletions

View File

@ -1,5 +1,34 @@
Sun Apr 26 12:10:18 1998 Mark Mitchell <mmitchell@usa.net>
* cp-tree.h (CLASSTYPE_IS_TEMPLATE): New macro.
(DECL_CLASS_TEMPLATE_P): Likewise.
(DECL_PRIMARY_TEMPLATE): Likewise.
(PRIMARY_TEMPLATE_P): Use it.
(push_template_decl_real): New function.
(redeclare_class_template): Take new template parameters as
input.
(is_specialization_of): New function.
(comp_template_args): Declare.
* decl.c (pushtag): Handle friend template classes.
(xref_tag): Likewise. Use new calling convention for
redeclare_class_template.
* decl2.c (grok_x_components): Handle friend templates.
* friend.c (is_friend): Use is_specialization_of where
appropriate. Deal with friend class templates.
(make_friend_class): Let a class template be friends with itself.
* pt.c (comp_template_args): Remove declaration.
(tsubst_friend_class): New function.
(push_template_decl_real): New function.
(push_template_decl): Use it.
(redeclare_class_template): Adjust for new calling convention.
(comp_template_args): Give it external linkage.
(instantiate_class_type): Use tsubst_friend_class to deal
with friend templates.
* typeck.c (comptypes): Use comp_template_args, rather than
expanding it inline.
* parse.y (component_decl): Handle a nested template type
like other component type declarations.
* pt.c (check_explicit_specialization): Handle overloaded
constructors correctly.

View File

@ -1139,6 +1139,15 @@ struct lang_decl
#define DELETE_EXPR_USE_VEC(NODE) TREE_LANG_FLAG_1 (NODE)
#define LOOKUP_EXPR_GLOBAL(NODE) TREE_LANG_FLAG_0 (NODE)
/* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a
TEMPLATE_DECL. This macro determines whether or not a given class
type is really a template type, as opposed to an instantiation or
specialization of one. */
#define CLASSTYPE_IS_TEMPLATE(NODE) \
(CLASSTYPE_TEMPLATE_INFO (NODE) \
&& !CLASSTYPE_USE_TEMPLATE (NODE) \
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE)))
#define TYPENAME_TYPE_FULLNAME(NODE) CLASSTYPE_SIZE (NODE)
/* Nonzero in INT_CST means that this int is negative by dint of
@ -1412,11 +1421,22 @@ extern int flag_new_for_scope;
(TREE_CODE (NODE) == TEMPLATE_DECL \
&& TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
/* Nonzero for a DECL that represents a template class. */
#define DECL_CLASS_TEMPLATE_P(NODE) \
(TREE_CODE (NODE) == TEMPLATE_DECL \
&& TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL \
&& !DECL_TEMPLATE_TEMPLATE_PARM_P (NODE))
/* A `primary' template is one that has its own template header. A
member function of a class template is a template, but not primary.
A member template is primary. */
#define PRIMARY_TEMPLATE_P(NODE) \
(TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)) == (NODE))
A member template is primary. Friend templates are primary, too. */
/* Returns the primary template corresponding to these parameters. */
#define DECL_PRIMARY_TEMPLATE(NODE) \
(TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)))
/* Returns non-zero if NODE is a primary template. */
#define PRIMARY_TEMPLATE_P(NODE) (DECL_PRIMARY_TEMPLATE (NODE) == NODE)
#define CLASSTYPE_TEMPLATE_LEVEL(NODE) \
(TREE_INT_CST_HIGH (TREE_PURPOSE (CLASSTYPE_TI_TEMPLATE (NODE))))
@ -2435,7 +2455,8 @@ extern tree end_template_parm_list PROTO((tree));
extern void end_template_decl PROTO((void));
extern tree current_template_args PROTO((void));
extern tree push_template_decl PROTO((tree));
extern void redeclare_class_template PROTO((tree));
extern tree push_template_decl_real PROTO((tree, int));
extern void redeclare_class_template PROTO((tree, tree));
extern tree lookup_template_class PROTO((tree, tree, tree, tree));
extern tree lookup_template_function PROTO((tree, tree));
extern int uses_template_parms PROTO((tree));
@ -2467,6 +2488,9 @@ extern void do_pushlevel PROTO((void));
extern int is_member_template PROTO((tree));
extern int comp_template_parms PROTO((tree, tree));
extern int template_class_depth PROTO((tree));
extern int is_specialization_of PROTO((tree, tree));
extern int comp_template_args PROTO((tree, tree));
extern int processing_specialization;
extern int processing_explicit_instantiation;

View File

@ -2157,7 +2157,7 @@ pop_everything ()
}
/* Push a tag name NAME for struct/class/union/enum type TYPE.
Normally put into into the inner-most non-tag-transparent scope,
Normally put it into the inner-most non-tag-transparent scope,
but if GLOBALIZE is true, put it in the inner-most non-class scope.
The latter is needed for implicit declarations. */
@ -2226,11 +2226,52 @@ pushtag (name, type, globalize)
TYPE_NAME (type) = d;
DECL_CONTEXT (d) = context;
if (! globalize && processing_template_decl
&& IS_AGGR_TYPE (type))
if (IS_AGGR_TYPE (type)
&& (/* If !GLOBALIZE then we are looking at a
definition. */
(processing_template_decl && !globalize)
/* This next condition is tricky. If we are
declaring a friend template class, we will have
GLOBALIZE set, since something like:
template <class T>
struct S1 {
template <class U>
friend class S2;
};
declares S2 to be at global scope. The condition
says that we are looking at a primary template
that is being declared in class scope. We can't
just drop the `in class scope' and then not check
GLOBALIZE either since on this code:
template <class T>
struct S1 {};
template <class T>
struct S2 { S1<T> f(); }
we get called by lookup_template_class (with TYPE
set to S1<T> and GLOBALIZE set to 1). However,
lookup_template_class calls
maybe_push_to_top_level which doesn't clear
processing_template_decl, so we would then
incorrectly call push_template_decl. */
|| (current_class_type != NULL_TREE
&& (processing_template_decl >
template_class_depth (current_class_type)))))
{
d = push_template_decl (d);
if (b->pseudo_global && b->level_chain->parm_flag == 2)
d = push_template_decl_real (d, globalize);
/* If the current binding level is the binding level for
the template parameters (see the comment in
begin_template_parm_list) and the enclosing level is
a class scope, and we're not looking at a friend,
push the declaration of the member class into the
class scope. In the friend case, push_template_decl
will already have put the friend into global scope,
if appropriate. */
if (!globalize && b->pseudo_global &&
b->level_chain->parm_flag == 2)
pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
b->level_chain);
}
@ -10812,6 +10853,15 @@ xref_tag (code_type_node, name, binfo, globalize)
{
/* 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
template, so we want this type. */
ref = DECL_RESULT (ref);
if (ref && TREE_CODE (ref) == TYPE_DECL
&& TREE_CODE (TREE_TYPE (ref)) == code)
ref = TREE_TYPE (ref);
@ -10898,7 +10948,7 @@ xref_tag (code_type_node, name, binfo, globalize)
}
if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref))
redeclare_class_template (ref);
redeclare_class_template (ref, current_template_parms);
}
if (binfo)

View File

@ -870,8 +870,16 @@ grok_x_components (specs, components)
tcode = class_type_node;
else if (IS_SIGNATURE (t))
tcode = signature_type_node;
t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
if (CLASSTYPE_IS_TEMPLATE (t))
/* In this case, the TYPE_IDENTIFIER will be something
like S<T>, rather than S, so to get the correct name we
look at the template. */
x = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
else
x = TYPE_IDENTIFIER (t);
t = xref_tag (tcode, x, NULL_TREE, 0);
return NULL_TREE;
break;

View File

@ -71,25 +71,17 @@ is_friend (type, supplicant)
if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL)
{
tree t;
/* Perhaps this function is a specialization of
a friend template. */
for (t = supplicant;
t != NULL_TREE;
t = DECL_TEMPLATE_INFO (t) ?
DECL_TI_TEMPLATE (t) : NULL_TREE)
/* FIXME: The use of comptypes here, and below, is
bogus, since two specializations of a
template parameter with non-type parameters
may have the same type, but be different. */
if (comptypes (TREE_TYPE (t),
TREE_TYPE (TREE_VALUE (friends)), 1))
return 1;
if (is_specialization_of (supplicant,
TREE_VALUE (friends)))
return 1;
continue;
}
/* FIXME: The use of comptypes here is bogus, since
two specializations of a template with non-type
parameters may have the same type, but be
different. */
if (comptypes (TREE_TYPE (supplicant),
TREE_TYPE (TREE_VALUE (friends)), 1))
return 1;
@ -106,8 +98,15 @@ is_friend (type, supplicant)
list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type)));
for (; list ; list = TREE_CHAIN (list))
if (supplicant == TREE_VALUE (list))
return 1;
{
tree t = TREE_VALUE (list);
if (supplicant == t
|| (CLASSTYPE_IS_TEMPLATE (t)
&& is_specialization_of (TYPE_MAIN_DECL (supplicant),
CLASSTYPE_TI_TEMPLATE (t))))
return 1;
}
}
if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
@ -249,7 +248,10 @@ make_friend_class (type, friend_type)
IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type)));
return;
}
if (type == friend_type)
/* If the TYPE is a template then it makes sense for it to be
friends with itself; this means that each instantiation is
friends with all other instantiations. */
if (type == friend_type && !CLASSTYPE_IS_TEMPLATE (type))
{
pedwarn ("class `%s' is implicitly friends with itself",
TYPE_NAME_STRING (type));

File diff suppressed because it is too large Load Diff

View File

@ -2498,8 +2498,12 @@ component_decl:
{ $$ = finish_member_template_decl ($1, $2); }
| template_header typed_declspecs ';'
{
shadow_tag ($2.t);
note_list_got_semicolon ($2.t);
grok_x_components ($2.t, NULL_TREE);
if (TYPE_CONTEXT (TREE_VALUE ($2.t)) != current_class_type)
/* The component was in fact a friend
declaration. */
$2.t = NULL_TREE;
$$ = finish_member_template_decl ($1, $2.t);
}
;

View File

@ -75,7 +75,6 @@ static int push_tinst_level PROTO((tree));
static tree classtype_mangled_name PROTO((tree));
static char *mangle_class_name_for_template PROTO((char *, tree, tree, tree));
static tree tsubst_expr_values PROTO((tree, tree));
static int comp_template_args PROTO((tree, tree));
static int list_eq PROTO((tree, tree));
static tree get_class_bindings PROTO((tree, tree, tree, tree));
static tree coerce_template_parms PROTO((tree, tree, tree, int, int, int));
@ -100,6 +99,7 @@ static tree reduce_template_parm_level PROTO((tree, tree, int));
static tree build_template_decl PROTO((tree, tree));
static int mark_template_parm PROTO((tree, void *));
static tree tsubst_friend_function PROTO((tree, tree));
static tree tsubst_friend_class PROTO((tree, tree));
static tree get_bindings_real PROTO((tree, tree, tree, int));
static int template_decl_level PROTO((tree));
static tree maybe_get_template_decl_from_type_decl PROTO((tree));
@ -489,13 +489,26 @@ add_to_template_args (args, extra_args)
void
begin_template_parm_list ()
{
/* We use a non-tag-transparent scope here, which causes pushtag to
put tags in this scope, rather than in the enclosing class or
namespace scope. This is the right thing, since we want
TEMPLATE_DECLS, and not TYPE_DECLS for template classes. For a
global template class, push_template_decl handles putting the
TEMPLATE_DECL into top-level scope. For a nested template class,
e.g.:
template <class T> struct S1 {
template <class T> struct S2 {};
};
pushtag contains special code to call pushdecl_with_scope on the
TEMPLATE_DECL for S2. */
pushlevel (0);
declare_pseudo_global_level ();
++processing_template_decl;
note_template_header (0);
}
/* We've just seen template <>. */
void
@ -504,7 +517,6 @@ begin_specialization ()
note_template_header (1);
}
/* Called at then end of processing a declaration preceeded by
template<>. */
@ -514,7 +526,6 @@ end_specialization ()
reset_specialization ();
}
/* Any template <>'s that we have seen thus far are not referring to a
function specialization. */
@ -525,7 +536,6 @@ reset_specialization ()
template_header_count = 0;
}
/* We've just seen a template header. If SPECIALIZATION is non-zero,
it was of the form template <>. */
@ -537,7 +547,6 @@ note_template_header (specialization)
template_header_count++;
}
/* We're beginning an explicit instantiation. */
void
@ -554,7 +563,6 @@ end_explicit_instantiation ()
--processing_explicit_instantiation;
}
/* Retrieve the specialization (in the sense of [temp.spec] - a
specialization is either an instantiation or an explicit
specialization) of TMPL for the given template ARGS. If there is
@ -580,7 +588,38 @@ retrieve_specialization (tmpl, args)
return NULL_TREE;
}
/* Returns non-zero iff DECL is a specialization of TMPL. */
int
is_specialization_of (decl, tmpl)
tree decl;
tree tmpl;
{
tree t;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
for (t = decl;
t != NULL_TREE;
t = DECL_TEMPLATE_INFO (t) ? DECL_TI_TEMPLATE (t) : NULL_TREE)
if (t == tmpl)
return 1;
}
else
{
my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 0);
for (t = TREE_TYPE (decl);
t != NULL_TREE;
t = CLASSTYPE_USE_TEMPLATE (t)
? TREE_TYPE (CLASSTYPE_TI_TEMPLATE (t)) : NULL_TREE)
if (comptypes (TYPE_MAIN_VARIANT (t),
TYPE_MAIN_VARIANT (TREE_TYPE (tmpl)), 1))
return 1;
}
return 0;
}
/* Register the specialization SPEC as a specialization of TMPL with
the indicated ARGS. */
@ -649,7 +688,6 @@ register_specialization (spec, tmpl, args)
= perm_tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
}
/* Print the list of candidate FNS in an error message. */
static void
@ -786,8 +824,7 @@ determine_specialization (template_id, decl, targs_out,
*targs_out = TREE_PURPOSE (templates);
return TREE_VALUE (templates);
}
/* Check to see if the function just declared, as indicated in
DECLARATOR, and in DECL, is a specialization of a function
template. We may also discover that the declaration is an explicit
@ -1160,7 +1197,6 @@ check_explicit_specialization (declarator, decl, template_count, flags)
return decl;
}
/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
parameters. These are represented in the same format used for
DECL_TEMPLATE_PARMS. */
@ -1213,7 +1249,6 @@ int comp_template_parms (parms1, parms2)
return 1;
}
/* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
ORIG_LEVEL, DECL, and TYPE. */
@ -1235,7 +1270,6 @@ build_template_parm_index (index, level, orig_level, decl, type)
return t;
}
/* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
TEMPLATE_PARM_LEVEL has been decreased by LEVELS. If such a
TEMPLATE_PARM_INDEX already exists, it is returned; otherwise, a
@ -1520,19 +1554,22 @@ mark_template_parm (t, data)
/* Creates a TEMPLATE_DECL for the indicated DECL using the template
parameters given by current_template_args, or reuses a
previously existing one, if appropriate. Returns the DECL, or an
equivalent one, if it is replaced via a call to duplicate_decls. */
equivalent one, if it is replaced via a call to duplicate_decls.
If IS_FRIEND is non-zero, DECL is a friend declaration. */
tree
push_template_decl (decl)
push_template_decl_real (decl, is_friend)
tree decl;
int is_friend;
{
tree tmpl;
tree args;
tree info;
tree ctx;
int primary;
int is_friend = (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_FRIEND_P (decl));
is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
if (is_friend)
/* For a friend, we want the context of the friend function, not
@ -1550,16 +1587,17 @@ push_template_decl (decl)
/* For determining whether this is a primary template or not, we're really
interested in the lexical context, not the true context. */
if (is_friend)
info = DECL_CLASS_CONTEXT (decl);
/* For a TYPE_DECL, there is no DECL_CLASS_CONTEXT. */
info = TREE_CODE (decl) == FUNCTION_DECL
? DECL_CLASS_CONTEXT (decl) : current_class_type;
else
info = ctx;
if (info && TREE_CODE (info) == FUNCTION_DECL)
primary = 0;
else if (! info
|| (TYPE_BEING_DEFINED (info) && template_header_count
&& ! processing_specialization)
|| (template_header_count > template_class_depth (info)))
/* Note that template_class_depth returns 0 if given NULL_TREE, so
this next line works even when we are at global scope. */
else if (processing_template_decl > template_class_depth (info))
primary = 1;
else
primary = 0;
@ -1775,14 +1813,14 @@ push_template_decl (decl)
DECL_TEMPLATE_RESULT (tmpl) = decl;
TREE_TYPE (tmpl) = TREE_TYPE (decl);
if (! ctx && primary)
/* The check of PRIMARY ensures that we do not try to push a
global template friend declared in a template class; such a
thing may well depend on the template parameters of the class. */
if (! ctx && !(is_friend && template_class_depth (info) > 0))
/* Note that we do not try to push a global template friend
declared in a template class; such a thing may well depend on
the template parameters of the class. */
tmpl = pushdecl_top_level (tmpl);
if (primary)
TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (tmpl)) = tmpl;
DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
info = perm_tree_cons (tmpl, args, NULL_TREE);
@ -1800,18 +1838,26 @@ push_template_decl (decl)
return DECL_TEMPLATE_RESULT (tmpl);
}
/* Called when a class template TYPE is redeclared, e.g.:
tree
push_template_decl (decl)
tree decl;
{
return push_template_decl_real (decl, 0);
}
/* Called when a class template TYPE is redeclared with the indicated
template PARMS, e.g.:
template <class T> struct S;
template <class T> struct S {}; */
void
redeclare_class_template (type)
redeclare_class_template (type, parms)
tree type;
tree parms;
{
tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
tree tmpl_parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
tree parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
tree tmpl_parms;
int i;
if (!PRIMARY_TEMPLATE_P (tmpl))
@ -1820,6 +1866,9 @@ redeclare_class_template (type)
type. */
return;
parms = INNERMOST_TEMPLATE_PARMS (parms);
tmpl_parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
if (TREE_VEC_LENGTH (parms) != TREE_VEC_LENGTH (tmpl_parms))
{
cp_error_at ("previous declaration `%D'", tmpl);
@ -2484,7 +2533,7 @@ coerce_template_parms (parms, arglist, in_decl,
/* Renturns 1 iff the OLDARGS and NEWARGS are in fact identical sets
of template arguments. Returns 0 otherwise. */
static int
int
comp_template_args (oldargs, newargs)
tree oldargs, newargs;
{
@ -3251,7 +3300,6 @@ tinst_for_decl ()
return p;
}
/* DECL is a friend FUNCTION_DECL or TEMPLATE_DECL. ARGS is the
vector of template arguments, as for tsubst.
@ -3340,6 +3388,51 @@ tsubst_friend_function (decl, args)
return new_friend;
}
/* FRIEND_TYPE is a friend RECORD_TYPE or UNION_TYPE. ARGS is the
vector of template arguments, as for tsubst.
Returns an appropriate tsbust'd friend type. */
static tree
tsubst_friend_class (friend_type, args)
tree friend_type;
tree args;
{
tree tmpl =
lookup_name (DECL_NAME (CLASSTYPE_TI_TEMPLATE (friend_type)), 1);
tmpl = maybe_get_template_decl_from_type_decl (tmpl);
if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl))
{
/* The friend template has already been declared. Just
check to see that the declarations match. */
redeclare_class_template (TREE_TYPE (tmpl),
DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE
(friend_type)));
friend_type = TREE_TYPE (tmpl);
}
else
{
/* The friend template has not already been declared. In this
case, the instantiation of the template class will cause the
injection of this template into the global scope. */
tmpl = tsubst (CLASSTYPE_TI_TEMPLATE (friend_type), args, NULL_TREE);
/* The new TMPL is not an instantiation of anything, so we
forget its origins. We don't reset CLASSTYPE_TI_TEMPLATE for
the new type because that is supposed to be the corresponding
template decl, i.e., TMPL. */
DECL_USE_TEMPLATE (tmpl) = 0;
DECL_TEMPLATE_INFO (tmpl) = NULL_TREE;
CLASSTYPE_USE_TEMPLATE (TREE_TYPE (tmpl)) = 0;
/* Inject this template into the global scope. */
friend_type = TREE_TYPE (pushdecl_top_level (tmpl));
}
return friend_type;
}
tree
instantiate_class_template (type)
@ -3604,12 +3697,25 @@ instantiate_class_template (type)
}
}
t = CLASSTYPE_FRIEND_CLASSES (type)
= tsubst (CLASSTYPE_FRIEND_CLASSES (pattern), args, NULL_TREE);
for (t = CLASSTYPE_FRIEND_CLASSES (pattern);
t != NULL_TREE;
t = TREE_CHAIN (t))
{
tree friend_type = TREE_VALUE (t);
/* This does injection for friend classes. */
for (; t; t = TREE_CHAIN (t))
TREE_VALUE (t) = xref_tag_from_type (TREE_VALUE (t), NULL_TREE, 1);
if (!CLASSTYPE_IS_TEMPLATE (friend_type))
/* The call to xref_tag_from_type does injection for friend
classes. */
friend_type =
xref_tag_from_type (tsubst (friend_type, args, NULL_TREE),
NULL_TREE, 1);
else
friend_type = tsubst_friend_class (friend_type, args);
CLASSTYPE_FRIEND_CLASSES (type) =
tree_cons (NULL_TREE, friend_type,
CLASSTYPE_FRIEND_CLASSES (type));
}
/* This does injection for friend functions. */
if (!processing_template_decl)

View File

@ -763,26 +763,8 @@ comptypes (type1, type2, strict)
if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2)
&& (CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2)
|| TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM))
{
int i = TREE_VEC_LENGTH (CLASSTYPE_TI_ARGS (t1));
tree *p1 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t1), 0);
tree *p2 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t2), 0);
while (i--)
{
if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't')
{
if (! comptypes (p1[i], p2[i], 1))
return 0;
}
else
{
if (simple_cst_equal (p1[i], p2[i]) <= 0)
return 0;
}
}
return 1;
}
return comp_template_args (CLASSTYPE_TI_ARGS (t1),
CLASSTYPE_TI_ARGS (t2));
if (strict <= 0)
goto look_hard;
return 0;

View File

@ -0,0 +1,25 @@
// Build don't link:
template <class U>
class S1
{
template <class T>
friend class S2;
static int i;
};
template <class T>
class S2
{
public:
static void f() { S1<T>::i = 3; }
};
void g()
{
S2<double>::f();
S2<long>::f();
}

View File

@ -0,0 +1,24 @@
// Build don't link:
class S1
{
template <class T>
friend class S2;
static int i;
};
template <class T>
class S2
{
public:
static void f() { S1::i = 3; }
};
void g()
{
S2<double>::f();
S2<char>::f();
}

View File

@ -0,0 +1,31 @@
// Build don't link:
template <class T>
class S2
{
public:
static void f();
};
template <class U>
class S1
{
template <class T>
friend class S2;
static int i;
};
template <class T>
void S2<T>::f()
{
S1<T>::i = 3;
}
void g()
{
S2<double>::f();
S2<char>::f();
}

View File

@ -0,0 +1,28 @@
// Build don't link:
template <class T>
class S2
{
public:
static void f();
};
class S1
{
template <class T>
friend class S2;
static int i;
};
template <class T>
void S2<T>::f()
{
S1::i = 3;
}
void g()
{
S2<double>::f();
S2<char>::f();
}

View File

@ -0,0 +1,26 @@
// Build don't link:
template <class U>
class S1
{
template <class T>
friend class S2;
static int i;
};
template <class T>
class S2
{
public:
static void f() { S1<T>::i = 3; }
};
void g()
{
S2<double>::f();
S2<long>::f();
}

View File

@ -0,0 +1,26 @@
// Build don't link:
template <class U>
class S1
{
template <class T>
friend class S2;
static int i;
};
template <class T>
class S2
{
public:
static void f() { S1<T>::i = 3; }
};
void g()
{
S2<double>::f();
S2<long>::f();
}