This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: specializations of member templates
- To: gcc-patches at gcc dot gnu dot org
- Subject: C++ PATCH: specializations of member templates
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Sun, 12 Mar 2000 10:56:15 -0800
- Reply-to: mark at codesourcery dot com
The following is legal C++:
template <class T> struct S {
template <class U> void f(U);
};
template <> template <class U> void S<int>::f(U) { ... };
This says that even though `S<int>' is just an instantiation of `S',
the `S<int>::f' template is a specialization: all instances thereof
get the special body. We didn't support this. Now we do.
As a side-effect, we now issue an error message on:
template <class T> template <class T2> void f(T2) {}
which we didn't before.
I also cleaned up some portions of the code in the process. I've
started generalizing the code in check_explicit_specialization so that
we can use it for classes as well as functions. Also, I made a little
bit more progress towards using standard names for things whose names
are defined in the standard, and removed a large block of duplicated
code in grokfndecl. (We handled constructors and normal functions
with two nearly-identical blocks that had to be manually kept in
sync.)
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.
Index: g++.benjamin/tem05.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.benjamin/tem05.C,v
retrieving revision 1.2
diff -c -p -r1.2 tem05.C
*** tem05.C 1998/12/16 21:22:17 1.2
--- tem05.C 2000/03/12 18:39:14
*************** unsigned short X_one<T>::ret_id() {
*** 49,55 ****
return id;
}
! export template <class T> template <class T2> // WARNING -
bool compare_ge(T2 test) {
if (test > type)
return true;
--- 49,55 ----
return id;
}
! export template <class T2> // WARNING -
bool compare_ge(T2 test) {
if (test > type)
return true;
Index: g++.pt/memtemp93.C
===================================================================
RCS file: memtemp93.C
diff -N memtemp93.C
*** /dev/null Tue May 5 13:32:27 1998
--- memtemp93.C Sun Mar 12 10:39:16 2000
***************
*** 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;
+ }
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.415
diff -c -p -r1.415 cp-tree.h
*** cp-tree.h 2000/03/10 11:56:00 1.415
--- cp-tree.h 2000/03/12 18:35:42
*************** typedef enum cp_lvalue_kind {
*** 3043,3048 ****
--- 3043,3074 ----
clk_bitfield = 4, /* An lvalue for a bit-field. */
} 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).
Each language context defines how this variable should be set. */
extern int strict_prototype;
*************** extern int toplevel_bindings_p PARAMS
*** 3682,3691 ****
extern int namespace_bindings_p PARAMS ((void));
extern void keep_next_level PARAMS ((int));
extern int kept_level_p PARAMS ((void));
! extern void declare_pseudo_global_level PARAMS ((void));
! extern int pseudo_global_level_p PARAMS ((void));
extern void set_class_shadows PARAMS ((tree));
! extern void pushlevel PARAMS ((int));
extern void note_level_for_for PARAMS ((void));
extern void resume_level PARAMS ((struct binding_level *));
extern void delete_block PARAMS ((tree));
--- 3708,3717 ----
extern int namespace_bindings_p PARAMS ((void));
extern void keep_next_level PARAMS ((int));
extern int kept_level_p PARAMS ((void));
! extern int template_parm_scope_p PARAMS ((void));
extern void set_class_shadows PARAMS ((tree));
! extern void begin_scope PARAMS ((scope_kind));
! extern void finish_scope PARAMS ((void));
extern void note_level_for_for PARAMS ((void));
extern void resume_level PARAMS ((struct binding_level *));
extern void delete_block PARAMS ((tree));
*************** extern int local_variable_p
*** 3832,3837 ****
--- 3858,3864 ----
extern int nonstatic_local_decl_p PARAMS ((tree));
extern tree declare_global_var PARAMS ((tree, tree));
extern void register_dtor_fn PARAMS ((tree));
+ extern tmpl_spec_kind current_tmpl_spec_kind PARAMS ((int));
/* in decl2.c */
extern void init_decl2 PARAMS ((void));
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.565
diff -c -p -r1.565 decl.c
*** decl.c 2000/03/11 08:27:17 1.565
--- decl.c 2000/03/12 18:35:51
*************** struct binding_level
*** 456,468 ****
tree dead_vars_from_for;
/* 1 for the level that holds the parameters of a function.
! 2 for the level that holds a class declaration.
! 3 for levels that hold parameter declarations. */
! unsigned parm_flag : 4;
/* 1 means make a BLOCK for this level regardless of all else.
2 for temporary binding contours created by the compiler. */
! unsigned keep : 3;
/* Nonzero if this level "doesn't exist" for tags. */
unsigned tag_transparent : 1;
--- 456,467 ----
tree dead_vars_from_for;
/* 1 for the level that holds the parameters of a function.
! 2 for the level that holds a class declaration. */
! unsigned parm_flag : 2;
/* 1 means make a BLOCK for this level regardless of all else.
2 for temporary binding contours created by the compiler. */
! unsigned keep : 2;
/* Nonzero if this level "doesn't exist" for tags. */
unsigned tag_transparent : 1;
*************** struct binding_level
*** 472,482 ****
unsigned more_cleanups_ok : 1;
unsigned have_cleanups : 1;
! /* Nonzero if this level is for storing the decls for template
parameters and generic decls; these decls will be discarded and
replaced with a TEMPLATE_DECL. */
! unsigned pseudo_global : 1;
/* This is set for a namespace binding level. */
unsigned namespace_p : 1;
--- 471,486 ----
unsigned more_cleanups_ok : 1;
unsigned have_cleanups : 1;
! /* Nonzero if this scope is for storing the decls for template
parameters and generic decls; these decls will be discarded and
replaced with a TEMPLATE_DECL. */
! 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. */
unsigned namespace_p : 1;
*************** struct binding_level
*** 487,493 ****
/* True if this level corresponds to an EH region, as for a try block. */
unsigned eh_region : 1;
! /* One bit left for this word. */
#if defined(DEBUG_CP_BINDING_LEVELS)
/* Binding depth at which this level began. */
--- 491,497 ----
/* True if this level corresponds to an EH region, as for a try block. */
unsigned eh_region : 1;
! /* Four bits left for this word. */
#if defined(DEBUG_CP_BINDING_LEVELS)
/* Binding depth at which this level began. */
*************** innermost_nonclass_level ()
*** 704,718 ****
/* Nonzero if we are currently in a toplevel binding level. This
means either the global binding level or a namespace in a toplevel
binding level. Since there are no non-toplevel namespace levels,
! this really means any namespace or pseudo-global level. We also
! include a class whose context is toplevel. */
int
toplevel_bindings_p ()
{
struct binding_level *b = innermost_nonclass_level ();
! return b->namespace_p || b->pseudo_global;
}
/* Nonzero if this is a namespace scope, or if we are defining a class
--- 708,722 ----
/* Nonzero if we are currently in a toplevel binding level. This
means either the global binding level or a namespace in a toplevel
binding level. Since there are no non-toplevel namespace levels,
! this really means any namespace or template parameter level. We
! also include a class whose context is toplevel. */
int
toplevel_bindings_p ()
{
struct binding_level *b = innermost_nonclass_level ();
! return b->namespace_p || b->template_parms_p;
}
/* Nonzero if this is a namespace scope, or if we are defining a class
*************** kept_level_p ()
*** 750,773 ****
&& !current_binding_level->tag_transparent));
}
- void
- declare_pseudo_global_level ()
- {
- current_binding_level->pseudo_global = 1;
- }
-
static void
declare_namespace_level ()
{
current_binding_level->namespace_p = 1;
}
int
! pseudo_global_level_p ()
{
! return current_binding_level->pseudo_global;
}
void
set_class_shadows (shadows)
tree shadows;
--- 754,863 ----
&& !current_binding_level->tag_transparent));
}
static void
declare_namespace_level ()
{
current_binding_level->namespace_p = 1;
}
+ /* Returns non-zero if this scope was created to store template
+ parameters. */
+
int
! template_parm_scope_p ()
{
! 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
set_class_shadows (shadows)
tree shadows;
*************** pushlevel (tag_transparent)
*** 806,812 ****
--- 896,934 ----
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
note_level_for_for ()
{
current_binding_level->is_for_scope = 1;
*************** maybe_push_to_top_level (pseudo)
*** 2381,2387 ****
inserted into namespace level, finish_file wouldn't find them
when doing pending instantiations. Therefore, don't stop at
namespace level, but continue until :: . */
! if (b == global_binding_level || (pseudo && b->pseudo_global))
break;
old_bindings = store_bindings (b->names, old_bindings);
--- 2503,2509 ----
inserted into namespace level, finish_file wouldn't find them
when doing pending instantiations. Therefore, don't stop at
namespace level, but continue until :: . */
! if (b == global_binding_level || (pseudo && b->template_parms_p))
break;
old_bindings = store_bindings (b->names, old_bindings);
*************** maybe_process_template_type_declaration
*** 2590,2596 ****
friend case, push_template_decl will already have put the
friend into global scope, if appropriate. */
if (TREE_CODE (type) != ENUMERAL_TYPE
! && !globalize && b->pseudo_global
&& b->level_chain->parm_flag == 2)
{
finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
--- 2712,2718 ----
friend case, push_template_decl will already have put the
friend into global scope, if appropriate. */
if (TREE_CODE (type) != ENUMERAL_TYPE
! && !globalize && b->template_parms_p
&& b->level_chain->parm_flag == 2)
{
finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
*************** pushtag (name, type, globalize)
*** 2675,2681 ****
if (!context)
context = current_namespace;
! if ((b->pseudo_global && b->level_chain->parm_flag == 2)
|| b->parm_flag == 2)
in_class = 1;
--- 2797,2803 ----
if (!context)
context = current_namespace;
! if ((b->template_parms_p && b->level_chain->parm_flag == 2)
|| b->parm_flag == 2)
in_class = 1;
*************** maybe_push_decl (decl)
*** 4195,4223 ****
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
under the name NAME. */
--- 4317,4322 ----
*************** lookup_tag (form, name, binding_level, t
*** 4969,4977 ****
int thislevel_only;
{
register struct binding_level *level;
! /* Non-zero if, we should look past a pseudo-global level, even if
! THISLEVEL_ONLY. */
! int allow_pseudo_global = 1;
for (level = binding_level; level; level = level->level_chain)
{
--- 5068,5076 ----
int thislevel_only;
{
register struct binding_level *level;
! /* Non-zero if, we should look past a template parameter level, even
! if THISLEVEL_ONLY. */
! int allow_template_parms_p = 1;
for (level = binding_level; level; level = level->level_chain)
{
*************** lookup_tag (form, name, binding_level, t
*** 4990,5000 ****
{
tree old = binding_for_name (name, tail);
! /* If we just skipped past a pseudo global level, even
! though THISLEVEL_ONLY, and we find a template class
! declaration, then we use the _TYPE node for the
template. See the example below. */
! if (thislevel_only && !allow_pseudo_global
&& old && BINDING_VALUE (old)
&& DECL_CLASS_TEMPLATE_P (BINDING_VALUE (old)))
old = TREE_TYPE (BINDING_VALUE (old));
--- 5089,5099 ----
{
tree old = binding_for_name (name, tail);
! /* If we just skipped past a template parameter level,
! even though THISLEVEL_ONLY, and we find a template
! class declaration, then we use the _TYPE node for the
template. See the example below. */
! if (thislevel_only && !allow_template_parms_p
&& old && BINDING_VALUE (old)
&& DECL_CLASS_TEMPLATE_P (BINDING_VALUE (old)))
old = TREE_TYPE (BINDING_VALUE (old));
*************** lookup_tag (form, name, binding_level, t
*** 5037,5043 ****
}
if (thislevel_only && ! level->tag_transparent)
{
! if (level->pseudo_global && allow_pseudo_global)
{
/* We must deal with cases like this:
--- 5136,5142 ----
}
if (thislevel_only && ! level->tag_transparent)
{
! if (level->template_parms_p && allow_template_parms_p)
{
/* We must deal with cases like this:
*************** lookup_tag (form, name, binding_level, t
*** 5050,5056 ****
template parameters, rather than the (surrounding)
namespace level. Thus, we keep going one more level,
even though THISLEVEL_ONLY is non-zero. */
! allow_pseudo_global = 0;
continue;
}
else
--- 5149,5155 ----
template parameters, rather than the (surrounding)
namespace level. Thus, we keep going one more level,
even though THISLEVEL_ONLY is non-zero. */
! allow_template_parms_p = 0;
continue;
}
else
*************** grokfndecl (ctype, type, declarator, ori
*** 8680,8777 ****
return decl;
if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator)
! {
! tree tmp;
! /* 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);
!
! 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 ((! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
! && check)
! {
! tmp = check_classfn (ctype, decl);
! if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
! tmp = DECL_TEMPLATE_RESULT(tmp);
! 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))
! return NULL_TREE;
! }
! else
{
! tree tmp;
! /* 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)
{
! tmp = check_classfn (ctype, decl);
! if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
! tmp = DECL_TEMPLATE_RESULT (tmp);
! if (tmp && DECL_STATIC_FUNCTION_P (tmp)
! && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
! {
! /* 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;
! }
}
return decl;
}
--- 8779,8855 ----
return decl;
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 old_decl;
! old_decl = check_classfn (ctype, decl);
!
! if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
! /* Because grokfndecl is always supposed to return a
! FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
! here. We depend on our callers to figure out that its
! really a template that's being returned. */
! old_decl = DECL_TEMPLATE_RESULT (old_decl);
! if (old_decl && DECL_STATIC_FUNCTION_P (old_decl)
! && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
{
! /* 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 (old_decl && DECL_ARTIFICIAL (old_decl))
! cp_error ("definition of implicitly-declared `%D'", old_decl);
! if (old_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);
! /* Attempt to merge the declarations. This can fail, in
! the case of some illegal specialization declarations. */
! if (!duplicate_decls (decl, old_decl))
! cp_error ("no `%#D' member function declared in class `%T'",
! decl, ctype);
! return old_decl;
}
+ }
! 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;
}
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.317
diff -c -p -r1.317 decl2.c
*** decl2.c 2000/03/10 11:56:00 1.317
--- decl2.c 2000/03/12 18:35:54
*************** check_classfn (ctype, function)
*** 1358,1363 ****
--- 1358,1365 ----
tree *end = 0;
if (DECL_USE_TEMPLATE (function)
+ && !(TREE_CODE (function) == TEMPLATE_DECL
+ && DECL_TEMPLATE_SPECIALIZATION (function))
&& is_member_template (DECL_TI_TEMPLATE (function)))
/* Since this is a specialization of a member template,
we're not going to find the declaration in the class.
Index: pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.404
diff -c -p -r1.404 pt.c
*** pt.c 2000/03/11 00:23:18 1.404
--- pt.c 2000/03/12 18:36:00
*************** begin_template_parm_list ()
*** 551,558 ****
pushtag contains special code to call pushdecl_with_scope on the
TEMPLATE_DECL for S2. */
! pushlevel (0);
! declare_pseudo_global_level ();
++processing_template_decl;
++processing_template_parmlist;
note_template_header (0);
--- 551,557 ----
pushtag contains special code to call pushdecl_with_scope on the
TEMPLATE_DECL for S2. */
! begin_scope (sk_template_parms);
++processing_template_decl;
++processing_template_parmlist;
note_template_header (0);
*************** check_specialization_scope ()
*** 596,601 ****
--- 595,601 ----
void
begin_specialization ()
{
+ begin_scope (sk_template_spec);
note_template_header (1);
check_specialization_scope ();
}
*************** begin_specialization ()
*** 606,611 ****
--- 606,612 ----
void
end_specialization ()
{
+ finish_scope ();
reset_specialization ();
}
*************** check_explicit_specialization (declarato
*** 1166,1274 ****
int specialization = 0;
int explicit_instantiation = 0;
int member_specialization = 0;
-
tree ctype = DECL_CLASS_CONTEXT (decl);
tree dname = DECL_NAME (decl);
! if (processing_specialization)
! {
! /* The last template header was of the form template <>. */
!
! 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;
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
}
! else
{
! /* This cannot be an explicit specialization. There are not
! enough headers for all of the qualifying classes. For
! example, we might have:
!
! template <>
! void S<int>::T<char>::f();
! But, we're missing another template <>. */
! cp_error("too few template parameter lists in declaration of `%D'", decl);
! return decl;
! }
! }
! else if (processing_explicit_instantiation)
! {
! if (template_header_count)
! cp_error ("template parameter list used in explicit instantiation");
!
if (have_def)
cp_error ("definition provided for explicit instantiation");
!
explicit_instantiation = 1;
! }
! 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(); };
! void S<int>::f() {} // Missing template <>
!
! We disable this check when the type is being defined to
! avoid complaining about default compiler-generated
! constructors, destructors, and assignment operators.
! Since the type is an instantiation, not a specialization,
! these are the only functions that can be defined before
! the class is complete. */
!
! /* If they said
! template <class T> void S<int>::f() {}
! that's bogus. */
if (template_header_count)
{
! cp_error ("template parameters specified in specialization");
return decl;
}
! if (pedantic)
! cp_pedwarn
! ("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);
! class S { friend void f<>(int); } */
! specialization = 1;
! else
{
/* This case handles bogus declarations like template <>
template <class T> void f<int>(); */
--- 1167,1265 ----
int specialization = 0;
int explicit_instantiation = 0;
int member_specialization = 0;
tree ctype = DECL_CLASS_CONTEXT (decl);
tree dname = DECL_NAME (decl);
+ tmpl_spec_kind tsk;
! tsk = current_tmpl_spec_kind (template_count);
! switch (tsk)
! {
! case tsk_none:
! if (processing_specialization)
{
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);
! class S { friend void f<>(int); } */
! specialization = 1;
! else
! {
! /* This case handles bogus declarations like template <>
! template <class T> void f<int>(); */
!
! 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)
cp_error ("definition provided for explicit instantiation");
!
explicit_instantiation = 1;
! break;
!
! case tsk_excessive_parms:
! cp_error ("too many template parameter lists in declaration of `%D'",
! decl);
! return error_mark_node;
!
! /* Fall through. */
! case tsk_expl_spec:
! SET_DECL_TEMPLATE_SPECIALIZATION (decl);
! if (ctype)
! member_specialization = 1;
! else
! specialization = 1;
! break;
!
! case tsk_insufficient_parms:
if (template_header_count)
{
! cp_error("too few template parameter lists in declaration of `%D'",
! decl);
return decl;
}
+ else if (ctype != NULL_TREE
+ && !TYPE_BEING_DEFINED (ctype)
+ && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
+ && !is_friend)
+ {
+ /* For backwards compatibility, we accept:
! template <class T> struct S { void f(); };
! void S<int>::f() {} // Missing template <>
! That used to be legal C++. */
! if (pedantic)
! cp_pedwarn
! ("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 <>
template <class T> void f<int>(); */
*************** check_explicit_specialization (declarato
*** 1277,1282 ****
--- 1268,1289 ----
declarator);
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)
*************** check_explicit_specialization (declarato
*** 1474,1483 ****
targs = new_targs;
}
! decl = instantiate_template (tmpl, targs);
! return decl;
}
!
/* If we though that the DECL was a member function, but it
turns out to be specializing a static member function,
make DECL a static member function as well. */
--- 1481,1499 ----
targs = new_targs;
}
! return instantiate_template (tmpl, targs);
}
!
! /* 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
turns out to be specializing a static member function,
make DECL a static member function as well. */
*************** check_explicit_specialization (declarato
*** 1504,1510 ****
we do not mangle S<int>::f() here. That's because it's
just an ordinary member function and doesn't need special
treatment. We do this here so that the ordinary,
! non-template, name-mangling algorith will not be used
later. */
if ((is_member_template (tmpl) || ctype == NULL_TREE)
&& name_mangling_version >= 1)
--- 1520,1526 ----
we do not mangle S<int>::f() here. That's because it's
just an ordinary member function and doesn't need special
treatment. We do this here so that the ordinary,
! non-template, name-mangling algorithm will not be used
later. */
if ((is_member_template (tmpl) || ctype == NULL_TREE)
&& name_mangling_version >= 1)
*************** end_template_decl ()
*** 1863,1873 ****
return;
/* This matches the pushlevel in begin_template_parm_list. */
! poplevel (0, 0, 0);
--processing_template_decl;
current_template_parms = TREE_CHAIN (current_template_parms);
- (void) get_pending_sizes (); /* Why? */
}
/* Given a template argument vector containing the template PARMS.
--- 1879,1888 ----
return;
/* This matches the pushlevel in begin_template_parm_list. */
! finish_scope ();
--processing_template_decl;
current_template_parms = TREE_CHAIN (current_template_parms);
}
/* Given a template argument vector containing the template PARMS.
*************** push_template_decl_real (decl, is_friend
*** 2370,2376 ****
DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
/* See if this is a primary template. */
! primary = pseudo_global_level_p ();
if (primary)
{
--- 2385,2391 ----
DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
/* See if this is a primary template. */
! primary = template_parm_scope_p ();
if (primary)
{
*************** push_template_decl_real (decl, is_friend
*** 2444,2452 ****
tree a, t, current, parms;
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 ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl)))
--- 2459,2464 ----
*************** tsubst_decl (t, args, type, in_decl)
*** 5601,5607 ****
template <class T> struct S {
template <class U> friend void f();
};
! template <class U> friend void f() {}
template S<int>;
template void f<double>();
--- 5613,5619 ----
template <class T> struct S {
template <class U> friend void f();
};
! template <class U> void f() {}
template S<int>;
template void f<double>();
*************** instantiate_template (tmpl, targ_ptr)
*** 7399,7405 ****
if (spec != NULL_TREE)
return spec;
! if (DECL_TEMPLATE_INFO (tmpl))
{
/* The TMPL is a partial instantiation. To get a full set of
arguments we must add the arguments used to perform the
--- 7411,7417 ----
if (spec != NULL_TREE)
return spec;
! if (DECL_TEMPLATE_INFO (tmpl) && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
{
/* The TMPL is a partial instantiation. To get a full set of
arguments we must add the arguments used to perform the
*************** most_general_template (decl)
*** 8948,8953 ****
--- 8960,8967 ----
tree 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
IDENTIFIER_NODE in some cases. (See cp-tree.h for
details.) */