cp-tree.h (scope_kind): New type.

* cp-tree.h (scope_kind): New type.
	(tmpl_spec_kind): Likewise.
	(declare_pseudo_global_level): Remove.
	(pseudo_global_level_p): Rename to template_parm_scope_p.
	(pushlevel): Remove declaration.
	(begin_scope): New function.
	(finish_scope): Likewise.
	(current_tmpl_spec_kind): Likewise.
	* decl.c (struct binding_level): Shorten parm_flag to 2 bits.
	Shorten keep to 2 bits.  Rename pseudo_global to template_parms_p.
	Add template_spec_p.
	(toplevel_bindings_p): Adjust.
	(declare_pseudo_global_level): Remove.
	(pseudo_global_level_p): Rename to template_parm_scope_p.
	(current_tmpl_spec_kind): New function.
	(begin_scope): Likewise.
	(finish_scope): Likewise.
	(maybe_push_to_top_level): Adjust.
	(maybe_process_template_type_declaration): Likewise.
	(pushtag): Likewise.
	(pushdecl_nonclass_level): Likewise.
	(lookup_tag): Likewise.
	(grokfndecl): Handle member template specializations.  Share
	constructor and non-constructor code.
	* decl2.c (check_classfn): Handle member template specializations.
	* pt.c (begin_template_parm_list): Use begin_scope.
	(begin_specialization): Likewise.
	(end_specialization): Likewise.
	(check_explicit_specialization): Use current_tmpl_spec_kind.
	Handle member template specializations.
	(end_template_decl): Use finish_scope.  Remove call to
	get_pending_sizes.
	(push_template_decl_real): Remove bogus error message.
	(tsubst_decl): Fix typo in code contained in comment.
	(instantiate_template): Handle member template specializations.
	(most_general_template): Likewise.

From-SVN: r32494
This commit is contained in:
Mark Mitchell 2000-03-12 18:47:52 +00:00 committed by Mark Mitchell
parent d453714896
commit 74b846e0de
7 changed files with 410 additions and 234 deletions

View File

@ -1,3 +1,42 @@
2000-03-11 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (scope_kind): New type.
(tmpl_spec_kind): Likewise.
(declare_pseudo_global_level): Remove.
(pseudo_global_level_p): Rename to template_parm_scope_p.
(pushlevel): Remove declaration.
(begin_scope): New function.
(finish_scope): Likewise.
(current_tmpl_spec_kind): Likewise.
* decl.c (struct binding_level): Shorten parm_flag to 2 bits.
Shorten keep to 2 bits. Rename pseudo_global to template_parms_p.
Add template_spec_p.
(toplevel_bindings_p): Adjust.
(declare_pseudo_global_level): Remove.
(pseudo_global_level_p): Rename to template_parm_scope_p.
(current_tmpl_spec_kind): New function.
(begin_scope): Likewise.
(finish_scope): Likewise.
(maybe_push_to_top_level): Adjust.
(maybe_process_template_type_declaration): Likewise.
(pushtag): Likewise.
(pushdecl_nonclass_level): Likewise.
(lookup_tag): Likewise.
(grokfndecl): Handle member template specializations. Share
constructor and non-constructor code.
* decl2.c (check_classfn): Handle member template specializations.
* pt.c (begin_template_parm_list): Use begin_scope.
(begin_specialization): Likewise.
(end_specialization): Likewise.
(check_explicit_specialization): Use current_tmpl_spec_kind.
Handle member template specializations.
(end_template_decl): Use finish_scope. Remove call to
get_pending_sizes.
(push_template_decl_real): Remove bogus error message.
(tsubst_decl): Fix typo in code contained in comment.
(instantiate_template): Handle member template specializations.
(most_general_template): Likewise.
2000-03-11 Gabriel Dos Reis <gdr@codesourcery.com> 2000-03-11 Gabriel Dos Reis <gdr@codesourcery.com>
* lex.c (whitespace_cr): Compress consecutive calls to warning(). * lex.c (whitespace_cr): Compress consecutive calls to warning().

View File

