diff options
author | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-03-12 18:47:52 +0000 |
---|---|---|
committer | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-03-12 18:47:52 +0000 |
commit | 3467e46177b0c62ff6506a5aa547968515835c2d (patch) | |
tree | cc6c6ee272891ffacecf2646e5035c7b822cdff4 | |
parent | 6437c7c83907e61401606123623161b5c9129e4d (diff) | |
download | gcc-3467e46177b0c62ff6506a5aa547968515835c2d.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32494 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/cp/ChangeLog | 39 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 33 | ||||
-rw-r--r-- | gcc/cp/decl.c | 344 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 2 | ||||
-rw-r--r-- | gcc/cp/pt.c | 206 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.benjamin/tem05.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/memtemp93.C | 16 |
7 files changed, 409 insertions, 233 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 37be27878c6..0e4812c6073 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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> * lex.c (whitespace_cr): Compress consecutive calls to warning(). diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9c348a0a53f..28f67c072f0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3043,6 +3043,32 @@ typedef enum cp_lvalue_kind { 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; @@ -3682,10 +3708,10 @@ extern int toplevel_bindings_p PARAMS ((void)); 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 int template_parm_scope_p PARAMS ((void)); 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 resume_level PARAMS ((struct binding_level *)); 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 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)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 20a6aba6f49..5b6e6a9d8f6 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -456,13 +456,12 @@ struct binding_level 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; + 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 : 3; + unsigned keep : 2; /* Nonzero if this level "doesn't exist" for tags. */ unsigned tag_transparent : 1; @@ -472,10 +471,15 @@ struct binding_level unsigned more_cleanups_ok : 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 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. */ 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. */ unsigned eh_region : 1; - /* One bit left for this word. */ + /* Four bits left for this word. */ #if defined(DEBUG_CP_BINDING_LEVELS) /* 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 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. */ + 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->pseudo_global; + return b->namespace_p || b->template_parms_p; } /* 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)); } -void -declare_pseudo_global_level () -{ - current_binding_level->pseudo_global = 1; -} - static void declare_namespace_level () { current_binding_level->namespace_p = 1; } +/* Returns non-zero if this scope was created to store template + parameters. */ + 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 @@ -806,6 +896,38 @@ pushlevel (tag_transparent) 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 () { @@ -2381,7 +2503,7 @@ maybe_push_to_top_level (pseudo) 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)) + if (b == global_binding_level || (pseudo && b->template_parms_p)) break; 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 into global scope, if appropriate. */ if (TREE_CODE (type) != ENUMERAL_TYPE - && !globalize && b->pseudo_global + && !globalize && b->template_parms_p && b->level_chain->parm_flag == 2) { finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type)); @@ -2675,7 +2797,7 @@ pushtag (name, type, globalize) if (!context) 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) in_class = 1; @@ -4195,29 +4317,6 @@ maybe_push_decl (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 under the name NAME. */ @@ -4969,9 +5068,9 @@ lookup_tag (form, name, binding_level, thislevel_only) 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; + /* 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) { @@ -4990,11 +5089,11 @@ lookup_tag (form, name, binding_level, thislevel_only) { 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 + /* 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_pseudo_global + if (thislevel_only && !allow_template_parms_p && old && BINDING_VALUE (old) && DECL_CLASS_TEMPLATE_P (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 (level->pseudo_global && allow_pseudo_global) + if (level->template_parms_p && allow_template_parms_p) { /* 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) namespace level. Thus, we keep going one more level, even though THISLEVEL_ONLY is non-zero. */ - allow_pseudo_global = 0; + allow_template_parms_p = 0; continue; } else @@ -8680,98 +8779,77 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals, 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); + 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 (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 + if (ctype != NULL_TREE + && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl)) + && check) { - tree tmp; + tree old_decl; - /* 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); + old_decl = check_classfn (ctype, decl); - 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 (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 (ctype != NULL_TREE - && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl)) - && check) + if (old_decl && DECL_STATIC_FUNCTION_P (old_decl) + && 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? */ + 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 (tmp && TREE_CODE (tmp) == TEMPLATE_DECL) - tmp = DECL_TEMPLATE_RESULT (tmp); + 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); - 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; - } + /* 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 (ctype == NULL_TREE || check) - return decl; + if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl)) + return NULL_TREE; - 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 (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; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 851b4022086..f7ed5810e3b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1358,6 +1358,8 @@ check_classfn (ctype, function) 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. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a286f53283c..9fef5acd36e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -551,8 +551,7 @@ begin_template_parm_list () pushtag contains special code to call pushdecl_with_scope on the TEMPLATE_DECL for S2. */ - pushlevel (0); - declare_pseudo_global_level (); + begin_scope (sk_template_parms); ++processing_template_decl; ++processing_template_parmlist; note_template_header (0); @@ -596,6 +595,7 @@ check_specialization_scope () void begin_specialization () { + begin_scope (sk_template_spec); note_template_header (1); check_specialization_scope (); } @@ -606,6 +606,7 @@ begin_specialization () void end_specialization () { + finish_scope (); reset_specialization (); } @@ -1166,109 +1167,99 @@ check_explicit_specialization (declarator, decl, template_count, flags) 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; - 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); + tsk = current_tmpl_spec_kind (template_count); - SET_DECL_TEMPLATE_SPECIALIZATION (decl); - if (ctype) - member_specialization = 1; - else - specialization = 1; - } - else if (template_header_count == template_count) + switch (tsk) + { + case tsk_none: + if (processing_specialization) { - /* 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 + else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) { - /* 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(); + if (is_friend) + /* This could be something like: - 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"); - + 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; - } - 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 <> + break; - 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. */ + case tsk_excessive_parms: + cp_error ("too many template parameter lists in declaration of `%D'", + decl); + return error_mark_node; - /* If they said - template <class T> void S<int>::f() {} - that's bogus. */ + /* 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 ("template parameters specified in specialization"); + 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: - 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> struct S { void f(); }; + void S<int>::f() {} // Missing template <> - template <class T> void f(T); - class S { friend void f<>(int); } */ - specialization = 1; - else + 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>(); */ @@ -1277,6 +1268,22 @@ check_explicit_specialization (declarator, decl, template_count, flags) 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) @@ -1474,10 +1481,19 @@ check_explicit_specialization (declarator, decl, template_count, flags) targs = new_targs; } - decl = instantiate_template (tmpl, targs); - return decl; + 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. */ @@ -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 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 + non-template, name-mangling algorithm will not be used later. */ if ((is_member_template (tmpl) || ctype == NULL_TREE) && name_mangling_version >= 1) @@ -1863,11 +1879,10 @@ end_template_decl () return; /* This matches the pushlevel in begin_template_parm_list. */ - poplevel (0, 0, 0); + finish_scope (); --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. @@ -2370,7 +2385,7 @@ push_template_decl_real (decl, is_friend) DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace); /* See if this is a primary template. */ - primary = pseudo_global_level_p (); + primary = template_parm_scope_p (); if (primary) { @@ -2444,9 +2459,6 @@ push_template_decl_real (decl, is_friend) 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))) @@ -5597,7 +5609,7 @@ tsubst_decl (t, args, type, in_decl) template <class T> struct S { template <class U> friend void f(); }; - template <class U> friend void f() {} + template <class U> void f() {} template S<int>; template void f<double>(); @@ -7395,7 +7407,7 @@ instantiate_template (tmpl, targ_ptr) if (spec != NULL_TREE) 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 arguments we must add the arguments used to perform the @@ -8944,6 +8956,8 @@ most_general_template (decl) 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.) */ diff --git a/gcc/testsuite/g++.old-deja/g++.benjamin/tem05.C b/gcc/testsuite/g++.old-deja/g++.benjamin/tem05.C index 92ad7390731..fc6af32938c 100644 --- a/gcc/testsuite/g++.old-deja/g++.benjamin/tem05.C +++ b/gcc/testsuite/g++.old-deja/g++.benjamin/tem05.C @@ -49,7 +49,7 @@ unsigned short X_one<T>::ret_id() { return id; } -export template <class T> template <class T2> // WARNING - +export template <class T2> // WARNING - bool compare_ge(T2 test) { if (test > type) return true; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp93.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp93.C new file mode 100644 index 00000000000..50f74233b17 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/memtemp93.C @@ -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; +} |