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

1998-07-31  Mark Mitchell  <mark@markmitchell.com>
	* cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro.
	(maybe_check_template_type): New function.
	* decl.c (maybe_process_template_type_declaration): New function,
	split out from pushtag  Call maybe_check_template_type.
	(pushtag): Use it.  Use PROCESSING_REAL_TEMPLATE_DECL_P.
	(xref_tag): Use PROCESSING_REAL_TEMPLATE_DECL_P.
	* friend.c (do_friend): Use PROCESSING_REAL_TEMPLATE_DECL_P.
	* pt.c (template_class_depth_real): Generalization of ...
	(template_class_depth): Use it.
	(register_specialization): Use duplicate_decls for duplicate
	declarations of specializations.
	(maybe_check_template_type): New function.
	(push_template_decl_real): Fix comment.
	(convert_nontype_argument): Likewise.
	(lookup_template_class): Likewise.  Avoid an infinite loop on
	erroneous code.
	(tsubst_friend_function): Fix comment.
	(tsubst, case FUNCTION_DECL): Deal with a DECL_TI_TEMPLATE that is
	an IDENTIFIER_NODE.
	* semantics.c (begin_function_definition): Use
	reset_specialization to note that template headers don't apply
	directly to declarations after the opening curly for a function.

From-SVN: r21505
This commit is contained in:
Mark Mitchell 1998-07-31 15:01:21 +00:00 committed by Mark Mitchell
parent 5f97de0ac9
commit 39c01e4c53
11 changed files with 284 additions and 88 deletions

View File

@ -1,3 +1,28 @@
1998-07-31 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (PROCESSING_REAL_TEMPLATE_DECL_P): New macro.
(maybe_check_template_type): New function.
* decl.c (maybe_process_template_type_declaration): New function,
split out from pushtag Call maybe_check_template_type.
(pushtag): Use it. Use PROCESSING_REAL_TEMPLATE_DECL_P.
(xref_tag): Use PROCESSING_REAL_TEMPLATE_DECL_P.
* friend.c (do_friend): Use PROCESSING_REAL_TEMPLATE_DECL_P.
* pt.c (template_class_depth_real): Generalization of ...
(template_class_depth): Use it.
(register_specialization): Use duplicate_decls for duplicate
declarations of specializations.
(maybe_check_template_type): New function.
(push_template_decl_real): Fix comment.
(convert_nontype_argument): Likewise.
(lookup_template_class): Likewise. Avoid an infinite loop on
erroneous code.
(tsubst_friend_function): Fix comment.
(tsubst, case FUNCTION_DECL): Deal with a DECL_TI_TEMPLATE that is
an IDENTIFIER_NODE.
* semantics.c (begin_function_definition): Use
reset_specialization to note that template headers don't apply
directly to declarations after the opening curly for a function.
1998-07-29 Jason Merrill <jason@yorick.cygnus.com> 1998-07-29 Jason Merrill <jason@yorick.cygnus.com>
* decl.c (push_overloaded_decl): Use current_namespace instead of * decl.c (push_overloaded_decl): Use current_namespace instead of

View File

@ -1692,6 +1692,12 @@ extern int flag_new_for_scope;
#define SET_CLASSTYPE_EXPLICIT_INSTANTIATION(NODE) \ #define SET_CLASSTYPE_EXPLICIT_INSTANTIATION(NODE) \
(CLASSTYPE_USE_TEMPLATE(NODE) = 3) (CLASSTYPE_USE_TEMPLATE(NODE) = 3)
/* Non-zero iff we are currently processing a declaration for an
entity with its own template parameter list, and which is not a
full specialization. */
#define PROCESSING_REAL_TEMPLATE_DECL_P() \
(processing_template_decl > template_class_depth (current_class_type))
/* This function may be a guiding decl for a template. */ /* This function may be a guiding decl for a template. */
#define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE) #define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE)
/* We know what we're doing with this decl now. */ /* We know what we're doing with this decl now. */
@ -2794,6 +2800,7 @@ extern int template_class_depth PROTO((tree));
extern int is_specialization_of PROTO((tree, tree)); extern int is_specialization_of PROTO((tree, tree));
extern int comp_template_args PROTO((tree, tree)); extern int comp_template_args PROTO((tree, tree));
extern void maybe_process_partial_specialization PROTO((tree)); extern void maybe_process_partial_specialization PROTO((tree));
extern void maybe_check_template_type PROTO((tree));
extern int processing_specialization; extern int processing_specialization;
extern int processing_explicit_instantiation; extern int processing_explicit_instantiation;