@ -3043,6 +3043,32 @@ typedef enum cp_lvalue_kind {
clk_bitfield = 4, /* An lvalue for a bit-field. */ clk_bitfield = 4, /* An lvalue for a bit-field. */
} cp_lvalue_kind; } cp_lvalue_kind;
/* The kinds of scopes we recognize. */
typedef enum scope_kind {
sk_template_parms, /* A scope for template parameters. */
sk_template_spec /* A scope corresponding to a template
specialization. There is never anything in
this scope. */
} scope_kind;
/* Various kinds of template specialization, instantiation, etc. */
typedef enum tmpl_spec_kind {
tsk_none, /* Not a template at all. */
tsk_invalid_member_spec, /* An explicit member template
specialization, but the enclosing
classes have not all been explicitly
specialized. */
tsk_invalid_expl_inst, /* An explicit instantiation containing
template parameter lists. */
tsk_excessive_parms, /* A template declaration with too many
template parameter lists. */
tsk_insufficient_parms, /* A template declaration with too few
parameter lists. */
tsk_template, /* A template declaration. */
tsk_expl_spec, /* An explicit specialization. */
tsk_expl_inst /* An explicit instantiation. */
} tmpl_spec_kind;
/* Zero means prototype weakly, as in ANSI C (no args means nothing). /* Zero means prototype weakly, as in ANSI C (no args means nothing).
Each language context defines how this variable should be set. */ Each language context defines how this variable should be set. */
extern int strict_prototype; extern int strict_prototype;
@ -3682,10 +3708,10 @@ extern int toplevel_bindings_p PARAMS ((void));
extern int namespace_bindings_p PARAMS ((void)); extern int namespace_bindings_p PARAMS ((void));
extern void keep_next_level PARAMS ((int)); extern void keep_next_level PARAMS ((int));
extern int kept_level_p PARAMS ((void)); extern int kept_level_p PARAMS ((void));
extern void declare_pseudo_global_level PARAMS ((void)); extern int template_parm_scope_p PARAMS ((void));
extern int pseudo_global_level_p PARAMS ((void));
extern void set_class_shadows PARAMS ((tree)); extern void set_class_shadows PARAMS ((tree));
extern void pushlevel PARAMS ((int)); extern void begin_scope PARAMS ((scope_kind));
extern void finish_scope PARAMS ((void));
extern void note_level_for_for PARAMS ((void)); extern void note_level_for_for PARAMS ((void));
extern void resume_level PARAMS ((struct binding_level *)); extern void resume_level PARAMS ((struct binding_level *));
extern void delete_block PARAMS ((tree)); extern void delete_block PARAMS ((tree));
@ -3832,6 +3858,7 @@ extern int local_variable_p PARAMS ((tree));
extern int nonstatic_local_decl_p PARAMS ((tree)); extern int nonstatic_local_decl_p PARAMS ((tree));
extern tree declare_global_var PARAMS ((tree, tree)); extern tree declare_global_var PARAMS ((tree, tree));
extern void register_dtor_fn PARAMS ((tree)); extern void register_dtor_fn PARAMS ((tree));
extern tmpl_spec_kind current_tmpl_spec_kind PARAMS ((int));
/* in decl2.c */ /* in decl2.c */
extern void init_decl2 PARAMS ((void)); extern void init_decl2 PARAMS ((void));

View File

