Commit 6757edfe by Mark Mitchell Committed by Mark Mitchell

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
parent 7bf40741
Sun Apr 26 12:10:18 1998 Mark Mitchell <mmitchell@usa.net> 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 * pt.c (check_explicit_specialization): Handle overloaded
constructors correctly. constructors correctly.
......
...@@ -1139,6 +1139,15 @@ struct lang_decl ...@@ -1139,6 +1139,15 @@ struct lang_decl
#define DELETE_EXPR_USE_VEC(NODE) TREE_LANG_FLAG_1 (NODE) #define DELETE_EXPR_USE_VEC(NODE) TREE_LANG_FLAG_1 (NODE)
#define LOOKUP_EXPR_GLOBAL(NODE) TREE_LANG_FLAG_0 (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) #define TYPENAME_TYPE_FULLNAME(NODE) CLASSTYPE_SIZE (NODE)
/* Nonzero in INT_CST means that this int is negative by dint of /* Nonzero in INT_CST means that this int is negative by dint of
...@@ -1412,11 +1421,22 @@ extern int flag_new_for_scope; ...@@ -1412,11 +1421,22 @@ extern int flag_new_for_scope;
(TREE_CODE (NODE) == TEMPLATE_DECL \ (TREE_CODE (NODE) == TEMPLATE_DECL \
&& TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_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 /* A `primary' template is one that has its own template header. A
member function of a class template is a template, but not primary. member function of a class template is a template, but not primary.
A member template is primary. */ A member template is primary. Friend templates are primary, too. */
#define PRIMARY_TEMPLATE_P(NODE) \
(TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)) == (NODE)) /* 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) \ #define CLASSTYPE_TEMPLATE_LEVEL(NODE) \
(TREE_INT_CST_HIGH (TREE_PURPOSE (CLASSTYPE_TI_TEMPLATE (NODE)))) (TREE_INT_CST_HIGH (TREE_PURPOSE (CLASSTYPE_TI_TEMPLATE (NODE))))
...@@ -2435,7 +2455,8 @@ extern tree end_template_parm_list PROTO((tree)); ...@@ -2435,7 +2455,8 @@ extern tree end_template_parm_list PROTO((tree));
extern void end_template_decl PROTO((void)); extern void end_template_decl PROTO((void));
extern tree current_template_args PROTO((void)); extern tree current_template_args PROTO((void));
extern tree push_template_decl PROTO((tree)); 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_class PROTO((tree, tree, tree, tree));
extern tree lookup_template_function PROTO((tree, tree)); extern tree lookup_template_function PROTO((tree, tree));
extern int uses_template_parms PROTO((tree)); extern int uses_template_parms PROTO((tree));
...@@ -2467,6 +2488,9 @@ extern void do_pushlevel PROTO((void)); ...@@ -2467,6 +2488,9 @@ extern void do_pushlevel PROTO((void));
extern int is_member_template PROTO((tree)); extern int is_member_template PROTO((tree));
extern int comp_template_parms PROTO((tree, tree)); extern int comp_template_parms PROTO((tree, tree));
extern int template_class_depth PROTO((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_specialization;
extern int processing_explicit_instantiation; extern int processing_explicit_instantiation;
......
...@@ -2157,7 +2157,7 @@ pop_everything () ...@@ -2157,7 +2157,7 @@ pop_everything ()
} }
/* Push a tag name NAME for struct/class/union/enum type TYPE. /* 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. but if GLOBALIZE is true, put it in the inner-most non-class scope.
The latter is needed for implicit declarations. */ The latter is needed for implicit declarations. */
...@@ -2226,11 +2226,52 @@ pushtag (name, type, globalize) ...@@ -2226,11 +2226,52 @@ pushtag (name, type, globalize)
TYPE_NAME (type) = d; TYPE_NAME (type) = d;
DECL_CONTEXT (d) = context; DECL_CONTEXT (d) = context;
if (! globalize && processing_template_decl if (IS_AGGR_TYPE (type)
&& IS_AGGR_TYPE (type)) && (/* If !GLOBALIZE then we are looking at a
{ definition. */
d = push_template_decl (d); (processing_template_decl && !globalize)
if (b->pseudo_global && b->level_chain->parm_flag == 2) /* 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_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), pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
b->level_chain); b->level_chain);
} }
...@@ -10812,6 +10853,15 @@ xref_tag (code_type_node, name, binfo, globalize) ...@@ -10812,6 +10853,15 @@ xref_tag (code_type_node, name, binfo, globalize)
{ {
/* Try finding it as a type declaration. If that wins, use it. */ /* Try finding it as a type declaration. If that wins, use it. */
ref = lookup_name (name, 1); 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 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);
...@@ -10898,7 +10948,7 @@ xref_tag (code_type_node, name, binfo, globalize) ...@@ -10898,7 +10948,7 @@ xref_tag (code_type_node, name, binfo, globalize)
} }
if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref)) if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref))
redeclare_class_template (ref); redeclare_class_template (ref, current_template_parms);
} }
if (binfo) if (binfo)
......
...@@ -870,8 +870,16 @@ grok_x_components (specs, components) ...@@ -870,8 +870,16 @@ grok_x_components (specs, components)
tcode = class_type_node; tcode = class_type_node;
else if (IS_SIGNATURE (t)) else if (IS_SIGNATURE (t))
tcode = signature_type_node; 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; return NULL_TREE;
break; break;
......
...@@ -71,25 +71,17 @@ is_friend (type, supplicant) ...@@ -71,25 +71,17 @@ is_friend (type, supplicant)
if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL) if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL)
{ {
tree t; if (is_specialization_of (supplicant,
TREE_VALUE (friends)))
/* Perhaps this function is a specialization of return 1;
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;
continue; 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), if (comptypes (TREE_TYPE (supplicant),
TREE_TYPE (TREE_VALUE (friends)), 1)) TREE_TYPE (TREE_VALUE (friends)), 1))
return 1; return 1;
...@@ -106,8 +98,15 @@ is_friend (type, supplicant) ...@@ -106,8 +98,15 @@ is_friend (type, supplicant)
list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type))); list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type)));
for (; list ; list = TREE_CHAIN (list)) 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)) if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
...@@ -249,7 +248,10 @@ make_friend_class (type, friend_type) ...@@ -249,7 +248,10 @@ make_friend_class (type, friend_type)
IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type))); IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type)));
return; 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", pedwarn ("class `%s' is implicitly friends with itself",
TYPE_NAME_STRING (type)); TYPE_NAME_STRING (type));
......
...@@ -2498,8 +2498,12 @@ component_decl: ...@@ -2498,8 +2498,12 @@ component_decl:
{ $$ = finish_member_template_decl ($1, $2); } { $$ = finish_member_template_decl ($1, $2); }
| template_header typed_declspecs ';' | template_header typed_declspecs ';'
{ {
shadow_tag ($2.t);
note_list_got_semicolon ($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); $$ = finish_member_template_decl ($1, $2.t);
} }
; ;
......
...@@ -763,26 +763,8 @@ comptypes (type1, type2, strict) ...@@ -763,26 +763,8 @@ comptypes (type1, type2, strict)
if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2) if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2)
&& (CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2) && (CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2)
|| TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)) || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM))
{ return comp_template_args (CLASSTYPE_TI_ARGS (t1),
int i = TREE_VEC_LENGTH (CLASSTYPE_TI_ARGS (t1)); CLASSTYPE_TI_ARGS (t2));
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;
}
if (strict <= 0) if (strict <= 0)
goto look_hard; goto look_hard;
return 0; return 0;
......
// 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();
}
// 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();
}
// 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();
}
// 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();
}
// 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();
}
// 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();
}
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