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:
parent
7bf407413f
commit
6757edfe65
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
|
660
gcc/cp/parse.c
660
gcc/cp/parse.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
;
|
||||
|
182
gcc/cp/pt.c
182
gcc/cp/pt.c
@ -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)
|
||||
|
@ -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;
|
||||
|
25
gcc/testsuite/g++.old-deja/g++.pt/friend14.C
Normal file
25
gcc/testsuite/g++.old-deja/g++.pt/friend14.C
Normal 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();
|
||||
}
|
24
gcc/testsuite/g++.old-deja/g++.pt/friend15.C
Normal file
24
gcc/testsuite/g++.old-deja/g++.pt/friend15.C
Normal 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();
|
||||
}
|
31
gcc/testsuite/g++.old-deja/g++.pt/friend16.C
Normal file
31
gcc/testsuite/g++.old-deja/g++.pt/friend16.C
Normal 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();
|
||||
}
|
28
gcc/testsuite/g++.old-deja/g++.pt/friend17.C
Normal file
28
gcc/testsuite/g++.old-deja/g++.pt/friend17.C
Normal 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();
|
||||
}
|
26
gcc/testsuite/g++.old-deja/g++.pt/friend18.C
Normal file
26
gcc/testsuite/g++.old-deja/g++.pt/friend18.C
Normal 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();
|
||||
}
|
||||
|
26
gcc/testsuite/g++.old-deja/g++.pt/friend19.C
Normal file
26
gcc/testsuite/g++.old-deja/g++.pt/friend19.C
Normal 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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user