View File

@ -176,6 +176,7 @@ static int member_function_or_else PROTO((tree, tree, char *));
static void bad_specifiers PROTO((tree, char *, int, int, int, int, static void bad_specifiers PROTO((tree, char *, int, int, int, int,
int)); int));
static void lang_print_error_function PROTO((char *)); static void lang_print_error_function PROTO((char *));
static tree maybe_process_template_type_declaration PROTO((tree, int, struct binding_level*));
#if defined (DEBUG_CP_BINDING_LEVELS) #if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PROTO((void)); static void indent PROTO((void));
@ -2223,6 +2224,88 @@ pop_everything ()
#endif #endif
} }
/* The type TYPE is being declared. If it is a class template, or a
specialization of a class template, do any processing required and
perform error-checking. If IS_FRIEND is non-zero, this TYPE is
being declared a friend. B is the binding level at which this TYPE
should be bound.
Returns the TYPE_DECL for TYPE, which may have been altered by this
processing. */
static tree
maybe_process_template_type_declaration (type, globalize, b)
tree type;
int globalize;
struct binding_level* b;
{
tree decl = TYPE_NAME (type);
if (processing_template_parmlist)
/* You can't declare a new template type in a template parameter
list. But, you can declare a non-template type:
template <class A*> struct S;
is a forward-declaration of `A'. */
;
else
{
maybe_check_template_type (type);
if (IS_AGGR_TYPE (type)
&& (/* If !GLOBALIZE then we are looking at a definition.
It may not be a primary template. (For example, in:
template <class T>
struct S1 { class S2 {}; }
we have to push_template_decl for S2.) */
(processing_template_decl && !globalize)
/* 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. */
|| PROCESSING_REAL_TEMPLATE_DECL_P ()))
{
/* This may change after the call to
push_template_decl_real, but we want the original value. */
tree name = DECL_NAME (decl);
decl = push_template_decl_real (decl, 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);
/* Put this tag on the list of tags for the class, since
that won't happen below because B is not the class
binding level, but is instead the pseudo-global level. */
b->level_chain->tags =
saveable_tree_cons (name, type, b->level_chain->tags);
TREE_NONLOCAL_FLAG (type) = 1;
if (TYPE_SIZE (current_class_type) == NULL_TREE)
CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
}
}
}
return decl;
}
/* 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 it 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.
@ -2298,63 +2381,8 @@ pushtag (name, type, globalize)
TYPE_NAME (type) = d; TYPE_NAME (type) = d;
DECL_CONTEXT (d) = FROB_CONTEXT (context); DECL_CONTEXT (d) = FROB_CONTEXT (context);
if (processing_template_parmlist) d = maybe_process_template_type_declaration (type,
/* You can't declare a new template type in a template globalize, b);
parameter list. But, you can declare a non-template
type:
template <class A*> struct S;
is a forward-declaration of `A'. */
;
else if (IS_AGGR_TYPE (type)
&& (/* If !GLOBALIZE then we are looking at a
definition. It may not be a primary template.
(For example, in:
template <class T>
struct S1 { class S2 {}; }
we have to push_template_decl for S2.) */
(processing_template_decl && !globalize)
/* 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. */
|| (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),
b->level_chain);
/* Put this tag on the list of tags for the class,
since that won't happen below because B is not
the class binding level, but is instead the
pseudo-global level. */
b->level_chain->tags =
saveable_tree_cons (name, type, b->level_chain->tags);
TREE_NONLOCAL_FLAG (type) = 1;
if (TYPE_SIZE (current_class_type) == NULL_TREE)
CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
}
}
if (b->parm_flag == 2) if (b->parm_flag == 2)
d = pushdecl_class_level (d); d = pushdecl_class_level (d);
@ -11349,8 +11377,7 @@ xref_tag (code_type_node, name, binfo, globalize)
{ {
if (current_class_type if (current_class_type
&& template_class_depth (current_class_type) && template_class_depth (current_class_type)
&& (processing_template_decl && PROCESSING_REAL_TEMPLATE_DECL_P ())
> template_class_depth (current_class_type)))
/* Since GLOBALIZE is non-zero, we are not looking at a /* Since GLOBALIZE is non-zero, we are not looking at a
definition of this tag. Since, in addition, we are currently definition of this tag. Since, in addition, we are currently
processing a (member) template declaration of a template processing a (member) template declaration of a template

View File

@ -354,8 +354,7 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
} }
if (TREE_CODE (decl) == FUNCTION_DECL) if (TREE_CODE (decl) == FUNCTION_DECL)
is_friend_template = processing_template_decl > is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
template_class_depth (current_class_type);
if (ctype) if (ctype)
{ {

View File

@ -121,6 +121,7 @@ static tree most_specialized PROTO((tree, tree, tree));
static tree most_specialized_class PROTO((tree, tree)); static tree most_specialized_class PROTO((tree, tree));
static tree most_general_template PROTO((tree)); static tree most_general_template PROTO((tree));
static void set_mangled_name_for_template_decl PROTO((tree)); static void set_mangled_name_for_template_decl PROTO((tree));
static int template_class_depth_real PROTO((tree, int));
/* We use TREE_VECs to hold template arguments. If there is only one /* We use TREE_VECs to hold template arguments. If there is only one
level of template arguments, then the TREE_VEC contains the level of template arguments, then the TREE_VEC contains the
@ -234,12 +235,19 @@ finish_member_template_decl (template_parameters, decl)
struct B {}; struct B {};
}; };
A<T>::B<U> has depth two, while A<T> has depth one. Also, A<T>::B<U> has depth two, while A<T> has depth one.
both A<T>::B<int> and A<int>::B<U> have depth one. */ Both A<T>::B<int> and A<int>::B<U> have depth one, if
COUNT_SPECIALIZATIONS is 0 or if they are instantiations, not
specializations.
This function is guaranteed to return 0 if passed NULL_TREE so
that, for example, `template_class_depth (current_class_type)' is
always safe. */
int int
template_class_depth (type) template_class_depth_real (type, count_specializations)
tree type; tree type;
int count_specializations;
{ {
int depth; int depth;
@ -249,12 +257,25 @@ template_class_depth (type)
type = TYPE_CONTEXT (type)) type = TYPE_CONTEXT (type))
if (CLASSTYPE_TEMPLATE_INFO (type) if (CLASSTYPE_TEMPLATE_INFO (type)
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)) && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
&& uses_template_parms (CLASSTYPE_TI_ARGS (type))) && ((count_specializations
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
|| uses_template_parms (CLASSTYPE_TI_ARGS (type))))
++depth; ++depth;
return depth; return depth;
} }
/* Returns the template nesting level of the indicated class TYPE.
Like template_class_depth_real, but instantiations do not count in
the depth. */
int
template_class_depth (type)
tree type;
{
return template_class_depth_real (type, /*count_specializations=*/0);
}
/* Returns 1 if processing DECL as part of do_pending_inlines /* Returns 1 if processing DECL as part of do_pending_inlines
needs us to push template parms. */ needs us to push template parms. */
@ -742,11 +763,8 @@ register_specialization (spec, tmpl, args)
} }
else if (DECL_TEMPLATE_SPECIALIZATION (fn)) else if (DECL_TEMPLATE_SPECIALIZATION (fn))
{ {
if (DECL_INITIAL (fn)) duplicate_decls (spec, TREE_VALUE (s));
cp_error ("duplicate specialization of %D", fn); return TREE_VALUE (s);
TREE_VALUE (s) = spec;
return spec;
} }
} }
} }
@ -1300,6 +1318,50 @@ check_explicit_specialization (declarator, decl, template_count, flags)
return decl; return decl;
} }
/* TYPE is being declared. Verify that the use of template headers
and such is reasonable. Issue error messages if not. */
void
maybe_check_template_type (type)
tree type;
{
if (template_header_count)
{
/* We are in the scope of some `template <...>' header. */
int context_depth
= template_class_depth_real (TYPE_CONTEXT (type),
/*count_specializations=*/1);
if (template_header_count <= context_depth)
/* This is OK; the template headers are for the context. We
are actually too lenient here; like
check_explicit_specialization we should consider the number
of template types included in the actual declaration. For
example,
template <class T> struct S {
template <class U> template <class V>
struct I {};
};
is illegal, but:
template <class T> struct S {
template <class U> struct I;
};
template <class T> template <class U.
struct S<T>::I {};
is not. */
;
else if (template_header_count > context_depth + 1)
/* There are two many template parameter lists. */
cp_error ("too many template parameter lists in declaration of `%T'", type);
}
}
/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template /* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
parameters. These are represented in the same format used for parameters. These are represented in the same format used for
DECL_TEMPLATE_PARMS. */ DECL_TEMPLATE_PARMS. */
@ -1951,9 +2013,7 @@ push_template_decl_real (decl, is_friend)
/* Push template declarations for global functions and types. Note /* Push template declarations for global functions and types. Note
that we do not try to push a global template friend declared in a 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 template class; such a thing may well depend on the template
parameters of the class. With guiding declarations, however, we parameters of the class. */
push the template so that subsequent declarations of the template
will match this one. */
if (! ctx if (! ctx
&& !(is_friend && template_class_depth (current_class_type) > 0)) && !(is_friend && template_class_depth (current_class_type) > 0))
tmpl = pushdecl_namespace_level (tmpl); tmpl = pushdecl_namespace_level (tmpl);
@ -2278,10 +2338,10 @@ convert_nontype_argument (type, expr)
if (TREE_CODE (type_referred_to) == FUNCTION_TYPE) if (TREE_CODE (type_referred_to) == FUNCTION_TYPE)
{ {
/* For a non-type template-parameter of type reference to /* For a non-type template-parameter of type reference to
function, no conversions apply. If the function, no conversions apply. If the
template-argument represents a set of overloaded template-argument represents a set of overloaded
functions, the matching function is selected from the functions, the matching function is selected from the
set (_over.over_). */ set (_over.over_). */
tree fns = expr; tree fns = expr;
tree fn; tree fn;
@ -3096,7 +3156,7 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
if (arg_depth == 1 && parm_depth > 1) if (arg_depth == 1 && parm_depth > 1)
{ {
/* We've been with an incomplete set of template arguments. /* We've been given an incomplete set of template arguments.
For example, given: For example, given:
template <class T> struct S1 { template <class T> struct S1 {
@ -3109,8 +3169,28 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope)
<class U> struct S1<T>::S2'. We must fill in the missing <class U> struct S1<T>::S2'. We must fill in the missing
arguments. */ arguments. */
my_friendly_assert (context != NULL_TREE, 0); my_friendly_assert (context != NULL_TREE, 0);
while (!IS_AGGR_TYPE_CODE (TREE_CODE (context))) while (!IS_AGGR_TYPE_CODE (TREE_CODE (context))
&& context != global_namespace)
context = DECL_REAL_CONTEXT (context); context = DECL_REAL_CONTEXT (context);
if (context == global_namespace)
/* This is bad. We cannot get enough arguments, even from
the surrounding context, to resolve this class. One
case where this might happen is (illegal) code like:
template <class U>
template <class T>
struct S {
A(const A<T>& a) {}
};
We should catch this error sooner (at the opening curly
for `S', but it is better to be safe than sorry here. */
{
cp_error ("invalid use of `%D'", template);
return error_mark_node;
}
arglist = add_to_template_args (CLASSTYPE_TI_ARGS (context), arglist = add_to_template_args (CLASSTYPE_TI_ARGS (context),
arglist); arglist);
arg_depth = TMPL_ARGS_DEPTH (arglist); arg_depth = TMPL_ARGS_DEPTH (arglist);
@ -3667,8 +3747,8 @@ tsubst_friend_function (decl, args)
args, NULL_TREE), args, NULL_TREE),
tsubst (DECL_TI_ARGS (decl), tsubst (DECL_TI_ARGS (decl),
args, NULL_TREE)); args, NULL_TREE));
/* FIXME: The decl we create via the next tsubst be created on a /* FIXME: The decl we create via the next tsubst could be
temporary obstack. */ created on a temporary obstack. */
new_friend = tsubst (decl, args, NULL_TREE); new_friend = tsubst (decl, args, NULL_TREE);
tmpl = determine_specialization (template_id, new_friend, tmpl = determine_specialization (template_id, new_friend,
&new_args, &new_args,
@ -4833,12 +4913,14 @@ tsubst (t, args, in_decl)
}; };
Here, the DECL_TI_TEMPLATE for the friend declaration Here, the DECL_TI_TEMPLATE for the friend declaration
will be a LOOKUP_EXPR. We are being called from will be a LOOKUP_EXPR or an IDENTIFIER_NODE. We are
tsubst_friend_function, and we want only to create a being called from tsubst_friend_function, and we want
new decl (R) with appropriate types so that we can call only to create a new decl (R) with appropriate types so
determine_specialization. */ that we can call determine_specialization. */
my_friendly_assert (TREE_CODE (DECL_TI_TEMPLATE (t)) my_friendly_assert ((TREE_CODE (DECL_TI_TEMPLATE (t))
== LOOKUP_EXPR, 0); == LOOKUP_EXPR)
|| (TREE_CODE (DECL_TI_TEMPLATE (t))
== IDENTIFIER_NODE), 0);
gen_tmpl = NULL_TREE; gen_tmpl = NULL_TREE;
} }