@ -456,13 +456,12 @@ struct binding_level
tree dead_vars_from_for; tree dead_vars_from_for;
/* 1 for the level that holds the parameters of a function. /* 1 for the level that holds the parameters of a function.
2 for the level that holds a class declaration. 2 for the level that holds a class declaration. */
3 for levels that hold parameter declarations. */ unsigned parm_flag : 2;
unsigned parm_flag : 4;
/* 1 means make a BLOCK for this level regardless of all else. /* 1 means make a BLOCK for this level regardless of all else.
2 for temporary binding contours created by the compiler. */ 2 for temporary binding contours created by the compiler. */
unsigned keep : 3; unsigned keep : 2;
/* Nonzero if this level "doesn't exist" for tags. */ /* Nonzero if this level "doesn't exist" for tags. */
unsigned tag_transparent : 1; unsigned tag_transparent : 1;
@ -472,10 +471,15 @@ struct binding_level
unsigned more_cleanups_ok : 1; unsigned more_cleanups_ok : 1;
unsigned have_cleanups : 1; unsigned have_cleanups : 1;
/* Nonzero if this level is for storing the decls for template /* Nonzero if this scope is for storing the decls for template
parameters and generic decls; these decls will be discarded and parameters and generic decls; these decls will be discarded and
replaced with a TEMPLATE_DECL. */ replaced with a TEMPLATE_DECL. */
unsigned pseudo_global : 1; unsigned template_parms_p : 1;
/* Nonzero if this scope corresponds to the `<>' in a
`template <>' clause. Whenever this flag is set,
TEMPLATE_PARMS_P will be set as well. */
unsigned template_spec_p : 1;
/* This is set for a namespace binding level. */ /* This is set for a namespace binding level. */
unsigned namespace_p : 1; unsigned namespace_p : 1;
@ -487,7 +491,7 @@ struct binding_level
/* True if this level corresponds to an EH region, as for a try block. */ /* True if this level corresponds to an EH region, as for a try block. */
unsigned eh_region : 1; unsigned eh_region : 1;
/* One bit left for this word. */ /* Four bits left for this word. */
#if defined(DEBUG_CP_BINDING_LEVELS) #if defined(DEBUG_CP_BINDING_LEVELS)
/* Binding depth at which this level began. */ /* Binding depth at which this level began. */
@ -704,15 +708,15 @@ innermost_nonclass_level ()
/* Nonzero if we are currently in a toplevel binding level. This /* Nonzero if we are currently in a toplevel binding level. This
means either the global binding level or a namespace in a toplevel means either the global binding level or a namespace in a toplevel
binding level. Since there are no non-toplevel namespace levels, binding level. Since there are no non-toplevel namespace levels,
this really means any namespace or pseudo-global level. We also this really means any namespace or template parameter level. We
include a class whose context is toplevel. */ also include a class whose context is toplevel. */
int int
toplevel_bindings_p () toplevel_bindings_p ()
{ {
struct binding_level *b = innermost_nonclass_level (); struct binding_level *b = innermost_nonclass_level ();
return b->namespace_p || b->pseudo_global; return b->namespace_p || b->template_parms_p;
} }
/* Nonzero if this is a namespace scope, or if we are defining a class /* Nonzero if this is a namespace scope, or if we are defining a class
@ -750,22 +754,108 @@ kept_level_p ()
&& !current_binding_level->tag_transparent)); && !current_binding_level->tag_transparent));
} }
void
declare_pseudo_global_level ()
{
current_binding_level->pseudo_global = 1;
}
static void static void
declare_namespace_level () declare_namespace_level ()
{ {
current_binding_level->namespace_p = 1; current_binding_level->namespace_p = 1;
} }
/* Returns non-zero if this scope was created to store template
parameters. */
int int
pseudo_global_level_p () template_parm_scope_p ()
{ {
return current_binding_level->pseudo_global; return current_binding_level->template_parms_p;
}
/* Returns the kind of template specialization we are currently
processing, given that it's declaration contained N_CLASS_SCOPES
explicit scope qualifications. */
tmpl_spec_kind
current_tmpl_spec_kind (n_class_scopes)
int n_class_scopes;
{
int n_template_parm_scopes = 0;
int seen_specialization_p = 0;
int innermost_specialization_p = 0;
struct binding_level *b;
/* Scan through the template parameter scopes. */
for (b = current_binding_level; b->template_parms_p; b = b->level_chain)
{
/* If we see a specialization scope inside a parameter scope,
then something is wrong. That corresponds to a declaration
like:
template <class T> template <> ...
which is always illegal since [temp.expl.spec] forbids the
specialization of a class member template if the enclosing
class templates are not explicitly specialized as well. */
if (b->template_spec_p)
{
if (n_template_parm_scopes == 0)
innermost_specialization_p = 1;
else
seen_specialization_p = 1;
}
else if (seen_specialization_p == 1)
return tsk_invalid_member_spec;
++n_template_parm_scopes;
}
/* Handle explicit instantiations. */
if (processing_explicit_instantiation)
{
if (n_template_parm_scopes != 0)
/* We've seen a template parameter list during an explicit
instantiation. For example:
template <class T> template void f(int);
This is erroneous. */
return tsk_invalid_expl_inst;
else
return tsk_expl_inst;
}
if (n_template_parm_scopes < n_class_scopes)
/* We've not seen enough template headers to match all the
specialized classes present. For example:
template <class T> void R<T>::S<T>::f(int);
This is illegal; there needs to be one set of template
parameters for each class. */
return tsk_insufficient_parms;
else if (n_template_parm_scopes == n_class_scopes)
/* We're processing a non-template declaration (even though it may
be a member of a template class.) For example:
template <class T> void S<T>::f(int);
The `class T' maches the `S<T>', leaving no template headers
corresponding to the `f'. */
return tsk_none;
else if (n_template_parm_scopes > n_class_scopes + 1)
/* We've got too many template headers. For example:
template <> template <class T> void f (T);
There need to be more enclosing classes. */
return tsk_excessive_parms;
else
/* This must be a template. It's of the form:
template <class T> template <class U> void S<T>::f(U);
This is a specialization if the innermost level was a
specialization; otherwise it's just a definition of the
template. */
return innermost_specialization_p ? tsk_expl_spec : tsk_template;
} }
void void
@ -806,6 +896,38 @@ pushlevel (tag_transparent)
keep_next_level_flag = 0; keep_next_level_flag = 0;
} }
/* Enter a new scope. The KIND indicates what kind of scope is being
created. */
void
begin_scope (sk)
scope_kind sk;
{
pushlevel (0);
switch (sk)
{
case sk_template_spec:
current_binding_level->template_spec_p = 1;
/* Fall through. */
case sk_template_parms:
current_binding_level->template_parms_p = 1;
break;
default:
my_friendly_abort (20000309);
}
}
/* Exit the current scope. */
void
finish_scope ()
{
poplevel (0, 0, 0);
}
void void
note_level_for_for () note_level_for_for ()
{ {
@ -2381,7 +2503,7 @@ maybe_push_to_top_level (pseudo)
inserted into namespace level, finish_file wouldn't find them inserted into namespace level, finish_file wouldn't find them
when doing pending instantiations. Therefore, don't stop at when doing pending instantiations. Therefore, don't stop at
namespace level, but continue until :: . */ namespace level, but continue until :: . */
if (b == global_binding_level || (pseudo && b->pseudo_global)) if (b == global_binding_level || (pseudo && b->template_parms_p))
break; break;
old_bindings = store_bindings (b->names, old_bindings); old_bindings = store_bindings (b->names, old_bindings);
@ -2590,7 +2712,7 @@ maybe_process_template_type_declaration (type, globalize, b)
friend case, push_template_decl will already have put the friend case, push_template_decl will already have put the
friend into global scope, if appropriate. */ friend into global scope, if appropriate. */
if (TREE_CODE (type) != ENUMERAL_TYPE if (TREE_CODE (type) != ENUMERAL_TYPE
&& !globalize && b->pseudo_global && !globalize && b->template_parms_p
&& b->level_chain->parm_flag == 2) && b->level_chain->parm_flag == 2)
{ {
finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type)); finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
@ -2675,7 +2797,7 @@ pushtag (name, type, globalize)
if (!context) if (!context)
context = current_namespace; context = current_namespace;
if ((b->pseudo_global && b->level_chain->parm_flag == 2) if ((b->template_parms_p && b->level_chain->parm_flag == 2)
|| b->parm_flag == 2) || b->parm_flag == 2)
in_class = 1; in_class = 1;
@ -4195,29 +4317,6 @@ maybe_push_decl (decl)
return pushdecl (decl); return pushdecl (decl);
} }
#if 0
/* This function is used to push the mangled decls for nested types into
the appropriate scope. Previously pushdecl_top_level was used, but that
is incorrect for members of local classes. */
void
pushdecl_nonclass_level (x)
tree x;
{
struct binding_level *b = current_binding_level;
my_friendly_assert (b->parm_flag != 2, 180);
#if 0
/* Get out of template binding levels */
while (b->pseudo_global)
b = b->level_chain;
#endif
pushdecl_with_scope (x, b);
}
#endif
/* Make the declaration(s) of X appear in CLASS scope /* Make the declaration(s) of X appear in CLASS scope
under the name NAME. */ under the name NAME. */
@ -4969,9 +5068,9 @@ lookup_tag (form, name, binding_level, thislevel_only)
int thislevel_only; int thislevel_only;
{ {
register struct binding_level *level; register struct binding_level *level;
/* Non-zero if, we should look past a pseudo-global level, even if /* Non-zero if, we should look past a template parameter level, even
THISLEVEL_ONLY. */ if THISLEVEL_ONLY. */
int allow_pseudo_global = 1; int allow_template_parms_p = 1;
for (level = binding_level; level; level = level->level_chain) for (level = binding_level; level; level = level->level_chain)
{ {
@ -4990,11 +5089,11 @@ lookup_tag (form, name, binding_level, thislevel_only)
{ {
tree old = binding_for_name (name, tail); tree old = binding_for_name (name, tail);
/* If we just skipped past a pseudo global level, even /* If we just skipped past a template parameter level,
though THISLEVEL_ONLY, and we find a template class even though THISLEVEL_ONLY, and we find a template
declaration, then we use the _TYPE node for the class declaration, then we use the _TYPE node for the
template. See the example below. */ template. See the example below. */
if (thislevel_only && !allow_pseudo_global if (thislevel_only && !allow_template_parms_p
&& old && BINDING_VALUE (old) && old && BINDING_VALUE (old)
&& DECL_CLASS_TEMPLATE_P (BINDING_VALUE (old))) && DECL_CLASS_TEMPLATE_P (BINDING_VALUE (old)))
old = TREE_TYPE (BINDING_VALUE (old)); old = TREE_TYPE (BINDING_VALUE (old));
@ -5037,7 +5136,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
} }
if (thislevel_only && ! level->tag_transparent) if (thislevel_only && ! level->tag_transparent)
{ {
if (level->pseudo_global && allow_pseudo_global) if (level->template_parms_p && allow_template_parms_p)
{ {
/* We must deal with cases like this: /* We must deal with cases like this:
@ -5050,7 +5149,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
template parameters, rather than the (surrounding) template parameters, rather than the (surrounding)
namespace level. Thus, we keep going one more level, namespace level. Thus, we keep going one more level,
even though THISLEVEL_ONLY is non-zero. */ even though THISLEVEL_ONLY is non-zero. */
allow_pseudo_global = 0; allow_template_parms_p = 0;
continue; continue;
} }
else else
@ -8680,98 +8779,77 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
return decl; return decl;
if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator) if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator)
DECL_CONSTRUCTOR_P (decl) = 1;
/* Function gets the ugly name, field gets the nice one. This call
may change the type of the function (because of default
parameters)! */
if (ctype != NULL_TREE)
grokclassfn (ctype, decl, flags, quals);
decl = check_explicit_specialization (orig_declarator, decl,
template_count,
2 * (funcdef_flag != 0) +
4 * (friendp != 0));
if (decl == error_mark_node)
return NULL_TREE;
if (ctype != NULL_TREE
&& (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
&& check)
{ {
tree tmp; tree old_decl;
/* Just handle constructors here. We could do this
inside the following if stmt, but I think
that the code is more legible by breaking this
case out. See comments below for what each of
the following calls is supposed to do. */
DECL_CONSTRUCTOR_P (decl) = 1;
grokclassfn (ctype, decl, flags, quals); old_decl = check_classfn (ctype, decl);
decl = check_explicit_specialization (orig_declarator, decl, if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
template_count, /* Because grokfndecl is always supposed to return a
2 * (funcdef_flag != 0) + FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
4 * (friendp != 0)); here. We depend on our callers to figure out that its
if (decl == error_mark_node) really a template that's being returned. */
return NULL_TREE; old_decl = DECL_TEMPLATE_RESULT (old_decl);
if ((! TYPE_FOR_JAVA (ctype) || check_java_method (decl)) if (old_decl && DECL_STATIC_FUNCTION_P (old_decl)
&& check) && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
{ {
tmp = check_classfn (ctype, decl); /* Remove the `this' parm added by grokclassfn.
XXX Isn't this done in start_function, too? */
if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL) revert_static_member_fn (&decl, NULL, NULL);
tmp = DECL_TEMPLATE_RESULT(tmp); last_function_parms = TREE_CHAIN (last_function_parms);
if (tmp && DECL_ARTIFICIAL (tmp))
cp_error ("definition of implicitly-declared `%D'", tmp);
if (tmp && duplicate_decls (decl, tmp))
return tmp;
} }
if (! grok_ctor_properties (ctype, decl)) if (old_decl && DECL_ARTIFICIAL (old_decl))
return NULL_TREE; cp_error ("definition of implicitly-declared `%D'", old_decl);
}
else
{
tree tmp;
/* Function gets the ugly name, field gets the nice one. if (old_decl)
This call may change the type of the function (because
of default parameters)! */
if (ctype != NULL_TREE)
grokclassfn (ctype, decl, flags, quals);
decl = check_explicit_specialization (orig_declarator, decl,
template_count,
2 * (funcdef_flag != 0) +
4 * (friendp != 0));
if (decl == error_mark_node)
return NULL_TREE;
if (ctype != NULL_TREE
&& (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
&& check)
{ {
tmp = check_classfn (ctype, decl); /* Since we've smashed OLD_DECL to its
DECL_TEMPLATE_RESULT, we must do the same to DECL. */
if (TREE_CODE (decl) == TEMPLATE_DECL)
decl = DECL_TEMPLATE_RESULT (decl);
if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL) /* Attempt to merge the declarations. This can fail, in
tmp = DECL_TEMPLATE_RESULT (tmp); the case of some illegal specialization declarations. */
if (!duplicate_decls (decl, old_decl))
if (tmp && DECL_STATIC_FUNCTION_P (tmp) cp_error ("no `%#D' member function declared in class `%T'",
&& TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) decl, ctype);
{ return old_decl;
/* Remove the `this' parm added by grokclassfn.
XXX Isn't this done in start_function, too? */
revert_static_member_fn (&decl, NULL, NULL);
last_function_parms = TREE_CHAIN (last_function_parms);
}
if (tmp && DECL_ARTIFICIAL (tmp))
cp_error ("definition of implicitly-declared `%D'", tmp);
if (tmp)
{
/* Attempt to merge the declarations. This can fail, in
the case of some illegal specialization declarations. */
if (!duplicate_decls (decl, tmp))
cp_error ("no `%#D' member function declared in class `%T'",
decl, ctype);
return tmp;
}
}
if (ctype == NULL_TREE || check)
return decl;
if (virtualp)
{
DECL_VIRTUAL_P (decl) = 1;
if (DECL_VINDEX (decl) == NULL_TREE)
DECL_VINDEX (decl) = error_mark_node;
IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
} }
} }
if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl))
return NULL_TREE;
if (ctype == NULL_TREE || check)
return decl;
if (virtualp)
{
DECL_VIRTUAL_P (decl) = 1;
if (DECL_VINDEX (decl) == NULL_TREE)
DECL_VINDEX (decl) = error_mark_node;
IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
}
return decl; return decl;
} }

View File

@ -1358,6 +1358,8 @@ check_classfn (ctype, function)
tree *end = 0; tree *end = 0;
if (DECL_USE_TEMPLATE (function) if (DECL_USE_TEMPLATE (function)
&& !(TREE_CODE (function) == TEMPLATE_DECL
&& DECL_TEMPLATE_SPECIALIZATION (function))
&& is_member_template (DECL_TI_TEMPLATE (function))) && is_member_template (DECL_TI_TEMPLATE (function)))
/* Since this is a specialization of a member template, /* Since this is a specialization of a member template,
we're not going to find the declaration in the class. we're not going to find the declaration in the class.

View File

@ -551,8 +551,7 @@ begin_template_parm_list ()
pushtag contains special code to call pushdecl_with_scope on the pushtag contains special code to call pushdecl_with_scope on the
TEMPLATE_DECL for S2. */ TEMPLATE_DECL for S2. */
pushlevel (0); begin_scope (sk_template_parms);
declare_pseudo_global_level ();
++processing_template_decl; ++processing_template_decl;
++processing_template_parmlist; ++processing_template_parmlist;
note_template_header (0); note_template_header (0);
@ -596,6 +595,7 @@ check_specialization_scope ()
void void
begin_specialization () begin_specialization ()
{ {
begin_scope (sk_template_spec);
note_template_header (1); note_template_header (1);
check_specialization_scope (); check_specialization_scope ();
} }
@ -606,6 +606,7 @@ begin_specialization ()
void void
end_specialization () end_specialization ()
{ {
finish_scope ();
reset_specialization (); reset_specialization ();
} }
@ -1166,109 +1167,99 @@ check_explicit_specialization (declarator, decl, template_count, flags)
int specialization = 0; int specialization = 0;
int explicit_instantiation = 0; int explicit_instantiation = 0;
int member_specialization = 0; int member_specialization = 0;
tree ctype = DECL_CLASS_CONTEXT (decl); tree ctype = DECL_CLASS_CONTEXT (decl);
tree dname = DECL_NAME (decl); tree dname = DECL_NAME (decl);
tmpl_spec_kind tsk;
if (processing_specialization) tsk = current_tmpl_spec_kind (template_count);
switch (tsk)
{ {
/* The last template header was of the form template <>. */ case tsk_none:
if (processing_specialization)
if (template_header_count > template_count)
{ {
/* There were more template headers than qualifying template
classes. */
if (template_header_count - template_count > 1)
/* There shouldn't be that many template parameter lists.
There can be at most one parameter list for every
qualifying class, plus one for the function itself. */
cp_error ("too many template parameter lists in declaration of `%D'", decl);
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
if (ctype)
member_specialization = 1;
else
specialization = 1;
}
else if (template_header_count == template_count)
{
/* The counts are equal. So, this might be a
specialization, but it is not a specialization of a
member template. It might be something like
template <class T> struct S {
void f(int i);
};
template <>
void S<int>::f(int i) {} */
specialization = 1; specialization = 1;
SET_DECL_TEMPLATE_SPECIALIZATION (decl); SET_DECL_TEMPLATE_SPECIALIZATION (decl);
} }
else else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
{ {
/* This cannot be an explicit specialization. There are not if (is_friend)
enough headers for all of the qualifying classes. For /* This could be something like:
example, we might have:
template <>
void S<int>::T<char>::f();
But, we're missing another template <>. */ template <class T> void f(T);
cp_error("too few template parameter lists in declaration of `%D'", decl); class S { friend void f<>(int); } */
return decl; specialization = 1;
} else
} {
else if (processing_explicit_instantiation) /* This case handles bogus declarations like template <>
{ template <class T> void f<int>(); */
if (template_header_count)
cp_error ("template parameter list used in explicit instantiation"); cp_error ("template-id `%D' in declaration of primary template",
declarator);
return decl;
}
}
break;
case tsk_invalid_member_spec:
/* The error has already been reported in
check_specialization_scope. */
return error_mark_node;
case tsk_invalid_expl_inst:
cp_error ("template parameter list used in explicit instantiation");
/* Fall through. */
case tsk_expl_inst:
if (have_def) if (have_def)
cp_error ("definition provided for explicit instantiation"); cp_error ("definition provided for explicit instantiation");
explicit_instantiation = 1; explicit_instantiation = 1;
} break;
else if (ctype != NULL_TREE
&& !TYPE_BEING_DEFINED (ctype)
&& CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
&& !is_friend)
{
/* This case catches outdated code that looks like this:
template <class T> struct S { void f(); }; case tsk_excessive_parms:
void S<int>::f() {} // Missing template <> cp_error ("too many template parameter lists in declaration of `%D'",
decl);
return error_mark_node;
We disable this check when the type is being defined to /* Fall through. */
avoid complaining about default compiler-generated case tsk_expl_spec:
constructors, destructors, and assignment operators. SET_DECL_TEMPLATE_SPECIALIZATION (decl);
Since the type is an instantiation, not a specialization, if (ctype)
these are the only functions that can be defined before member_specialization = 1;
the class is complete. */ else
specialization = 1;
/* If they said break;
template <class T> void S<int>::f() {}
that's bogus. */ case tsk_insufficient_parms:
if (template_header_count) if (template_header_count)
{ {
cp_error ("template parameters specified in specialization"); cp_error("too few template parameter lists in declaration of `%D'",
decl);
return decl; return decl;
} }
else if (ctype != NULL_TREE
&& !TYPE_BEING_DEFINED (ctype)
&& CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
&& !is_friend)
{
/* For backwards compatibility, we accept:
if (pedantic) template <class T> struct S { void f(); };
cp_pedwarn void S<int>::f() {} // Missing template <>
("explicit specialization not preceded by `template <>'");
specialization = 1;
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
}
else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
{
if (is_friend)
/* This could be something like:
template <class T> void f(T); That used to be legal C++. */
class S { friend void f<>(int); } */ if (pedantic)
specialization = 1; cp_pedwarn
else ("explicit specialization not preceded by `template <>'");
specialization = 1;
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
}
break;
case tsk_template:
if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
{ {
/* This case handles bogus declarations like template <> /* This case handles bogus declarations like template <>
template <class T> void f<int>(); */ template <class T> void f<int>(); */
@ -1277,6 +1268,22 @@ check_explicit_specialization (declarator, decl, template_count, flags)
declarator); declarator);
return decl; return decl;
} }
if (ctype && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
/* This is a specialization of a member template, without
specialization the containing class. Something like:
template <class T> struct S {
template <class U> void f (U);
};
template <> template <class U> void S<int>::f(U) {}
That's a specialization -- but of the entire template. */
specialization = 1;
break;
default:
my_friendly_abort (20000309);
} }
if (specialization || member_specialization) if (specialization || member_specialization)
@ -1474,10 +1481,19 @@ check_explicit_specialization (declarator, decl, template_count, flags)
targs = new_targs; targs = new_targs;
} }
decl = instantiate_template (tmpl, targs); return instantiate_template (tmpl, targs);
return decl;
} }
/* If this is both a template specialization, then it's a
specialization of a member template of a template class.
In that case we want to return the TEMPLATE_DECL, not the
specialization of it. */
if (tsk == tsk_template)
{
SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
return tmpl;
}
/* If we though that the DECL was a member function, but it /* If we though that the DECL was a member function, but it
turns out to be specializing a static member function, turns out to be specializing a static member function,
make DECL a static member function as well. */ make DECL a static member function as well. */
@ -1504,7 +1520,7 @@ check_explicit_specialization (declarator, decl, template_count, flags)
we do not mangle S<int>::f() here. That's because it's we do not mangle S<int>::f() here. That's because it's
just an ordinary member function and doesn't need special just an ordinary member function and doesn't need special
treatment. We do this here so that the ordinary, treatment. We do this here so that the ordinary,
non-template, name-mangling algorith will not be used non-template, name-mangling algorithm will not be used
later. */ later. */
if ((is_member_template (tmpl) || ctype == NULL_TREE) if ((is_member_template (tmpl) || ctype == NULL_TREE)
&& name_mangling_version >= 1) && name_mangling_version >= 1)
@ -1863,11 +1879,10 @@ end_template_decl ()
return; return;
/* This matches the pushlevel in begin_template_parm_list. */ /* This matches the pushlevel in begin_template_parm_list. */
poplevel (0, 0, 0); finish_scope ();
--processing_template_decl; --processing_template_decl;
current_template_parms = TREE_CHAIN (current_template_parms); current_template_parms = TREE_CHAIN (current_template_parms);
(void) get_pending_sizes (); /* Why? */
} }
/* Given a template argument vector containing the template PARMS. /* Given a template argument vector containing the template PARMS.
@ -2370,7 +2385,7 @@ push_template_decl_real (decl, is_friend)
DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
/* See if this is a primary template. */ /* See if this is a primary template. */
primary = pseudo_global_level_p (); primary = template_parm_scope_p ();
if (primary) if (primary)
{ {
@ -2444,9 +2459,6 @@ push_template_decl_real (decl, is_friend)
tree a, t, current, parms; tree a, t, current, parms;
int i; int i;
if (CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
cp_error ("must specialize `%#T' before defining member `%#D'",
ctx, decl);
if (TREE_CODE (decl) == TYPE_DECL) if (TREE_CODE (decl) == TYPE_DECL)
{ {
if ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl))) if ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl)))
@ -5597,7 +5609,7 @@ tsubst_decl (t, args, type, in_decl)
template <class T> struct S { template <class T> struct S {
template <class U> friend void f(); template <class U> friend void f();
}; };
template <class U> friend void f() {} template <class U> void f() {}
template S<int>; template S<int>;
template void f<double>(); template void f<double>();
@ -7395,7 +7407,7 @@ instantiate_template (tmpl, targ_ptr)
if (spec != NULL_TREE) if (spec != NULL_TREE)
return spec; return spec;
if (DECL_TEMPLATE_INFO (tmpl)) if (DECL_TEMPLATE_INFO (tmpl) && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
{ {
/* The TMPL is a partial instantiation. To get a full set of /* The TMPL is a partial instantiation. To get a full set of
arguments we must add the arguments used to perform the arguments we must add the arguments used to perform the
@ -8944,6 +8956,8 @@ most_general_template (decl)
tree decl; tree decl;
{ {
while (DECL_TEMPLATE_INFO (decl) while (DECL_TEMPLATE_INFO (decl)
&& !(TREE_CODE (decl) == TEMPLATE_DECL
&& DECL_TEMPLATE_SPECIALIZATION (decl))
/* The DECL_TI_TEMPLATE can be a LOOKUP_EXPR or /* The DECL_TI_TEMPLATE can be a LOOKUP_EXPR or
IDENTIFIER_NODE in some cases. (See cp-tree.h for IDENTIFIER_NODE in some cases. (See cp-tree.h for
details.) */ details.) */

View File

@ -49,7 +49,7 @@ unsigned short X_one<T>::ret_id() {
return id; return id;
} }
export template <class T> template <class T2> // WARNING - export template <class T2> // WARNING -
bool compare_ge(T2 test) { bool compare_ge(T2 test) {
if (test > type) if (test > type)
return true; return true;

View File

@ -0,0 +1,16 @@
// Build don't run:
// Origin: Mark Mitchell <mark@codesourcery.com>
template <int n> struct A {
template <class T> A (T t);
template <class T> int f(T t) const;
};
template <> template<class T> int A<1>::f(T t) const {return 1;}
template <> template<class T> A<1>::A (T t) {}
int main() {
A<1> a (3);
a.f(1);
return 0;
}