View File

@ -1098,6 +1098,10 @@ begin_function_definition (decl_specs, declarator)
return 0; return 0;
reinit_parse_for_function (); reinit_parse_for_function ();
/* The things we're about to see are not directly qualified by any
template headers we've seen thus far. */
reset_specialization ();
return 1; return 1;
} }

View File

@ -0,0 +1,10 @@
// Build don't link:
template <class T>
template <class U>
struct A { // ERROR - too many template parameter lists
public:
A() {}
A(const A<T>& b) {} // ERROR - invalid use of template
};

View File

@ -0,0 +1,4 @@
// Build don't link:
template <>
enum E {e}; // ERROR - template declaration of enum

View File

@ -4,7 +4,7 @@ template <class T>
void foo(T t); void foo(T t);
template <> template <>
void foo(int) {}; void foo(int) {}; // ERROR - previously defined here.
template <> template <>
void foo<int>(int) {} // ERROR - duplicate specialization. void foo<int>(int) {} // ERROR - duplicate specialization.

View File

@ -0,0 +1,22 @@
// Build don't link:
class mystream;
template <class T> class a {
public:
friend mystream& operator>> <>( mystream&, a<T>& thea );
private:
T amember;
};
template <class T> mystream& operator>>( mystream& s, a<T>& thea );
template<> mystream& operator>> <int>( mystream& s, a<int>& thea );
template class a<int>;
template<> mystream& operator>> <int>( mystream& s, a<int>& thea )
{
thea.amember = 0;
return s;
}

View File

@ -0,0 +1,16 @@
// Build don't link:
template <class T> class a {
public:
friend void foo<>( a<T>& thea );
private:
T amember;
};
template <class T> void foo( a<T>& thea )
{
thea.amember = 0;
}
template class a<int>;