]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cp-tree.h (TI_USES_TEMPLATE_PARMS): Remove.
authorMark Mitchell <mark@markmitchell.com>
Tue, 28 Jul 1998 01:03:16 +0000 (01:03 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Tue, 28 Jul 1998 01:03:16 +0000 (01:03 +0000)
* cp-tree.h (TI_USES_TEMPLATE_PARMS): Remove.
(build_template_decl_overload): Remove.
(set_mangled_name_for_decl): New function.
(innermost_args): Remove is_spec parameter.
(most_specialized, most_specialized_class): Remove declarations.
(lookup_template_class): Add entering_scope parameter.
(maybe_process_partial_specialization): New function.
(finish_template_decl): Likewise.
(finish_template_type): Likewise.
* class.c (finish_struct): Clean up processing of member template
specializations.
* decl.c (pushtag): Fix formatting.
(lookup_tag): Improve handling of pseudo-global levels.
(make_typename_type): Adjust call to lookup_template_class.
(shadow_tag): Use maybe_process_partial_specialization.
(xref_tag): Improve handling of member friends.
(start_function): Call push_nested_class before
push_template_decl.  Don't call push_template_decl for
specializations.
* decl2.c (grok_x_components): Don't call xref_tag for
template instantiations.  Handle UNION_TYPEs like RECORD_TYPEs.
(grokclassfn): Use set_mangled_name_for_decl.
(arg_assoc_class): Adjust call to innermost_args.
(mark_used): Don't call instantiate_decl for a TEMPLATE_DECL.
* error.c (dump_function_name): Improve printing of template
function names.
* friend.c (is_friend): Don't compare types of decls to determine
friendship, unless flag_guiding_decls.
(make_friend_class): Partial specializations cannot be friends.
(do_friend): Use set_mangled_name_for_decl.  Call
push_template_decl_real instead of push_template_decl.
* method.c (build_decl_overload_real): Remove prototype.  Give it
external linkage.
(build_overload_identififer): Adjust call to innermost_args.
(build_template_decl_overload): Remove.
(set_mangled_name_for_decl): New function.
* parse.y (.finish_template_type): New non-terminal.
(template_def): Use finish_template_decl.  Use template_extdef
instead of extdef.
(template_extdef, template_datadef): New non-terminals, containing
only those rules for things which can be templates.
(datadef): Tidy.
(template_type, self_template_type): Use .finish_template_type.
(named_class_head): Use maybe_process_partial_specialization.
* pt.c (mangle_class_name_for_template): Remove context parameter.
(get_class_bindings): Remove outer_args parameter.
(complete_template_args): Remove.
(add_outermost_template_args): New function.
(register_specialization): Return the specialization.
(unregister_specialization): New function.
(tsubst_template_parms): Likewise.
(most_specialized, most_specialized_class): Prototype here as
static.
(original_template): Rename to most_general_template.
(tsubst_template_parms): New function.
(set_mangled_name_for_template_decl): Likewise.
(TMPL_ARGS_DEPTH): New macro.
(TMPL_ARGS_HAVE_MULTIPLE_LEVELS): Adjust.
(TMPL_ARGS_LEVEL): New macro.
(SET_TMPL_ARGS_LEVEL): Likewise.
(TMPL_ARG): Likewise.
(SET_TMPL_ARG): Likewise.
(TMPL_ARGS_DEPTH): Likewise.
(finish_member_template_decl): Use finish_template_decl.
(maybe_process_partial_specialization): New function, split out
from tsubst.
(inline_needs_template_parms): Use TMPL_PARMS_DEPTH.
(maybe_begin_member_template_processing): Use new macros.
(is_member_template): Likewise.
(is_member_template_class): Likewise.
(add_to_template_args): Likewise.  Deal with multiple levels of
args.
(maybe_process_partial_specialization): New function.
(retrieve_specialization): Add consistency check.
(determine_specialization): Return full argument list.
(check_explicit_specialization): Tweak friend handling.  Use full
argument lists.  Simplify.
(current_template_args): Use new macros.
(push_template_decl_real): Change ill-named mainargs to specargs.
Check that a partial specialization actually specializes at least
one parameter.   Improve friend handling.  Modify for full
template arguments.
(classtype_mangled_name): Don't mangle the names of
specializations.
(lookup_template_class): Add entering_scope parameter.  Use it to
avoid finding a template type when an instantiation is required.
Simplify.  Use full template arguments.
(tsubst_friend_function): Use unregister_specialization.  Use new
macros.  Use full template arguments.
(tsubst_friend_class): Substitute, using tsubst_template_parms,
into the template parameters before passing them to
redeclare_class_template.
(instantiate_class_template): Simplify.  Use full template
arguments.  Adjust calls to get_class_bindings.  Use
SET_IDENTIFIER_TYPE_VALUE where needed.  Improve friend handling.
(innermost_args): Use new macros.
(tsubst_aggr_type): New function, split out from tsubst.
(tsubst): Use tsubst_aggr_type, tsubst_template_parms, new calling
conventions for lookup_tmeplate_class.  Refine handling of partial
instantiations.   Remove calls to complete_template_args.
Simplify.  Add consistency checks.  Use set_mangled_name_for_decl
and set_mangled_name_for_template_decl.
(tsubst_copy): Use tsubst_aggr_type.
(instantiate_template): Use full template arguments.
(more_specialized): Improve formatting.
(more_specialized_class): Adjust calls to get_class_bindings.
(get_bindings_real): Don't call complete_template_args.
(most_specialized): Don't overwrite input; create a new list.
(most_specialized_class): Use most_general_template.
(regenerate_decl_from_template): Use unregister_specialization.
Use full template arguments.
(instantiate_decl): Use full template arguments.
(set_mangled_name_for_template_decl): New function.
* semantics.c (begin_class_definition): Use
maybe_process_partial_specialization.
(finish_member_class_template): New function.
(finish_template_decl): Likewise.
(finish_template_type): Likewise.
(typeck.c): Don't crash after issuing a compiler_error.
* Makefile.in (CONFLICTS): Adjust; we removed a s/r conflict.

From-SVN: r21433

37 files changed:
gcc/cp/ChangeLog
gcc/cp/Makefile.in
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/friend.c
gcc/cp/method.c
gcc/cp/parse.y
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
gcc/testsuite/g++.old-deja/g++.brendan/crash8.C
gcc/testsuite/g++.old-deja/g++.pt/crash11.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/crash13.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/crash14.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/crash8.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend21.C
gcc/testsuite/g++.old-deja/g++.pt/friend22.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend23.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend24.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend25.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend26.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/friend27.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/memclass13.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/memclass14.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/memclass15.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/ttp52.C
gcc/testsuite/g++.old-deja/g++.pt/typename3.C
gcc/testsuite/g++.old-deja/g++.pt/typename4.C
gcc/testsuite/g++.old-deja/g++.pt/typename5.C
gcc/testsuite/g++.old-deja/g++.pt/typename6.C
gcc/testsuite/g++.old-deja/g++.robertl/eb125.C
gcc/testsuite/g++.old-deja/g++.robertl/eb49.C

index 72cbecd85260b6a9c05ef322688902cc3a2456e3..52df5d573d28aea1ee4d9f17a5e6b12c1f7c25b5 100644 (file)
@@ -1,3 +1,126 @@
+1998-07-27  Mark Mitchell  <mark@markmitchell.com>
+
+       * cp-tree.h (TI_USES_TEMPLATE_PARMS): Remove.
+       (build_template_decl_overload): Remove.
+       (set_mangled_name_for_decl): New function.
+       (innermost_args): Remove is_spec parameter.
+       (most_specialized, most_specialized_class): Remove declarations.
+       (lookup_template_class): Add entering_scope parameter.
+       (maybe_process_partial_specialization): New function.
+       (finish_template_decl): Likewise.
+       (finish_template_type): Likewise.  
+       * class.c (finish_struct): Clean up processing of member template
+       specializations.
+       * decl.c (pushtag): Fix formatting.
+       (lookup_tag): Improve handling of pseudo-global levels.
+       (make_typename_type): Adjust call to lookup_template_class.
+       (shadow_tag): Use maybe_process_partial_specialization.
+       (xref_tag): Improve handling of member friends.  
+       (start_function): Call push_nested_class before
+       push_template_decl.  Don't call push_template_decl for
+       specializations.
+       * decl2.c (grok_x_components): Don't call xref_tag for
+       template instantiations.  Handle UNION_TYPEs like RECORD_TYPEs.
+       (grokclassfn): Use set_mangled_name_for_decl.
+       (arg_assoc_class): Adjust call to innermost_args.
+       (mark_used): Don't call instantiate_decl for a TEMPLATE_DECL.
+       * error.c (dump_function_name): Improve printing of template
+       function names.
+       * friend.c (is_friend): Don't compare types of decls to determine
+       friendship, unless flag_guiding_decls.
+       (make_friend_class): Partial specializations cannot be friends.  
+       (do_friend): Use set_mangled_name_for_decl.  Call
+       push_template_decl_real instead of push_template_decl.
+       * method.c (build_decl_overload_real): Remove prototype.  Give it
+       external linkage.
+       (build_overload_identififer): Adjust call to innermost_args.
+       (build_template_decl_overload): Remove.
+       (set_mangled_name_for_decl): New function.
+       * parse.y (.finish_template_type): New non-terminal.
+       (template_def): Use finish_template_decl.  Use template_extdef
+       instead of extdef.
+       (template_extdef, template_datadef): New non-terminals, containing
+       only those rules for things which can be templates.
+       (datadef): Tidy.
+       (template_type, self_template_type): Use .finish_template_type.
+       (named_class_head): Use maybe_process_partial_specialization.
+       * pt.c (mangle_class_name_for_template): Remove context parameter.
+       (get_class_bindings): Remove outer_args parameter.
+       (complete_template_args): Remove.
+       (add_outermost_template_args): New function.
+       (register_specialization): Return the specialization.
+       (unregister_specialization): New function.
+       (tsubst_template_parms): Likewise.
+       (most_specialized, most_specialized_class): Prototype here as
+       static. 
+       (original_template): Rename to most_general_template.
+       (tsubst_template_parms): New function.
+       (set_mangled_name_for_template_decl): Likewise.
+       (TMPL_ARGS_DEPTH): New macro.
+       (TMPL_ARGS_HAVE_MULTIPLE_LEVELS): Adjust.
+       (TMPL_ARGS_LEVEL): New macro.
+       (SET_TMPL_ARGS_LEVEL): Likewise.
+       (TMPL_ARG): Likewise.
+       (SET_TMPL_ARG): Likewise.
+       (TMPL_ARGS_DEPTH): Likewise.
+       (finish_member_template_decl): Use finish_template_decl.
+       (maybe_process_partial_specialization): New function, split out
+       from tsubst.
+       (inline_needs_template_parms): Use TMPL_PARMS_DEPTH.
+       (maybe_begin_member_template_processing): Use new macros.
+       (is_member_template): Likewise.
+       (is_member_template_class): Likewise.
+       (add_to_template_args): Likewise.  Deal with multiple levels of
+       args. 
+       (maybe_process_partial_specialization): New function.
+       (retrieve_specialization): Add consistency check.
+       (determine_specialization): Return full argument list.
+       (check_explicit_specialization): Tweak friend handling.  Use full
+       argument lists.  Simplify.
+       (current_template_args): Use new macros.
+       (push_template_decl_real): Change ill-named mainargs to specargs.
+       Check that a partial specialization actually specializes at least
+       one parameter.   Improve friend handling.  Modify for full
+       template arguments.
+       (classtype_mangled_name): Don't mangle the names of
+       specializations. 
+       (lookup_template_class): Add entering_scope parameter.  Use it to
+       avoid finding a template type when an instantiation is required.
+       Simplify.  Use full template arguments.
+       (tsubst_friend_function): Use unregister_specialization.  Use new
+       macros.  Use full template arguments.
+       (tsubst_friend_class): Substitute, using tsubst_template_parms,
+       into the template parameters before passing them to
+       redeclare_class_template.
+       (instantiate_class_template): Simplify.  Use full template
+       arguments.  Adjust calls to get_class_bindings.  Use
+       SET_IDENTIFIER_TYPE_VALUE where needed.  Improve friend handling.
+       (innermost_args): Use new macros.
+       (tsubst_aggr_type): New function, split out from tsubst.
+       (tsubst): Use tsubst_aggr_type, tsubst_template_parms, new calling
+       conventions for lookup_tmeplate_class.  Refine handling of partial
+       instantiations.   Remove calls to complete_template_args.
+       Simplify.  Add consistency checks.  Use set_mangled_name_for_decl
+       and set_mangled_name_for_template_decl.
+       (tsubst_copy): Use tsubst_aggr_type.
+       (instantiate_template): Use full template arguments.
+       (more_specialized): Improve formatting.
+       (more_specialized_class): Adjust calls to get_class_bindings.
+       (get_bindings_real): Don't call complete_template_args.
+       (most_specialized): Don't overwrite input; create a new list.
+       (most_specialized_class): Use most_general_template.
+       (regenerate_decl_from_template): Use unregister_specialization.
+       Use full template arguments.  
+       (instantiate_decl): Use full template arguments.
+       (set_mangled_name_for_template_decl): New function.
+       * semantics.c (begin_class_definition): Use
+       maybe_process_partial_specialization.
+       (finish_member_class_template): New function.
+       (finish_template_decl): Likewise.
+       (finish_template_type): Likewise.  
+       (typeck.c): Don't crash after issuing a compiler_error.
+       * Makefile.in (CONFLICTS): Adjust; we removed a s/r conflict.
+       
 1998-07-27  Jason Merrill  <jason@yorick.cygnus.com>
 
        * typeck2.c (build_functional_cast): Handle default-initialization.
index 523bbe0eb3de24722afa580e818fee1cc071bc50..085fe3c5c86f2ca291353e2d10179053d1dd38f5 100644 (file)
@@ -215,7 +215,7 @@ parse.o : $(PARSE_C) $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(BIG_SWITCHFLAG) \
   `echo $(PARSE_C) | sed 's,^\./,,'`
 
-CONFLICTS = expect 26 shift/reduce conflicts and 42 reduce/reduce conflicts.
+CONFLICTS = expect 25 shift/reduce conflicts and 42 reduce/reduce conflicts.
 $(PARSE_H) : $(PARSE_C)
 $(PARSE_C) : $(srcdir)/parse.y
        @echo $(CONFLICTS)
index 714aad64225b2beb4f72d8d3e3b49a60b291777b..098f6c3c71794d6e1d37f8a28aa52790aa936cd6 100644 (file)
@@ -4458,49 +4458,21 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
   /* Now, figure out which member templates we're specializing.  */
   for (x = specializations; x != NULL_TREE; x = TREE_CHAIN (x))
     {
-      tree spec_args;
-      tree fn;
       int pending_specialization;
 
-      if (uses_template_parms (t))
-       /* If t is a template class, and x is a specialization, then x
-          is itself really a template.  Due to the vagaries of the
-          parser, however, we will have a handle to a function
-          declaration, rather than the template declaration, at this
-          point.  */
-       {
-         my_friendly_assert (DECL_TEMPLATE_INFO (x) != NULL_TREE, 0);
-         my_friendly_assert (DECL_TI_TEMPLATE (x) != NULL_TREE, 0);
-         fn = DECL_TI_TEMPLATE (x);
-       }
-      else
-       fn = x;
-
-      /* We want the specialization arguments, which will be the
-        innermost ones.  */
-      if (DECL_TI_ARGS (fn) && TREE_CODE (DECL_TI_ARGS (fn)) == TREE_VEC)
-       spec_args 
-         = TREE_VEC_ELT (DECL_TI_ARGS (fn), 0);
-      else
-       spec_args = DECL_TI_ARGS (fn);
-      
       pending_specialization 
-       = TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (fn));
+       = TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (x));
       check_explicit_specialization 
-       (lookup_template_function (DECL_NAME (fn), spec_args),
-        fn, 0, 1 | (8 * pending_specialization));
-      TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (fn)) = 0;
+       (lookup_template_function (DECL_NAME (x), DECL_TI_ARGS (x)),
+        x, 0, 1 | (8 * pending_specialization));
+      TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (x)) = 0;
 
       /* Now, the assembler name will be correct for fn, so we
         make its RTL.  */
-      DECL_RTL (fn) = 0;
-      make_decl_rtl (fn, NULL_PTR, 1);
-
-      if (x != fn)
-       {
-         DECL_RTL (x) = 0;
-         make_decl_rtl (x, NULL_PTR, 1);
-       }
+      DECL_RTL (x) = 0;
+      make_decl_rtl (x, NULL_PTR, 1);
+      DECL_RTL (DECL_TI_TEMPLATE (x)) = 0;
+      make_decl_rtl (DECL_TI_TEMPLATE (x), NULL_PTR, 1);
     }
 
   if (current_class_type)
index 7572921cb5fbd587a68e61369fe04daa31bd1891..be97c1b1ca00c98f6173a4e01e1676894d69efb6 100644 (file)
@@ -27,7 +27,6 @@ Boston, MA 02111-1307, USA.  */
 /* Usage of TREE_LANG_FLAG_?:
    0: TREE_NONLOCAL_FLAG (in TREE_LIST or _TYPE).
       BINFO_MARKED (BINFO nodes).
-      TI_USES_TEMPLATE_PARMS.
       COMPOUND_STMT_NO_SCOPE (in COMPOUND_STMT).
       NEW_EXPR_USE_GLOBAL (in NEW_EXPR).
       DELETE_EXPR_USE_GLOBAL (in DELETE_EXPR).
@@ -1250,13 +1249,35 @@ struct lang_decl
 #define TI_TEMPLATE(NODE) (TREE_PURPOSE (NODE))
 #define TI_ARGS(NODE) (TREE_VALUE (NODE))
 #define TI_SPEC_INFO(NODE) (TREE_CHAIN (NODE))
-#define TI_USES_TEMPLATE_PARMS(NODE) TREE_LANG_FLAG_0 (NODE)
 #define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
 /* TI_PENDING_SPECIALIZATION_FLAG on a template-info node indicates
    that the template is a specialization of a member template, but
    that we don't yet know which one.  */
 #define TI_PENDING_SPECIALIZATION_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
+/* The TEMPLATE_DECL instantiated or specialized by NODE.  This
+   TEMPLATE_DECL will be the immediate parent, not the most general
+   template.  For example, in:
+
+      template <class T> struct S { template <class U> void f(U); }
+
+   the FUNCTION_DECL for S<int>::f<double> will have, as its
+   DECL_TI_TEMPLATE, `template <class U> S<int>::f<U>'. 
+
+   As a special case, for a member friend template of a template
+   class, this value will not be a TEMPLATE_DECL, but rather a
+   LOOKUP_EXPR indicating the name of the template and any explicit
+   template arguments provided.  For example, in:
+
+     template <class T> struct S { friend void f<int>(int, double); }
+
+   the DECL_TI_TEMPLATE will be a LOOKUP_EXPR for `f' and the
+   DECL_TI_ARGS will be {int}.  */ 
 #define DECL_TI_TEMPLATE(NODE)      TI_TEMPLATE (DECL_TEMPLATE_INFO (NODE))
+/* The template arguments used to obtain this decl from the most
+   general form of DECL_TI_TEMPLATE.  For the example given for
+   DECL_TI_TEMPLATE, the DECL_TI_ARGS will be {int, double}.  These
+   are always the full set of arguments required to instantiate this
+   declaration from the most general template specialized here.  */
 #define DECL_TI_ARGS(NODE)          TI_ARGS (DECL_TEMPLATE_INFO (NODE))
 #define CLASSTYPE_TI_TEMPLATE(NODE) TI_TEMPLATE (CLASSTYPE_TEMPLATE_INFO (NODE))
 #define CLASSTYPE_TI_ARGS(NODE)     TI_ARGS (CLASSTYPE_TEMPLATE_INFO (NODE))
@@ -1528,25 +1549,80 @@ extern int flag_new_for_scope;
 /* Accessor macros for C++ template decl nodes.  */
 
 /* The DECL_TEMPLATE_PARMS are a list.  The TREE_PURPOSE of each node
-   indicates the level of the template parameters, with 1 being the
-   outermost set of template parameters.  The TREE_VALUE is a vector,
-   whose elements are the template parameters at each level.  Each
-   element in the vector is a TREE_LIST, whose TREE_VALUE is a
-   PARM_DECL (if the parameter is a non-type parameter), or a
-   TYPE_DECL (if the parameter is a type parameter).  The TREE_PURPOSE
-   is the default value, if any.  The TEMPLATE_PARM_INDEX for the
-   parameter is avilable as the DECL_INITIAL (for a PARM_DECL) or as
-   the TREE_TYPE (for a TYPE_DECL).  */
+   is a INT_CST whose TREE_INT_CST_HIGH indicates the level of the
+   template parameters, with 1 being the outermost set of template
+   parameters.  The TREE_VALUE is a vector, whose elements are the
+   template parameters at each level.  Each element in the vector is a
+   TREE_LIST, whose TREE_VALUE is a PARM_DECL (if the parameter is a
+   non-type parameter), or a TYPE_DECL (if the parameter is a type
+   parameter).  The TREE_PURPOSE is the default value, if any.  The
+   TEMPLATE_PARM_INDEX for the parameter is avilable as the
+   DECL_INITIAL (for a PARM_DECL) or as the TREE_TYPE (for a
+   TYPE_DECL).  */
 #define DECL_TEMPLATE_PARMS(NODE)       DECL_ARGUMENTS(NODE)
 #define DECL_INNERMOST_TEMPLATE_PARMS(NODE) \
    INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (NODE))
 #define DECL_NTPARMS(NODE) \
    TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (NODE))
-/* For class templates.  */
-#define DECL_TEMPLATE_SPECIALIZATIONS(NODE)     DECL_SIZE(NODE)
 /* For function, method, class-data templates.  */
 #define DECL_TEMPLATE_RESULT(NODE)      DECL_RESULT(NODE)
+/* For a static member variable template, the
+   DECL_TEMPLATE_INSTANTIATIONS list contains the explicitly and
+   implicitly generated instantiations of the variable.  There are no
+   partial instantiations of static member variables, so all of these
+   will be full instantiations.
+
+   For a class template the DECL_TEMPLATE_INSTANTIATIONS lists holds
+   all instantiations and specializations of the class type, including
+   partial instantiations and partial specializations.
+
+   In both cases, the TREE_PURPOSE of each node contains the arguments
+   used; the TREE_VALUE contains the generated variable.  The template
+   arguments are always complete.  For example, given:
+
+      template <class T> struct S1 {
+        template <class U> struct S2 {};
+       template <class U> struct S2<U*> {};
+      };
+
+   the record for the partial specialization will contain, as its
+   argument list, { {T}, {U*} }, and will be on the
+   DECL_TEMPLATE_INSTANTIATIONS list for `template <class T> template
+   <class U> struct S1<T>::S2'.
+
+   This list is not used for function templates.  */
 #define DECL_TEMPLATE_INSTANTIATIONS(NODE) DECL_VINDEX(NODE)
+/* For a function template, the DECL_TEMPLATE_SPECIALIZATIONS lists
+   contains all instantiations and specializations of the function,
+   including partial instantiations.  For a partial instantiation
+   which is a specialization, this list holds only full
+   specializations of the template that are instantiations of the
+   partial instantiation.  For example, given:
+
+      template <class T> struct S {
+        template <class U> void f(U);
+       template <> void f(T); 
+      };
+
+   the `S<int>::f<int>(int)' function will appear on the
+   DECL_TEMPLATE_SPECIALIZATIONS list for both `template <class T>
+   template <class U> void S<T>::f(U)' and `template <class T> void
+   S<int>::f(T)'.  In the latter case, however, it will have only the
+   innermost set of arguments (T, in this case).  The DECL_TI_TEMPLATE
+   for the function declaration will point at the specialization, not
+   the fully general template.
+
+   For a class template, this list contains the partial
+   specializations of this template.  (Full specializations are not
+   recorded on this list.)  The TREE_PURPOSE holds the innermost
+   arguments used in the partial specialization (e.g., for `template
+   <class T> struct S<T*, int>' this will be `T*'.)  The TREE_VALUE
+   holds the innermost template parameters for the specialization
+   (e.g., `T' in the example above.)  The TREE_TYPE is the _TYPE node
+   for the partial specialization.
+
+   This list is not used for static variable templates.  */
+#define DECL_TEMPLATE_SPECIALIZATIONS(NODE)     DECL_SIZE(NODE)
 #define DECL_TEMPLATE_INJECT(NODE)     DECL_INITIAL(NODE)
 
 /* Nonzero for TEMPLATE_DECL nodes that represents template template
@@ -2649,7 +2725,9 @@ extern void do_inline_function_hair               PROTO((tree, tree));
 extern char *build_overload_name               PROTO((tree, int, int));
 extern tree build_static_name                  PROTO((tree, tree));
 extern tree build_decl_overload                        PROTO((tree, tree, int));
-extern tree build_template_decl_overload        PROTO((tree, tree, tree, tree, tree, int));
+extern tree build_decl_overload_real            PROTO((tree, tree, tree, tree,
+                                                      tree, int)); 
+extern tree set_mangled_name_for_decl           PROTO((tree));
 extern tree build_typename_overload            PROTO((tree));
 extern tree build_overload_with_type           PROTO((tree, tree));
 extern tree build_destructor_name              PROTO((tree));
@@ -2661,7 +2739,7 @@ extern void synthesize_method                     PROTO((tree));
 extern tree get_id_2                           PROTO((char *, tree));
 
 /* in pt.c */
-extern tree innermost_args                     PROTO ((tree, int));
+extern tree innermost_args                     PROTO ((tree));
 extern tree tsubst                             PROTO ((tree, tree, tree));
 extern tree tsubst_expr                                PROTO ((tree, tree, tree));
 extern tree tsubst_copy                                PROTO ((tree, tree, tree));
@@ -2684,7 +2762,7 @@ extern tree current_template_args         PROTO((void));
 extern tree push_template_decl                 PROTO((tree));
 extern tree push_template_decl_real             PROTO((tree, int));
 extern void redeclare_class_template            PROTO((tree, tree));
-extern tree lookup_template_class              PROTO((tree, tree, tree, tree));
+extern tree lookup_template_class              PROTO((tree, tree, tree, tree, int));
 extern tree lookup_template_function            PROTO((tree, tree));
 extern int uses_template_parms                 PROTO((tree));
 extern tree instantiate_class_template         PROTO((tree));
@@ -2708,8 +2786,6 @@ extern void begin_tree                          PROTO((void));
 extern void end_tree                            PROTO((void));
 extern void add_maybe_template                 PROTO((tree, tree));
 extern void pop_tinst_level                    PROTO((void));
-extern tree most_specialized                   PROTO((tree, tree, tree));
-extern tree most_specialized_class             PROTO((tree, tree, tree));
 extern int more_specialized_class              PROTO((tree, tree));
 extern void do_pushlevel                       PROTO((void));
 extern int is_member_template                   PROTO((tree));
@@ -2717,6 +2793,7 @@ extern int comp_template_parms                  PROTO((tree, tree));
 extern int template_class_depth                 PROTO((tree));
 extern int is_specialization_of                 PROTO((tree, tree));
 extern int comp_template_args                   PROTO((tree, tree));
+extern void maybe_process_partial_specialization PROTO((tree));
 
 extern int processing_specialization;
 extern int processing_explicit_instantiation;
@@ -2839,6 +2916,8 @@ extern tree finish_class_definition             PROTO((tree, tree, tree, int));
 extern void finish_default_args                 PROTO((void));
 extern void begin_inline_definitions            PROTO((void));
 extern tree finish_member_class_template        PROTO((tree, tree));
+extern void finish_template_decl                PROTO((tree));
+extern tree finish_template_type                PROTO((tree, tree, int));
 
 /* in sig.c */
 extern tree build_signature_pointer_type       PROTO((tree, int, int));
index 0149679cb9e8f4faf466c0daf03c6ba60bb0bb59..aa5204ec84461ad2bd1aa70a40b7e617f4c5c5ae 100644 (file)
@@ -2339,8 +2339,8 @@ pushtag (name, type, globalize)
                 class scope.  In the friend case, push_template_decl
                 will already have put the friend into global scope,
                 if appropriate.  */ 
-             if (!globalize && b->pseudo_global &&
-                 b->level_chain->parm_flag == 2)
+             if (!globalize && b->pseudo_global
+                 && b->level_chain->parm_flag == 2)
                {
                  pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
                                       b->level_chain);
@@ -4455,6 +4455,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;
 
   for (level = binding_level; level; level = level->level_chain)
     {
@@ -4472,7 +4475,19 @@ lookup_tag (form, name, binding_level, thislevel_only)
        /* XXX: is this a real lookup, considering using-directives etc. ??? */
        for (tail = current_namespace; 1; tail = CP_DECL_CONTEXT (tail))
          {
-           tree old = BINDING_TYPE (binding_for_name (name, tail));
+           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));
+           else 
+             old = BINDING_TYPE (old);
+
            /* If it has an original type, it is a typedef, and we
               should not return it.  */
            if (old && DECL_ORIGINAL_TYPE (TYPE_NAME (old)))
@@ -4509,16 +4524,24 @@ lookup_tag (form, name, binding_level, thislevel_only)
          }
       if (thislevel_only && ! level->tag_transparent)
        {
-         if (level->pseudo_global)
-           {
-             tree t = IDENTIFIER_CLASS_VALUE (name);
-             if (t && DECL_CLASS_TEMPLATE_P (t))
-               return TREE_TYPE (t);
-             t = IDENTIFIER_NAMESPACE_VALUE (name);
-             if (t && DECL_CLASS_TEMPLATE_P (t))
-               return TREE_TYPE (t);
+         if (level->pseudo_global && allow_pseudo_global)
+           {
+             /* We must deal with cases like this:
+                
+                  template <class T> struct S;
+                  template <class T> struct S {};
+                  
+                When looking up `S', for the second declaration, we
+                would like to find the first declaration.  But, we
+                are in the pseudo-global level created for the
+                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;
            }
-         return NULL_TREE;
+         else
+           return NULL_TREE;
        }
       if (current_class_type && level->level_chain->namespace_p)
        {
@@ -4730,7 +4753,8 @@ make_typename_type (context, name)
            }
 
          return lookup_template_class (t, TREE_OPERAND (fullname, 1),
-                                       NULL_TREE, context);
+                                       NULL_TREE, context, 
+                                       /*entering_scope=*/0);
        }
       else
        {
@@ -6207,18 +6231,7 @@ shadow_tag (declspecs)
        {
          my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
 
-         if (IS_AGGR_TYPE (value) && CLASSTYPE_USE_TEMPLATE (value))
-           {
-             if (CLASSTYPE_IMPLICIT_INSTANTIATION (value)
-                 && TYPE_SIZE (value) == NULL_TREE)
-               {
-                 SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (value);
-                 if (processing_template_decl)
-                   push_template_decl (TYPE_MAIN_DECL (value));
-               }
-             else if (CLASSTYPE_TEMPLATE_INSTANTIATION (value))
-               cp_error ("specialization after instantiation of `%T'", value);
-           }
+         maybe_process_partial_specialization (value);
 
          t = value;
          ok_code = code;
@@ -10241,9 +10254,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              {
                tree t = NULL_TREE;
                if (decl && DECL_NAME (decl))
-                 t = do_friend (ctype, declarator, decl,
-                                last_function_parms, flags, quals,
-                                funcdef_flag);
+                 {
+                   if (template_class_depth (current_class_type) == 0)
+                     decl 
+                       = check_explicit_specialization 
+                       (declarator, decl,
+                        template_count, 2 * (funcdef_flag != 0) + 4);
+                   t = do_friend (ctype, declarator, decl,
+                                  last_function_parms, flags, quals,
+                                  funcdef_flag);
+                 }
                if (t && funcdef_flag)
                  return t;
                
@@ -11321,37 +11341,66 @@ xref_tag (code_type_node, name, binfo, globalize)
       if (t && TYPE_CONTEXT (t) && got_type)
        ref = t;
       else
-       {
-         /* If we know we are defining this tag, only look it up in
-            this scope and don't try to find it as a type.  */
-         ref = lookup_tag (code, name, b, 1);
-       }
+       /* If we know we are defining this tag, only look it up in
+          this scope and don't try to find it as a type.  */
+       ref = lookup_tag (code, name, b, 1);
     }
   else
     {
-      if (t)
-       ref = t;
-      else
-        ref = lookup_tag (code, name, b, 0);
-
-      if (! ref)
-       {
-         /* Try finding it as a type declaration.  If that wins, use it.  */
-         ref = lookup_name (name, 1);
+      if (current_class_type 
+         && template_class_depth (current_class_type) 
+         && (processing_template_decl 
+             > template_class_depth (current_class_type)))
+      /* Since GLOBALIZE is non-zero, we are not looking at a
+        definition of this tag.  Since, in addition, we are currently
+        processing a (member) template declaration of a template
+        class, we don't want to do any lookup at all; consider:
+
+          template <class X>
+          struct S1
+
+          template <class U>
+          struct S2
+          { template <class V>
+            friend struct S1; };
+          
+        Here, the S2::S1 declaration should not be confused with the
+        outer declaration.  In particular, the inner version should
+        have a template parameter of level 2, not level 1.  This
+        would be particularly important if the member declaration
+        were instead:
+
+          template <class V = U> friend struct S1;
+
+        say, when we should tsubst into `U' when instantiating S2.  */
+       ref = NULL_TREE;
+      else 
+       {
+         if (t)
+           ref = t;
+         else
+           ref = lookup_tag (code, name, b, 0);
+         
+         if (! ref)
+           {
+             /* Try finding it as a type declaration.  If that wins,
+                use it.  */ 
+             ref = lookup_name (name, 1);
 
-         if (ref != NULL_TREE
-             && processing_template_decl
-             && DECL_CLASS_TEMPLATE_P (ref)
-             && template_class_depth (current_class_type) == 0)
-           /* Since GLOBALIZE is true, we're declaring a global
+             if (ref != NULL_TREE
+                 && processing_template_decl
+                 && DECL_CLASS_TEMPLATE_P (ref)
+                 && template_class_depth (current_class_type) == 0)
+               /* Since GLOBALIZE is true, we're declaring a global
               template, so we want this type.  */
-           ref = DECL_RESULT (ref);
+               ref = DECL_RESULT (ref);
 
-         if (ref && TREE_CODE (ref) == TYPE_DECL
-             && TREE_CODE (TREE_TYPE (ref)) == code)
-           ref = TREE_TYPE (ref);
-         else
-           ref = NULL_TREE;
+             if (ref && TREE_CODE (ref) == TYPE_DECL
+                 && TREE_CODE (TREE_TYPE (ref)) == code)
+               ref = TREE_TYPE (ref);
+             else
+               ref = NULL_TREE;
+           }
        }
     }
 
@@ -12121,13 +12170,24 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
      (This does not mean `static' in the C sense!)  */
   TREE_STATIC (decl1) = 1;
 
+  /* Set up current_class_type, and enter the scope of the class, if
+     appropriate.  */
+  if (ctype)
+    push_nested_class (ctype, 1);
+  else if (DECL_STATIC_FUNCTION_P (decl1))
+    push_nested_class (DECL_CONTEXT (decl1), 2);
+
+  /* We must call push_template_decl after current_class_type is set
+     up.  (If we are processing inline definitions after exiting a
+     class scope, current_class_type will be NULL_TREE until set above
+     by push_nested_class.)  */
+  if (processing_template_decl)
+    decl1 = push_template_decl (decl1);
+
   /* Record the decl so that the function name is defined.
      If we already have a decl for this name, and it is a FUNCTION_DECL,
      use the old decl.  */
-
-  if (processing_template_decl)
-    decl1 = push_template_decl (decl1);
-  else if (pre_parsed_p == 0)
+  if (!processing_template_decl && pre_parsed_p == 0)
     {
       /* A specialization is not used to guide overload resolution.  */
       if ((flag_guiding_decls 
@@ -12207,8 +12267,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
 
   if (ctype)
     {
-      push_nested_class (ctype, 1);
-
       /* If we're compiling a friend function, neither of the variables
         current_class_ptr nor current_class_type will have values.  */
       if (! doing_friend)
@@ -12241,10 +12299,8 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
     }
   else
     {
-      if (DECL_STATIC_FUNCTION_P (decl1))
-       push_nested_class (DECL_CONTEXT (decl1), 2);
-      else
-       push_memoized_context (0, 1);
+      if (!DECL_STATIC_FUNCTION_P (decl1))
+       push_memoized_context (NULL_TREE, 1);
       current_class_ptr = current_class_ref = NULL_TREE;
     }
 
@@ -13185,7 +13241,8 @@ start_method (declspecs, declarator)
   if (flag_default_inline)
     DECL_INLINE (fndecl) = 1;
 
-  if (processing_template_decl)
+  /* We process method specializations in finish_struct_1.  */
+  if (processing_template_decl && !DECL_TEMPLATE_SPECIALIZATION (fndecl))
     fndecl = push_template_decl (fndecl);
 
   /* We read in the parameters on the maybepermanent_obstack,
index 901f56587229d605a608fcdafa70b52009b8888f..3aa5d73593b9a3fd6fa293887b4d3b22525b40d8 100644 (file)
@@ -912,34 +912,29 @@ grok_x_components (specs, components)
          break;
 
        case RECORD_TYPE:
-         /* This code may be needed for UNION_TYPEs as
-            well.  */
-         tcode = record_type_node;
+       case UNION_TYPE:
+         if (TREE_CODE (t) == UNION_TYPE)
+           tcode = union_type_node;
+         else
+           tcode = record_type_node;
          if (CLASSTYPE_DECLARED_CLASS (t))
            tcode = class_type_node;
          else if (IS_SIGNATURE (t))
            tcode = signature_type_node;
-
-         if (CLASSTYPE_IS_TEMPLATE (t))
-           /* In this case, the TYPE_IDENTIFIER will be something
-              like S<T>, rather than S, so to get the correct name we
-              look at the template.  */
-           x = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
-         else
-           x = TYPE_IDENTIFIER (t);
-
-         t = xref_tag (tcode, x, NULL_TREE, 0);
-         return NULL_TREE;
-         break;
-
-       case UNION_TYPE:
-       case ENUMERAL_TYPE:
-         if (TREE_CODE (t) == UNION_TYPE)
-           tcode = union_type_node;
+         
+         if (TYPE_LANG_SPECIFIC (t) 
+             && CLASSTYPE_USE_TEMPLATE (t))
+           /* We have already looked up this type.  */
+           ;
          else
-           tcode = enum_type_node;
+           {
+             if (CLASSTYPE_IS_TEMPLATE (t))
+               x = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
+             else
+               x = TYPE_IDENTIFIER (t);
+             t = xref_tag (tcode, x, NULL_TREE, 0);
+           }
 
-         t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
          if (ANON_UNION_TYPE_P (t))
            {
              /* See also shadow_tag.  */
@@ -972,11 +967,17 @@ grok_x_components (specs, components)
              for (; *p; *p = (*p)->next)
                if (DECL_CONTEXT ((*p)->fndecl) != t)
                  break;
+
+             return x;
            }
-         else if (TREE_CODE (t) == ENUMERAL_TYPE)
-           x = grok_enum_decls (NULL_TREE);
-         else
-           x = NULL_TREE;
+
+         return NULL_TREE;
+         break;
+
+       case ENUMERAL_TYPE:
+         tcode = enum_type_node;
+         t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
+         x = grok_enum_decls (NULL_TREE);
          return x;
          break;
 
@@ -1132,16 +1133,7 @@ grokclassfn (ctype, cname, function, flags, quals)
       TYPE_HAS_DESTRUCTOR (ctype) = 1;
     }
   else
-    {
-      if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
-       /* Only true for static member functions.  */
-       arg_types = hash_tree_chain (build_pointer_type (qualtype),
-                                    arg_types);
-
-      DECL_ASSEMBLER_NAME (function)
-       = build_decl_overload (fn_name, arg_types,
-                              1 + DECL_CONSTRUCTOR_P (function));
-    }
+    set_mangled_name_for_decl (function);
 }
 
 /* Work on the expr used by alignof (this is only called by the parser).  */
@@ -4299,7 +4291,7 @@ arg_assoc_class (k, type)
   /* Process template arguments.  */
   if (CLASSTYPE_TEMPLATE_INFO (type))
     {
-      list = innermost_args (CLASSTYPE_TI_ARGS (type), 0);
+      list = innermost_args (CLASSTYPE_TI_ARGS (type));
       for (i = 0; i < TREE_VEC_LENGTH (list); ++i)
        arg_assoc (k, TREE_VEC_ELT (list, i));
     }
@@ -4690,13 +4682,21 @@ mark_used (decl)
   if (processing_template_decl)
     return;
   assemble_external (decl);
+
   /* Is it a synthesized method that needs to be synthesized?  */
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_CLASS_CONTEXT (decl)
       && DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
       /* Kludge: don't synthesize for default args.  */
       && current_function_decl)
     synthesize_method (decl);
-  if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
+
+  /* If this is a function or variable that is an instance of some
+     template, we now know that we will need to actually do the
+     instantiation.  A TEMPLATE_DECL may also have DECL_TEMPLATE_INFO,
+     if it's a partial instantiation, but there's no need to
+     instantiate such a thing.  */
+  if (TREE_CODE (decl) != TEMPLATE_DECL
+      && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
     instantiate_decl (decl);
 }
 
index bb21bcb5021c7420761af2e21d708490f76c10ce..bd459c2a6f82d19bebb1f5a0653e44f4d233974a 100644 (file)
@@ -1042,91 +1042,75 @@ dump_function_name (t)
   else
     dump_decl (name, 0);
 
-  if (DECL_LANG_SPECIFIC (t) && DECL_USE_TEMPLATE (t))
+  if (DECL_LANG_SPECIFIC (t) && DECL_USE_TEMPLATE (t) 
+      && DECL_TEMPLATE_INFO (t)
+      && (DECL_TEMPLATE_SPECIALIZATION (t) 
+         || TREE_CODE (DECL_TI_TEMPLATE (t)) != TEMPLATE_DECL
+         || DECL_TEMPLATE_SPECIALIZATION (DECL_TI_TEMPLATE (t))
+         || PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t))))
     {
       tree args = DECL_TEMPLATE_INFO (t) ? DECL_TI_ARGS (t) : NULL_TREE; 
+      OB_PUTC ('<');
 
-      if (args != NULL_TREE
-         && DECL_CONTEXT (t) != NULL_TREE
-         && uses_template_parms (DECL_CONTEXT (t))
-         /* This next clause checks that there is only one level of
-            template arguments.  In that case, they are the
-            arguments for the class context.  */
-         && (TREE_CODE (args) == TREE_LIST
-             || (TREE_CODE (args) == TREE_VEC 
-                 && TREE_VEC_ELT (args, 0) != NULL_TREE
-                 && TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC)))
-       /* We have something like this:
-          
-          template <class T> struct S { void f(); };
-          
-          and we are printing S<int>::f().  This is a template
-          instantiation, but we don't print anything after the f.  */
-       ;
-      else
+      /* Be careful only to print things when we have them, so as not
+        to crash producing error messages.  */
+      if (args)
        {
-         OB_PUTC ('<');
-
-         /* Be careful only to print things when we have them, so as not
-            to crash producing error messages.  */
-         if (args)
+         if (TREE_CODE (args) == TREE_LIST)
            {
-             if (TREE_CODE (args) == TREE_LIST)
+             tree arg;
+             int need_comma = 0;
+             
+             for (arg = args; arg; arg = TREE_CHAIN (arg))
                {
-                 tree arg;
-                 int need_comma = 0;
-
-                 for (arg = args; arg; arg = TREE_CHAIN (arg))
-                   {
-                     tree a = TREE_VALUE (arg);
-
-                     if (need_comma)
-                       OB_PUTS (", ");
-
-                     if (a)
-                       {
-                         if (TREE_CODE_CLASS (TREE_CODE (a)) == 't'
-                             || TREE_CODE (a) == TEMPLATE_DECL)
-                           dump_type (a, 0);
-                         else
-                           dump_expr (a, 0);
-                       }
+                 tree a = TREE_VALUE (arg);
+                 
+                 if (need_comma)
+                   OB_PUTS (", ");
                  
-                     need_comma = 1;
+                 if (a)
+                   {
+                     if (TREE_CODE_CLASS (TREE_CODE (a)) == 't'
+                         || TREE_CODE (a) == TEMPLATE_DECL)
+                       dump_type (a, 0);
+                     else
+                       dump_expr (a, 0);
                    }
+                 
+                 need_comma = 1;
                }
-             else if (TREE_CODE (args) == TREE_VEC)
+           }
+         else if (TREE_CODE (args) == TREE_VEC)
+           {
+             int i;
+             int need_comma = 0;
+             
+             if (TREE_VEC_LENGTH (args) > 0
+                 && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+               args = TREE_VEC_ELT (args, 
+                                    TREE_VEC_LENGTH (args) - 1);
+             
+             for (i = 0; i < TREE_VEC_LENGTH (args); i++)
                {
-                 int i;
-                 int need_comma = 0;
-
-                 if (TREE_VEC_LENGTH (args) > 0
-                     && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
-                   args = TREE_VEC_ELT (args, 
-                                        TREE_VEC_LENGTH (args) - 1);
-
-                 for (i = 0; i < TREE_VEC_LENGTH (args); i++)
-                   {
-                     tree a = TREE_VEC_ELT (args, i);
-
-                     if (need_comma)
-                       OB_PUTS (", ");
-
-                     if (a)
-                       {
-                         if (TREE_CODE_CLASS (TREE_CODE (a)) == 't'
-                             || TREE_CODE (a) == TEMPLATE_DECL)
-                           dump_type (a, 0);
-                         else
-                           dump_expr (a, 0);
-                       }
+                 tree a = TREE_VEC_ELT (args, i);
+                 
+                 if (need_comma)
+                   OB_PUTS (", ");
                  
-                     need_comma = 1;
+                 if (a)
+                   {
+                     if (TREE_CODE_CLASS (TREE_CODE (a)) == 't'
+                         || TREE_CODE (a) == TEMPLATE_DECL)
+                       dump_type (a, 0);
+                     else
+                       dump_expr (a, 0);
                    }
+                 
+                 need_comma = 1;
                }
            }
-         OB_PUTC ('>');
        }
+      OB_PUTC ('>');
     }
 }
 
index 58747effcf079ffee36991e3fe65bc43a4d761d5..4bd0b08ecff7e4e0c8d6cf3062d57fb81daf495b 100644 (file)
@@ -70,21 +70,22 @@ is_friend (type, supplicant)
                  if (TREE_VALUE (friends) == NULL_TREE)
                    continue;
 
-                 if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL)
-                   {
-                     if (is_specialization_of (supplicant, 
-                                               TREE_VALUE (friends)))
-                       return 1;
-
-                     continue;
-                   }
-
-                 /* FIXME: The use of comptypes here is bogus, since
-                    two specializations of a template with non-type
-                    parameters may have the same type, but be
-                    different.  */
-                 if (comptypes (TREE_TYPE (supplicant),
-                                TREE_TYPE (TREE_VALUE (friends)), 1))
+                 if (supplicant == TREE_VALUE (friends))
+                   return 1;
+
+                 /* With -fguiding-decls we are more lenient about
+                    friendship.  This is bogus in general since two
+                    specializations of a template with non-type
+                    template parameters may have the same type, but
+                    be different.  */
+                 if (flag_guiding_decls 
+                     && comptypes (TREE_TYPE (supplicant),
+                                   TREE_TYPE (TREE_VALUE (friends)), 1))
+                   return 1;
+
+                 if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL
+                     && is_specialization_of (supplicant, 
+                                              TREE_VALUE (friends)))
                    return 1;
                }
              break;
@@ -253,6 +254,21 @@ make_friend_class (type, friend_type)
             IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type)));
       return;
     }
+
+  if (CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)) 
+    {
+      /* [temp.friend]
+        
+        Friend declarations shall not declare partial
+        specializations.  
+
+         Note that CLASSTYPE_TEMPLATE_SPECIALIZATION is not set for
+        full specializations.  */ 
+      cp_error ("partial specialization `%T' declared `friend'",
+               friend_type);
+      return;
+    }
+
   if (processing_template_decl > template_class_depth (type))
     /* If the TYPE is a template then it makes sense for it to be
        friends with itself; this means that each instantiation is
@@ -407,9 +423,7 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
 
         Note that because classes all wind up being top-level
         in their scope, their friend wind up in top-level scope as well.  */
-      DECL_ASSEMBLER_NAME (decl)
-       = build_decl_overload (declarator, TYPE_ARG_TYPES (TREE_TYPE (decl)),
-                              TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
+      set_mangled_name_for_decl (decl);
       DECL_ARGUMENTS (decl) = parmdecls;
       if (funcdef_flag)
        DECL_CLASS_CONTEXT (decl) = current_class_type;
@@ -417,20 +431,17 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
       if (! DECL_USE_TEMPLATE (decl))
        {
          /* We can call pushdecl here, because the TREE_CHAIN of this
-            FUNCTION_DECL is not needed for other purposes.  Don't do this
-            for a template instantiation.  */
-         if (!is_friend_template)
-           {  
-             /* However, we don't call pushdecl() for a friend
-                function of a template class, since in general,
-                such a declaration depends on template
-                parameters.  Instead, we call pushdecl when the
-                class is instantiated.  */
-             if (template_class_depth (current_class_type) == 0)
-               decl = pushdecl (decl);
-           }
+            FUNCTION_DECL is not needed for other purposes.  Don't do
+            this for a template instantiation.  However, we don't
+            call pushdecl() for a friend function of a template
+            class, since in general, such a declaration depends on
+            template parameters.  Instead, we call pushdecl when the
+            class is instantiated.  */
+         if (!is_friend_template
+             && template_class_depth (current_class_type) == 0)
+           decl = pushdecl (decl);
          else 
-           decl = push_template_decl (decl); 
+           decl = push_template_decl_real (decl, /*is_friend=*/1); 
 
          if (! funcdef_flag && ! flag_guiding_decls && ! is_friend_template
              && current_template_parms && uses_template_parms (decl))
index d718a44920b80788cb8938cb0b088702d91f823f..a4c19822897851469f8839ddcefbbd962571e653 100644 (file)
@@ -71,8 +71,6 @@ static void process_overload_item PROTO((tree,int));
 static void do_build_assign_ref PROTO((tree));
 static void do_build_copy_constructor PROTO((tree));
 static tree largest_union_member PROTO((tree));
-static tree build_decl_overload_real PROTO((tree, tree, tree, tree,
-                                           tree, int)); 
 static void build_template_template_parm_names PROTO((tree));
 static void build_template_parm_names PROTO((tree, tree));
 static void build_underscore_int PROTO((int));
@@ -922,7 +920,7 @@ build_overload_identifier (name)
       /* NAME is the TYPE_DECL for a template specialization.  */
       tree template, parmlist, arglist, tname;
       template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
-      arglist = innermost_args (TREE_VALUE (template), 0);
+      arglist = innermost_args (TREE_VALUE (template));
       template = TREE_PURPOSE (template);
       tname = DECL_NAME (template);
       parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
@@ -1499,7 +1497,10 @@ build_static_name (context, name)
   return get_identifier ((char *)obstack_base (&scratch_obstack));
 }
 \f
-static tree 
+/* FOR_METHOD should be 1 if the declaration in question is for a member
+   of a class (including a static member) and 2 if the declaration is
+   for a constructor.  */
+tree 
 build_decl_overload_real (dname, parms, ret_type, tparms, targs,
                          for_method) 
      tree dname;
@@ -1660,38 +1661,32 @@ build_decl_overload (dname, parms, for_method)
                                   NULL_TREE, for_method); 
 }
 
-
-/* Like build_decl_overload, but for template functions. */
+/* Set the mangled name (DECL_ASSEMBLER_NAME) for DECL.  */
 
 tree
-build_template_decl_overload (decl, parms, ret_type, tparms, targs,
-                             for_method) 
+set_mangled_name_for_decl (decl)
      tree decl;
-     tree parms;
-     tree ret_type;
-     tree tparms;
-     tree targs;
-     int for_method;
 {
-  tree res, saved_ctx;
+  tree parm_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
 
-  /* If the template is in a namespace, we need to put that into the
-     mangled name. Unfortunately, build_decl_overload_real does not
-     get the decl to mangle, so it relies on the current
-     namespace. Therefore, we set that here temporarily. */
-
-  my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd', 980702);
-  saved_ctx = current_namespace;
-  current_namespace = CP_DECL_CONTEXT (decl);  
-
-  res = build_decl_overload_real (DECL_NAME (decl), parms, ret_type,
-                                 tparms, targs, for_method); 
-
-  current_namespace = saved_ctx;
-  return res;
+  if (DECL_STATIC_FUNCTION_P (decl))
+    parm_types = 
+      hash_tree_chain (build_pointer_type (DECL_CLASS_CONTEXT (decl)),
+                                          parm_types);
+  else
+    /* The only member functions whose type is a FUNCTION_TYPE, rather
+       than a METHOD_TYPE, should be static members.  */
+    my_friendly_assert (!DECL_CONTEXT (decl)
+                       || !IS_AGGR_TYPE_CODE (TREE_CODE (DECL_CONTEXT (decl)))
+                       || TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE,
+                       0);
+
+  DECL_ASSEMBLER_NAME (decl)
+    = build_decl_overload (DECL_NAME (decl), parm_types, 
+                          DECL_FUNCTION_MEMBER_P (decl)
+                          + DECL_CONSTRUCTOR_P (decl));
 }
 
-
 /* Build an overload name for the type expression TYPE.  */
 
 tree
index 1113c15ba9565b902efe6efb97c1ebcfa57fd320..22d92428291a12fa6f806180bc5ddb3ef8e85708 100644 (file)
@@ -267,7 +267,7 @@ empty_parms ()
 %type <ttype> named_class_head_sans_basetype_defn
 %type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
 
-%type <ttype> self_template_type
+%type <ttype> self_template_type .finish_template_type
 
 %token NSNAME
 %type <ttype> NSNAME
@@ -556,22 +556,38 @@ template_parm:
        ;
 
 template_def:
-         template_header
-         extdef
-                { 
-                  if ($1) 
-                    end_template_decl (); 
-                 else
-                   end_specialization ();
-               }
-       | template_header
-         error  %prec EMPTY
-               { 
-                  if ($1) 
-                    end_template_decl ();
-                 else
-                   end_specialization (); 
-                }
+         template_header template_extdef
+                { finish_template_decl ($1); }
+       | template_header error  %prec EMPTY
+                { finish_template_decl ($1); }
+       ;
+
+template_extdef:
+         fndef eat_saved_input
+               { if (pending_inlines) do_pending_inlines (); }
+       | template_datadef
+               { if (pending_inlines) do_pending_inlines (); }
+       | template_def
+               { if (pending_inlines) do_pending_inlines (); }
+       | extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
+               { if (pending_inlines) do_pending_inlines ();
+                 pop_lang_context (); }
+       | extern_lang_string .hush_warning template_datadef .warning_ok
+               { if (pending_inlines) do_pending_inlines ();
+                 pop_lang_context (); }
+       | extension template_extdef
+               { pedantic = $<itype>1; }
+       ;
+
+template_datadef:
+         nomods_initdecls ';'
+       | declmods notype_initdecls ';'
+               {}
+       | typed_declspecs initdecls ';'
+                { note_list_got_semicolon ($1.t); }
+       | structsp ';'
+                { maybe_process_partial_specialization ($1.t);
+                 note_got_semicolon ($1.t); }
        ;
 
 datadef:
@@ -579,9 +595,7 @@ datadef:
        | declmods notype_initdecls ';'
                {}
        | typed_declspecs initdecls ';'
-               {
-                 note_list_got_semicolon ($1.t);
-               }
+                { note_list_got_semicolon ($1.t); }
         | declmods ';'
                { pedwarn ("empty declaration"); }
        | explicit_instantiation ';'
@@ -870,29 +884,29 @@ end_explicit_instantiation:
 
 template_type:
          PTYPENAME '<' template_arg_list_opt template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
+           .finish_template_type
+                { $$ = $5; }
        | TYPENAME  '<' template_arg_list_opt template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
+           .finish_template_type
+                { $$ = $5; }
        | self_template_type
        ;
 
 self_template_type:
          SELFNAME  '<' template_arg_list_opt template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
+           .finish_template_type
+                { $$ = $5; }
        ;
 
+.finish_template_type:
+                { 
+                 if (yychar == YYEMPTY)
+                   yychar = YYLEX;
+
+                 $$ = finish_template_type ($<ttype>-3, $<ttype>-1, 
+                                            yychar == SCOPE);
+               }
+
 template_close_bracket:
          '>'
        | RSHIFT 
@@ -2193,18 +2207,7 @@ named_class_head:
                    cp_pedwarn ("non-`union' tag used in declaring `%#T'", $$);
                  if ($2)
                    {
-                     if (IS_AGGR_TYPE ($$) && CLASSTYPE_USE_TEMPLATE ($$))
-                       {
-                         if (CLASSTYPE_IMPLICIT_INSTANTIATION ($$)
-                             && TYPE_SIZE ($$) == NULL_TREE)
-                           {
-                             SET_CLASSTYPE_TEMPLATE_SPECIALIZATION ($$);
-                             if (processing_template_decl)
-                               push_template_decl (TYPE_MAIN_DECL ($$));
-                           }
-                         else if (CLASSTYPE_TEMPLATE_INSTANTIATION ($$))
-                           cp_error ("specialization after instantiation of `%T'", $$);
-                       }
+                     maybe_process_partial_specialization ($$);
                      xref_basetypes (current_aggr, $1, $$, $2); 
                    }
                }
index 9c724314ccfaba37d715d2bf437bb3c4419725a8..07174a0b4c02e96444416e4fc72d7502938f435e 100644 (file)
@@ -80,29 +80,29 @@ static int unify PROTO((tree, tree, tree, tree, int, int*));
 static void add_pending_template PROTO((tree));
 static int push_tinst_level PROTO((tree));
 static tree classtype_mangled_name PROTO((tree));
-static char *mangle_class_name_for_template PROTO((char *, tree, tree, tree));
+static char *mangle_class_name_for_template PROTO((char *, tree, tree));
 static tree tsubst_expr_values PROTO((tree, tree));
 static int list_eq PROTO((tree, tree));
-static tree get_class_bindings PROTO((tree, tree, tree, tree));
+static tree get_class_bindings PROTO((tree, tree, tree));
 static tree coerce_template_parms PROTO((tree, tree, tree, int, int));
 static tree tsubst_enum        PROTO((tree, tree, tree *));
 static tree add_to_template_args PROTO((tree, tree));
+static tree add_outermost_template_args PROTO((tree, tree));
 static void maybe_adjust_types_for_deduction PROTO((unification_kind_t, tree*,
                                                    tree*)); 
 static int  type_unification_real PROTO((tree, tree, tree, tree,
                                         int, unification_kind_t, int, int*));
-static tree complete_template_args PROTO((tree, tree, int));
 static void note_template_header PROTO((int));
 static tree maybe_fold_nontype_arg PROTO((tree));
 static tree convert_nontype_argument PROTO((tree, tree));
 static tree get_bindings_overload PROTO((tree, tree, tree));
 static int for_each_template_parm PROTO((tree, tree_fn_t, void*));
 static tree build_template_parm_index PROTO((int, int, int, tree, tree));
-static tree original_template PROTO((tree));
 static int inline_needs_template_parms PROTO((tree));
 static void push_inline_template_parms_recursive PROTO((tree, int));
 static tree retrieve_specialization PROTO((tree, tree));
-static void register_specialization PROTO((tree, tree, tree));
+static tree register_specialization PROTO((tree, tree, tree));
+static int unregister_specialization PROTO((tree, tree));
 static void print_candidates PROTO((tree));
 static tree reduce_template_parm_level PROTO((tree, tree, int));
 static tree build_template_decl PROTO((tree, tree));
@@ -114,17 +114,72 @@ static int template_decl_level PROTO((tree));
 static tree maybe_get_template_decl_from_type_decl PROTO((tree));
 static int check_cv_quals_for_unify PROTO((int, tree, tree));
 static tree tsubst_template_arg_vector PROTO((tree, tree));
+static tree tsubst_template_parms PROTO((tree, tree));
 static void regenerate_decl_from_template PROTO((tree, tree));
 static int is_member_template_class PROTO((tree));
-
-/* Nonzero if ARGVEC contains multiple levels of template arguments.  */
-#define TMPL_ARGS_HAVE_MULTIPLE_LEVELS(NODE)           \
-  (NODE != NULL_TREE                                   \
-   && TREE_CODE (NODE) == TREE_VEC                     \
-   && TREE_VEC_LENGTH (NODE) > 0                       \
-   && TREE_VEC_ELT (NODE, 0) != NULL_TREE               \
+static tree most_specialized PROTO((tree, tree, tree));
+static tree most_specialized_class PROTO((tree, tree));
+static tree most_general_template PROTO((tree));
+static void set_mangled_name_for_template_decl PROTO((tree));
+
+/* We use TREE_VECs to hold template arguments.  If there is only one
+   level of template arguments, then the TREE_VEC contains the
+   arguments directly.  If there is more than one level of template
+   arguments, then each entry in the TREE_VEC is itself a TREE_VEC,
+   containing the template arguments for a single level.  The first
+   entry in the outer TREE_VEC is the outermost level of template
+   parameters; the last is the innermost.  
+
+   It is incorrect to ever form a template argument vector containing
+   only one level of arguments, but which is a TREE_VEC containing as
+   its only entry the TREE_VEC for that level.  */
+
+/* The depth of a template argument vector.  When called directly by
+   the parser, we use a TREE_LIST rather than a TREE_VEC to represent
+   template arguments.  In fact, we may even see NULL_TREE if there
+   are no template arguments.  In both of those cases, there is only
+   one level of template arguments.  */
+#define TMPL_ARGS_DEPTH(NODE)                                  \
+  ((NODE != NULL_TREE                                          \
+    && TREE_CODE (NODE) == TREE_VEC                            \
+    && TREE_VEC_LENGTH (NODE) > 0                              \
+    && TREE_VEC_ELT (NODE, 0) != NULL_TREE                     \
+    && TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC) ?       \
+   TREE_VEC_LENGTH (NODE) : 1)
+
+/* Non-zero if the template arguments is actually a vector of vectors,
+   rather than just a vector.  */
+#define TMPL_ARGS_HAVE_MULTIPLE_LEVELS(NODE) \
+  (NODE != NULL_TREE                                           \
+   && TREE_CODE (NODE) == TREE_VEC                             \
+   && TREE_VEC_LENGTH (NODE) > 0                               \
+   && TREE_VEC_ELT (NODE, 0) != NULL_TREE                      \
    && TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC)
 
+/* The LEVELth level of the template ARGS.  Note that template
+   parameter levels are indexed from 1, not from 0.  */
+#define TMPL_ARGS_LEVEL(ARGS, LEVEL)           \
+  (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (ARGS)       \
+   ? TREE_VEC_ELT ((ARGS), (LEVEL) - 1) : ARGS)
+
+/* Set the LEVELth level of the template ARGS to VAL.  This macro does
+   not work with single-level argument vectors.  */
+#define SET_TMPL_ARGS_LEVEL(ARGS, LEVEL, VAL)  \
+  (TREE_VEC_ELT ((ARGS), (LEVEL) - 1) = (VAL))
+
+/* Accesses the IDXth parameter in the LEVELth level of the ARGS.  */
+#define TMPL_ARG(ARGS, LEVEL, IDX)                             \
+  (TREE_VEC_ELT (TMPL_ARGS_LEVEL (ARGS, LEVEL), IDX))
+
+/* Set the IDXth element in the LEVELth level of ARGS to VAL.  This
+   macro does not work with single-level argument vectors.  */
+#define SET_TMPL_ARG(ARGS, LEVEL, IDX, VAL)                    \
+  (TREE_VEC_ELT (TREE_VEC_ELT ((ARGS), (LEVEL) - 1), (IDX)) = (VAL))
+
+/* The number of levels of template parameters given by NODE.  */
+#define TMPL_PARMS_DEPTH(NODE) \
+  (TREE_INT_CST_HIGH (TREE_PURPOSE (NODE)))
+
 /* Do any processing required when DECL (a member template declaration
    using TEMPLATE_PARAMETERS as its innermost parameter list) is
    finished.  Returns the TEMPLATE_DECL corresponding to DECL, unless
@@ -135,10 +190,7 @@ finish_member_template_decl (template_parameters, decl)
   tree template_parameters;
   tree decl;
 {
-  if (template_parameters)
-    end_template_decl ();
-  else
-    end_specialization ();
+  finish_template_decl (template_parameters);
 
   if (decl == NULL_TREE || decl == void_type_node)
     return NULL_TREE;
@@ -203,18 +255,6 @@ template_class_depth (type)
   return depth;
 }
 
-/* Return the original template for this decl, disregarding any
-   specializations.  */
-
-static tree
-original_template (decl)
-     tree decl;
-{
-  while (DECL_TEMPLATE_INFO (decl))
-    decl = DECL_TI_TEMPLATE (decl);
-  return decl;
-}
-
 /* Returns 1 if processing DECL as part of do_pending_inlines
    needs us to push template parms.  */
 
@@ -225,7 +265,7 @@ inline_needs_template_parms (decl)
   if (! DECL_TEMPLATE_INFO (decl))
     return 0;
 
-  return (list_length (DECL_TEMPLATE_PARMS (original_template (decl)))
+  return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (most_general_template (decl)))
          > (processing_template_decl + DECL_TEMPLATE_SPECIALIZATION (decl)));
 }
 
@@ -293,9 +333,9 @@ maybe_begin_member_template_processing (decl)
   if (! inline_needs_template_parms (decl))
     return;
 
-  parms = DECL_TEMPLATE_PARMS (original_template (decl));
+  parms = DECL_TEMPLATE_PARMS (most_general_template (decl));
 
-  levels = list_length (parms) - processing_template_decl;
+  levels = TMPL_PARMS_DEPTH (parms) - processing_template_decl;
 
   if (DECL_TEMPLATE_SPECIALIZATION (decl))
     {
@@ -371,7 +411,7 @@ is_member_template (t)
          /* If there are more levels of template parameters than
             there are template classes surrounding the declaration,
             then we have a member template.  */
-         && (list_length (DECL_TEMPLATE_PARMS (tmpl)) > 
+         && (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)) > 
              template_class_depth (DECL_CLASS_CONTEXT (t))))
        return 1;
     }
@@ -400,146 +440,58 @@ is_member_template_class (t)
   /* If there are more levels of template parameters than there are
      template classes surrounding the declaration, then we have a
      member template.  */
-  return  (list_length (DECL_TEMPLATE_PARMS (t)) > 
+  return  (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (t)) > 
           template_class_depth (DECL_CONTEXT (t)));
 }
 
-/* Return a new template argument vector which contains all of ARGS
-   for all outer templates TMPL is contained in, but has as its 
-   innermost set of arguments the EXTRA_ARGS.  If UNBOUND_ONLY, we
-   are only interested in unbound template arguments, not arguments from
-   enclosing templates that have been instantiated already.  */
+/* Return a new template argument vector which contains all of ARGS,
+   but has as its innermost set of arguments the EXTRA_ARGS.  The
+   resulting vector will be built on a temporary obstack, and so must
+   be explicitly copied to the permanent obstack, if required.  */
 
 static tree
-complete_template_args (tmpl, extra_args, unbound_only)
-     tree tmpl, extra_args;
-     int unbound_only;
+add_to_template_args (args, extra_args)
+     tree args;
+     tree extra_args;
 {
-  /* depth is the number of levels of enclosing args we're adding.  */
-  int depth, i;
-  tree args, new_args, spec_args = NULL_TREE;
-  int extra_arg_depth;
-
-  my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
-  my_friendly_assert (TREE_CODE (extra_args) == TREE_VEC, 0);
-
-  if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (extra_args))
-    extra_arg_depth = TREE_VEC_LENGTH (extra_args);
-  else
-    extra_arg_depth = 1;
-
-  if (DECL_TEMPLATE_INFO (tmpl) && !unbound_only)
-    {
-      /* A specialization of a member template of a template class shows up
-        as a TEMPLATE_DECL with DECL_TEMPLATE_SPECIALIZATION set.
-        DECL_TI_ARGS is the specialization args, and DECL_TI_TEMPLATE
-        is the template being specialized.  */
-      if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
-       {
-         spec_args = DECL_TI_ARGS (tmpl);
-         tmpl = DECL_TI_TEMPLATE (tmpl);
-       }
-
-      if (DECL_TEMPLATE_INFO (tmpl))
-       {
-         /* A partial instantiation of a member template shows up as a
-            TEMPLATE_DECL with DECL_TEMPLATE_INFO.  DECL_TI_ARGS is
-            all the bound template arguments.  */
-         args = DECL_TI_ARGS (tmpl);
-         if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
-           depth = 1;
-         else
-           depth = TREE_VEC_LENGTH (args);
-       }
-      else
-       /* If we are a specialization, we might have no previously bound
-          template args.  */
-       depth = 0;
-
-      new_args = make_tree_vec (depth + extra_arg_depth + (!!spec_args));
-
-      if (depth == 1)
-       TREE_VEC_ELT (new_args, 0) = args;
-      else
-       for (i = 0; i < depth; ++i)
-         TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (args, i);
-    }
-  else
-    {
-      tree type;
-      int skip;
-
-      /* For unbound args, we have to do more work.  We are getting bindings
-        for the innermost args from extra_args, so we start from our
-        context and work out until we've seen all the args.  We need to
-        do it this way to handle partial specialization.  */
-
-      depth = list_length (DECL_TEMPLATE_PARMS (tmpl)) - 1;
-      if (depth == 0)
-       return extra_args;
-
-      new_args = make_tree_vec (depth + extra_arg_depth);
-
-      /* If this isn't a member template, extra_args is for the innermost
-        template class, so skip over it.  */
-      skip = (! is_member_template (tmpl));
-
-      if (depth > skip)
-       {
-         type = DECL_REAL_CONTEXT (tmpl);
-         for (i = depth; i; type = TYPE_CONTEXT (type))
-           if (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)))
-             {
-               if (skip)
-                 skip = 0;
-               else
-                 {
-                   --i;
-                   TREE_VEC_ELT (new_args, i) = CLASSTYPE_TI_ARGS (type);
-                 }
-             }
-       }
-    }
+  tree new_args;
+  int extra_depth;
+  int i;
+  int j;
 
-  if (extra_arg_depth == 1)
-    TREE_VEC_ELT (new_args, depth++) = extra_args;
-  else
-    for (i = 0; i < extra_arg_depth; ++i)
-      TREE_VEC_ELT (new_args, depth++) = TREE_VEC_ELT (extra_args, i);
+  extra_depth = TMPL_ARGS_DEPTH (extra_args);
+  new_args = make_temp_vec (TMPL_ARGS_DEPTH (args) + extra_depth);
 
-  if (spec_args)
-    TREE_VEC_ELT (new_args, depth) = spec_args;
+  for (i = 1; i <= TMPL_ARGS_DEPTH (args); ++i)
+    SET_TMPL_ARGS_LEVEL (new_args, i, TMPL_ARGS_LEVEL (args, i));
 
+  for (j = 1; j <= extra_depth; ++j, ++i)
+    SET_TMPL_ARGS_LEVEL (new_args, i, TMPL_ARGS_LEVEL (extra_args, j));
+    
   return new_args;
 }
 
-/* Return a new template argument vector which contains all of ARGS,
-   but has as its innermost set of arguments the EXTRA_ARGS.  */
+/* Like add_to_template_args, but only the outermost ARGS are added to
+   the EXTRA_ARGS.  In particular, all but TMPL_ARGS_DEPTH
+   (EXTRA_ARGS) levels are added.  This function is used to combine
+   the template arguments from a partial instantiation with the
+   template arguments used to attain the full instantiation from the
+   partial instantiation.  */
 
 static tree
-add_to_template_args (args, extra_args)
+add_outermost_template_args (args, extra_args)
      tree args;
      tree extra_args;
 {
   tree new_args;
 
-  if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
-    {
-      new_args = make_tree_vec (2);
-      TREE_VEC_ELT (new_args, 0) = args;
-    }
-  else 
-    {
-      int i;
-
-      new_args = make_tree_vec (TREE_VEC_LENGTH (args) + 1);
+  /* For the moment, we make ARGS look like it contains fewer levels.  */
+  TREE_VEC_LENGTH (args) -= TMPL_ARGS_DEPTH (extra_args);
+  
+  new_args = add_to_template_args (args, extra_args);
 
-      for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
-       TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (args, i);
-    }
-         
-  TREE_VEC_ELT (new_args, 
-               TREE_VEC_LENGTH (new_args) - 1) = extra_args;
+  /* Now, we restore ARGS to its full dimensions.  */
+  TREE_VEC_LENGTH (args) += TMPL_ARGS_DEPTH (extra_args);
 
   return new_args;
 }
@@ -625,6 +577,27 @@ end_explicit_instantiation ()
   --processing_explicit_instantiation;
 }
 
+/* The TYPE is being declared.  If it is a template type, that means it
+   is a partial specialization.  Do appropriate error-checking.  */
+
+void 
+maybe_process_partial_specialization (type)
+     tree type;
+{
+  if (IS_AGGR_TYPE (type) && CLASSTYPE_USE_TEMPLATE (type))
+    {
+      if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
+         && TYPE_SIZE (type) == NULL_TREE)
+       {
+         SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type);
+         if (processing_template_decl)
+           push_template_decl (TYPE_MAIN_DECL (type));
+       }
+      else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+       cp_error ("specialization of `%T' after instantiation", type);
+    }
+}
+
 /* Retrieve the specialization (in the sense of [temp.spec] - a
    specialization is either an instantiation or an explicit
    specialization) of TMPL for the given template ARGS.  If there is
@@ -641,6 +614,12 @@ retrieve_specialization (tmpl, args)
 
   my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
 
+  /* There should be as many levels of arguments as there are
+     levels of parameters.  */
+  my_friendly_assert (TMPL_ARGS_DEPTH (args) 
+                     == TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)),
+                     0);
+                     
   for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
        s != NULL_TREE;
        s = TREE_CHAIN (s))
@@ -684,9 +663,10 @@ is_specialization_of (decl, tmpl)
 }
 
 /* Register the specialization SPEC as a specialization of TMPL with
-   the indicated ARGS.  */
+   the indicated ARGS.  Returns SPEC, or an equivalent prior
+   declaration, if available.  */
 
-static void
+static tree
 register_specialization (spec, tmpl, args)
      tree spec;
      tree tmpl;
@@ -696,14 +676,27 @@ register_specialization (spec, tmpl, args)
 
   my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
 
-  if (TREE_CODE (spec) != TEMPLATE_DECL
-      && list_length (DECL_TEMPLATE_PARMS (tmpl)) > 1)
-    /* Avoid registering function declarations as
-       specializations of member templates, as would otherwise
-       happen with out-of-class specializations of member
-       templates.  */
-    return;
+  if (TREE_CODE (spec) == FUNCTION_DECL 
+      && uses_template_parms (DECL_TI_ARGS (spec)))
+    /* This is the FUNCTION_DECL for a partial instantiation.  Don't
+       register it; we want the corresponding TEMPLATE_DECL instead.
+       We use `uses_template_parms (DECL_TI_ARGS (spec))' rather than
+       the more obvious `uses_template_parms (spec)' to avoid problems
+       with default function arguments.  In particular, given
+       something like this:
+
+          template <class T> void f(T t1, T t = T())
+
+       the default argument expression is not substituted for in an
+       instantiation unless and until it is actually needed.  */
+    return spec;
     
+  /* There should be as many levels of arguments as there are
+     levels of parameters.  */
+  my_friendly_assert (TMPL_ARGS_DEPTH (args) 
+                     == TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)),
+                     0);
+
   for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
        s != NULL_TREE;
        s = TREE_CHAIN (s))
@@ -720,7 +713,7 @@ register_specialization (spec, tmpl, args)
                  {
                    cp_error ("specialization of %D after instantiation",
                              fn);
-                   return;
+                   return spec;
                  }
                else
                  {
@@ -729,10 +722,22 @@ register_specialization (spec, tmpl, args)
                       the second is an explicit specialization, and
                       the implicit instantiation has not yet been
                       used.  That situation can occur if we have
-                      implicitly instantiated a member function of
-                      class type, and then specialized it later.  */
-                   TREE_VALUE (s) = spec;
-                   return;
+                      implicitly instantiated a member function and
+                      then specialized it later.
+
+                      We can also wind up here if a friend
+                      declaration that looked like an instantiation
+                      turns out to be a specialization:
+
+                        template <class T> void foo(T);
+                        class S { friend void foo<>(int) };
+                        template <> void foo(int);  
+
+                      We transform the existing DECL in place so that
+                      any pointers to it become pointers to the
+                      updated declaration.  */
+                   duplicate_decls (spec, TREE_VALUE (s));
+                   return TREE_VALUE (s);
                  }
              }
            else if (DECL_TEMPLATE_SPECIALIZATION (fn))
@@ -741,13 +746,38 @@ register_specialization (spec, tmpl, args)
                  cp_error ("duplicate specialization of %D", fn);
 
                TREE_VALUE (s) = spec;
-               return;
+               return spec;
              }
          }
       }
 
   DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
      = perm_tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+
+  return spec;
+}
+
+/* Unregister the specialization SPEC as a specialization of TMPL.
+   Returns nonzero if the SPEC was listed as a specialization of
+   TMPL.  */
+
+static int
+unregister_specialization (spec, tmpl)
+     tree spec;
+     tree tmpl;
+{
+  tree* s;
+
+  for (s = &DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+       *s != NULL_TREE;
+       s = &TREE_CHAIN (*s))
+    if (TREE_VALUE (*s) == spec)
+      {
+       *s = TREE_CHAIN (*s);
+       return 1;
+      }
+
+  return 0;
 }
 
 /* Print the list of candidate FNS in an error message.  */
@@ -856,13 +886,26 @@ determine_specialization (template_id, decl, targs_out,
   if (decl != NULL_TREE)
     {
       tree tmpl = most_specialized (templates, decl, targs_in);
+      tree inner_args;
+      tree tmpl_args;
 
       if (tmpl == error_mark_node) 
        goto ambiguous;
       else if (tmpl == NULL_TREE)
        goto no_match;
 
-      *targs_out = get_bindings (tmpl, decl, targs_in);
+      inner_args = get_bindings (tmpl, decl, targs_in);
+      tmpl_args = DECL_TI_ARGS (DECL_RESULT (tmpl));
+      if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (tmpl_args))
+       {
+         *targs_out = copy_node (tmpl_args);
+         SET_TMPL_ARGS_LEVEL (*targs_out, 
+                              TMPL_ARGS_DEPTH (*targs_out),
+                              inner_args);
+       }
+      else
+       *targs_out = inner_args;
+      
       return tmpl;
     }
 
@@ -927,8 +970,7 @@ determine_specialization (template_id, decl, targs_out,
 
      template <class T> struct S {};
      template <> struct S<int> { void f(); }
-     template <>
-     void S<int>::f();
+     template <> void S<int>::f();
 
    the TEMPLATE_COUNT would be 0.  (Note that this declaration is
    illegal; there should be no template <>.)
@@ -1018,7 +1060,8 @@ check_explicit_specialization (declarator, decl, template_count, flags)
        }
       else if (ctype != NULL_TREE
               && !TYPE_BEING_DEFINED (ctype)
-              && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
+              && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)
+              && !is_friend)
        {
          /* This case catches outdated code that looks like this:
 
@@ -1049,13 +1092,21 @@ check_explicit_specialization (declarator, decl, template_count, flags)
        }
       else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
        {
-         /* This case handles bogus declarations like
-            template <> template <class T>
-            void f<int>();  */
+         if (is_friend)
+           /* This could be something like:
 
-         cp_error ("template-id `%D' in declaration of primary template",
-                   declarator);
-         return decl;
+                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;
+           }
        }
     }
 
@@ -1073,6 +1124,7 @@ check_explicit_specialization (declarator, decl, template_count, flags)
 
   if (specialization || member_specialization || explicit_instantiation)
     {
+      tree gen_tmpl;
       tree tmpl = NULL_TREE;
       tree targs = NULL_TREE;
 
@@ -1172,9 +1224,10 @@ check_explicit_specialization (declarator, decl, template_count, flags)
         Note that for an explicit instantiation, even one for a
         member function, we cannot tell apriori whether the
         instantiation is for a member template, or just a member
-        function of a template class.  In particular, even in if the
-        instantiation is for a member template, the template
-        arguments could be deduced from the declaration.  */
+        function of a template class.  Even if a member template is
+        being instantiated, the member template arguments may be
+        elided if they can be deduced from the rest of the
+        declaration.  */
       tmpl = determine_specialization (declarator, decl,
                                       &targs, 
                                       member_specialization,
@@ -1182,9 +1235,11 @@ check_explicit_specialization (declarator, decl, template_count, flags)
            
       if (tmpl && tmpl != error_mark_node)
        {
+         gen_tmpl = most_general_template (tmpl);
+
          if (explicit_instantiation)
            {
-             decl = instantiate_template (tmpl, targs);
+             decl = instantiate_template (tmpl, innermost_args (targs));
              if (!DECL_TEMPLATE_SPECIALIZATION (decl))
                /* There doesn't seem to be anything in the draft to
                   prevent a specialization from being explicitly
@@ -1194,72 +1249,49 @@ check_explicit_specialization (declarator, decl, template_count, flags)
                SET_DECL_EXPLICIT_INSTANTIATION (decl);
              return decl;
            }
-         else if (DECL_STATIC_FUNCTION_P (tmpl)
-                  && DECL_NONSTATIC_MEMBER_FUNCTION_P (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.  */
+         if (DECL_STATIC_FUNCTION_P (tmpl)
+             && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
            {
              revert_static_member_fn (&decl, 0, 0);
              last_function_parms = TREE_CHAIN (last_function_parms);
            }
 
+         /* Set up the DECL_TEMPLATE_INFO for DECL.  */
+         DECL_TEMPLATE_INFO (decl) 
+           = perm_tree_cons (tmpl, targs, NULL_TREE);
+
          /* Mangle the function name appropriately.  Note that we do
             not mangle specializations of non-template member
             functions of template classes, e.g. with
+
               template <class T> struct S { void f(); }
+
             and given the specialization 
+
               template <> void S<int>::f() {}
+
             we do not mangle S<int>::f() here.  That's because it's
             just an ordinary member function and doesn't need special
-            treatment.  */
+            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)
-           {
-             tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
-
-             if (ctype 
-                 && TREE_CODE (TREE_TYPE (tmpl)) == FUNCTION_TYPE)
-               arg_types = 
-                 hash_tree_chain (build_pointer_type (ctype),
-                                  arg_types);
-
-             DECL_ASSEMBLER_NAME (decl) 
-               = build_template_decl_overload 
-               (decl, arg_types, TREE_TYPE (TREE_TYPE (tmpl)),
-                DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
-                targs, ctype != NULL_TREE);
-           }
+           set_mangled_name_for_template_decl (decl);
 
          if (is_friend && !have_def)
-           {
-             /* This is not really a declaration of a specialization.
-                It's just the name of an instantiation.  But, it's not
-                a request for an instantiation, either.  */
+           /* This is not really a declaration of a specialization.
+              It's just the name of an instantiation.  But, it's not
+              a request for an instantiation, either.  */
              SET_DECL_IMPLICIT_INSTANTIATION (decl);
-             DECL_TEMPLATE_INFO (decl) 
-               = perm_tree_cons (tmpl, targs, NULL_TREE);
-             return decl;
-           }
-
-         /* If DECL_TI_TEMPLATE (decl), the decl is an
-            instantiation of a specialization of a member template.
-            (In other words, there was a member template, in a
-            class template.  That member template was specialized.
-            We then instantiated the class, so there is now an
-            instance of that specialization.)  
-
-            According to the CD2,
-
-            14.7.3.13 [tmpl.expl.spec]
-              
-            A specialization  of  a member function template or
-            member class template of a non-specialized class
-            template is itself a template.             
-
-            So, we just leave the template info alone in this case.  */
-         if (!(DECL_TEMPLATE_INFO (decl) && DECL_TI_TEMPLATE (decl)))
-           DECL_TEMPLATE_INFO (decl)
-             = perm_tree_cons (tmpl, targs, NULL_TREE);
 
-         register_specialization (decl, tmpl, targs);
+         /* Register this specialization so that we can find it
+            again.  */
+         decl = register_specialization (decl, gen_tmpl, targs);
 
          return decl;
        }
@@ -1521,26 +1553,34 @@ end_template_decl ()
   (void) get_pending_sizes (); /* Why? */
 }
 
-/* Generate a valid set of template args from current_template_parms.  */
+/* Given a template argument vector containing the template PARMS.
+   The innermost PARMS are given first.  */
 
 tree
 current_template_args ()
 {
-  tree header = current_template_parms;
-  int length = list_length (header);
-  tree args = make_tree_vec (length);
+  tree header;
+  tree args;
+  int length = TMPL_PARMS_DEPTH (current_template_parms);
   int l = length;
 
-  while (header)
+  /* If there is only one level of template parameters, we do not
+     create a TREE_VEC of TREE_VECs.  Instead, we return a single
+     TREE_VEC containing the arguments.  */
+  if (length > 1)
+    args = make_tree_vec (length);
+
+  for (header = current_template_parms; header; header = TREE_CHAIN (header))
     {
       tree a = copy_node (TREE_VALUE (header));
-      int i = TREE_VEC_LENGTH (a);
+      int i;
+
       TREE_TYPE (a) = NULL_TREE;
-      while (i--)
+      for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
        {
          tree t = TREE_VEC_ELT (a, i);
 
-         /* t will be a list if we are called from within a
+         /* T will be a list if we are called from within a
             begin/end_template_parm_list pair, but a vector directly
             if within a begin/end_member_template_processing pair.  */
          if (TREE_CODE (t) == TREE_LIST) 
@@ -1552,18 +1592,19 @@ current_template_args ()
                t = TREE_TYPE (t);
              else
                t = DECL_INITIAL (t);
+             TREE_VEC_ELT (a, i) = t;
            }
-
-         TREE_VEC_ELT (a, i) = t;
        }
-      TREE_VEC_ELT (args, --l) = a;
-      header = TREE_CHAIN (header);
+
+      if (length > 1)
+       TREE_VEC_ELT (args, --l) = a;
+      else
+       args = a;
     }
 
   return args;
 }
 
-
 /* Return a TEMPLATE_DECL corresponding to DECL, using the indicated
    template PARMS.  Used by push_template_decl below.  */
 
@@ -1668,9 +1709,7 @@ push_template_decl_real (decl, is_friend)
   /* For determining whether this is a primary template or not, we're really
      interested in the lexical context, not the true context.  */
   if (is_friend)
-    /* For a TYPE_DECL, there is no DECL_CLASS_CONTEXT.  */
-    info = TREE_CODE (decl) == FUNCTION_DECL 
-      ? DECL_CLASS_CONTEXT (decl) : current_class_type;
+    info = current_class_type;
   else
     info = ctx;
 
@@ -1697,8 +1736,7 @@ push_template_decl_real (decl, is_friend)
     {
       tree type = TREE_TYPE (decl);
       tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
-      tree mainargs = CLASSTYPE_TI_ARGS (type);
-      tree spec = DECL_TEMPLATE_SPECIALIZATIONS (maintmpl);
+      tree specargs = CLASSTYPE_TI_ARGS (type);
 
       /* We check that each of the template parameters given in the
         partial specialization is used in the argument list to the
@@ -1732,15 +1770,16 @@ push_template_decl_real (decl, is_friend)
          or some such would have been OK.  */
       int  i;
       struct template_parm_data tpd;
-      int ntparms = TREE_VEC_LENGTH (TREE_VALUE (current_template_parms));
+      int ntparms 
+       = TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS (current_template_parms));
       int did_error_intro = 0;
 
-      tpd.level = TREE_INT_CST_HIGH (TREE_PURPOSE (current_template_parms));
+      tpd.level = TMPL_PARMS_DEPTH (current_template_parms);
       tpd.parms = alloca (sizeof (int) * ntparms);
       for (i = 0; i < ntparms; ++i)
        tpd.parms[i] = 0;
-      for (i = 0; i < TREE_VEC_LENGTH (mainargs); ++i)
-       for_each_template_parm (TREE_VEC_ELT (mainargs, i),
+      for (i = 0; i < TREE_VEC_LENGTH (specargs); ++i)
+       for_each_template_parm (TREE_VEC_ELT (specargs, i),
                                &mark_template_parm,
                                &tpd);
       for (i = 0; i < ntparms; ++i)
@@ -1760,16 +1799,22 @@ push_template_decl_real (decl, is_friend)
                                   i)));
          }
 
-      for (; spec; spec = TREE_CHAIN (spec))
-       {
-         /* purpose: args to main template
-            value: spec template */
-         if (comp_template_args (TREE_PURPOSE (spec), mainargs))
-           return decl;
-       }
+      /* [temp.class.spec]
+
+        The argument list of the specialization shall not be
+        identical to the implicit argument list of the primary
+        template.  */
+      if (comp_template_args (specargs, 
+                             CLASSTYPE_TI_ARGS (TREE_TYPE (maintmpl))))
+       cp_error ("partial specialization `%T' does not specialize any template arguments", type);
+                          
+      if (retrieve_specialization (maintmpl, specargs))
+       /* We've already got this specialization.  */
+       return decl;
 
       DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) = CLASSTYPE_TI_SPEC_INFO (type)
-       = perm_tree_cons (mainargs, TREE_VALUE (current_template_parms),
+       = perm_tree_cons (innermost_args (specargs),
+                         INNERMOST_TEMPLATE_PARMS (current_template_parms),
                          DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
       TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
       return decl;
@@ -1857,7 +1902,7 @@ push_template_decl_real (decl, is_friend)
              return decl;
            }
          
-         a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+         a = innermost_args (args);
          t = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
          if (TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (a))
            {
@@ -1865,15 +1910,15 @@ push_template_decl_real (decl, is_friend)
                        TREE_VEC_LENGTH (a), decl);
              cp_error ("  but %d required", TREE_VEC_LENGTH (t));
            }
-         if (TREE_VEC_LENGTH (args) > 1)
+         if (TMPL_ARGS_DEPTH (args) > 1)
            /* Get the template parameters for the enclosing template
               class.  */ 
-           a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 2);
+           a = TMPL_ARGS_LEVEL (args, TMPL_ARGS_DEPTH (args) - 1);
          else
            a = NULL_TREE;
        }
       else 
-       a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+       a = innermost_args (args);
 
       t = NULL_TREE;
 
@@ -1899,23 +1944,18 @@ push_template_decl_real (decl, is_friend)
          cp_error ("  but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
        }
     }
-  /* Get the innermost set of template arguments.  We don't do this
-     for a non-template member function of a nested template class
-     because there we will never get a `partial instantiation' of the
-     function containing the outer arguments, and so we must save all
-     of the arguments here.  */
-  if (TREE_CODE (decl) != FUNCTION_DECL 
-      || template_class_depth (ctx) <= 1
-      || primary)
-    args = innermost_args (args, 0);
 
   DECL_TEMPLATE_RESULT (tmpl) = decl;
   TREE_TYPE (tmpl) = TREE_TYPE (decl);
 
-  if (! ctx && !(is_friend && template_class_depth (info) > 0))
-    /* Note that we do not try to push a global template friend
-       declared in a template class; such a thing may well depend on
-       the template parameters of the class.  */
+  /* Push template declarations for global functions and types.  Note
+     that we do not try to push a global template friend declared in a
+     template class; such a thing may well depend on the template
+     parameters of the class.  With guiding declarations, however, we
+     push the template so that subsequent declarations of the template
+     will match this one.  */
+  if (! ctx 
+      && !(is_friend && template_class_depth (current_class_type) > 0))
     tmpl = pushdecl_namespace_level (tmpl);
 
   if (primary)
@@ -2733,7 +2773,7 @@ comp_template_args (oldargs, newargs)
       if (TREE_CODE (nt) == TREE_VEC)
         {
           /* For member templates */
-         if (comp_template_args (nt, ot))
+         if (comp_template_args (ot, nt))
            continue;
         }
       else if (TREE_CODE_CLASS (TREE_CODE (ot)) == 't')
@@ -2752,10 +2792,9 @@ comp_template_args (oldargs, newargs)
    for the instantiation.  */
 
 static char *
-mangle_class_name_for_template (name, parms, arglist, ctx)
+mangle_class_name_for_template (name, parms, arglist)
      char *name;
      tree parms, arglist;
-     tree ctx;
 {
   static struct obstack scratch_obstack;
   static char *scratch_firstobj;
@@ -2767,37 +2806,13 @@ mangle_class_name_for_template (name, parms, arglist, ctx)
     obstack_free (&scratch_obstack, scratch_firstobj);
   scratch_firstobj = obstack_alloc (&scratch_obstack, 1);
 
-#if 0
-#define buflen sizeof(buf)
-#define check  if (bufp >= buf+buflen-1) goto too_long
-#define ccat(c) *bufp++=(c); check
-#define advance        bufp+=strlen(bufp); check
-#define cat(s) strncpy(bufp, s, buf+buflen-bufp-1); advance
-#else
-#define check
 #define ccat(c)        obstack_1grow (&scratch_obstack, (c));
-#define advance
 #define cat(s) obstack_grow (&scratch_obstack, (s), strlen (s))
-#endif
 
-  if (ctx && ctx != global_namespace)
-    {
-      char* s;
-
-      if (TREE_CODE (ctx) == FUNCTION_DECL)
-       s = fndecl_as_string (ctx, 0);
-      else if (TREE_CODE_CLASS (TREE_CODE (ctx)) == 't')
-       s = type_as_string_real (ctx, 0, 1);
-      else if (TREE_CODE (ctx) == NAMESPACE_DECL)
-       s = decl_as_string (ctx, 0);
-      else
-       my_friendly_abort (0);
-      cat (s);
-      cat ("::");
-    }
   cat (name);
   ccat ('<');
   nparms = TREE_VEC_LENGTH (parms);
+  arglist = innermost_args (arglist);
   my_friendly_assert (nparms == TREE_VEC_LENGTH (arglist), 268);
   for (i = 0; i < nparms; i++)
     {
@@ -2860,13 +2875,6 @@ mangle_class_name_for_template (name, parms, arglist, ctx)
   ccat ('>');
   ccat ('\0');
   return (char *) obstack_base (&scratch_obstack);
-
-#if 0
- too_long:
-#endif
-  fatal ("out of (preallocated) string space creating template instantiation name");
-  /* NOTREACHED */
-  return NULL;
 }
 
 static tree
@@ -2874,22 +2882,18 @@ classtype_mangled_name (t)
      tree t;
 {
   if (CLASSTYPE_TEMPLATE_INFO (t)
+      /* Specializations have already had their names set up in
+        lookup_template_class.  */
+      && !CLASSTYPE_TEMPLATE_SPECIALIZATION (t)
+      /* For non-primary templates, the template parameters are
+        implicit from their surrounding context.  */
       && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))
     {
       tree name = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
-      /* We do not pass in the context here since that is only needed
-        when mangling the name of instantiations, not the primary
-        template declaration.  In reality, it should not be needed
-        then either, but the way lookup_template_class operates
-        requires the context for the moment.  In the long run,
-        lookup_template_class should not be looking for existing
-        instantiations by matching mangled names, but rather by
-        matching the templates, and then scanning the instantiation
-        list.  */
       char *mangled_name = mangle_class_name_for_template
        (IDENTIFIER_POINTER (name),
         DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (t)),
-        CLASSTYPE_TI_ARGS (t), NULL_TREE);
+        CLASSTYPE_TI_ARGS (t));
       tree id = get_identifier (mangled_name);
       IDENTIFIER_TEMPLATE (id) = name;
       return id;
@@ -2967,21 +2971,28 @@ maybe_get_template_decl_from_type_decl (decl)
    parameters, find the desired type.
 
    D1 is the PTYPENAME terminal, and ARGLIST is the list of arguments.
-   Since ARGLIST is build on the decl_obstack, we must copy it here
-   to keep it from being reclaimed when the decl storage is reclaimed.
+   (Actually ARGLIST may be either a TREE_LIST or a TREE_VEC.  It will
+   be a TREE_LIST if called directly from the parser, and a TREE_VEC
+   otherwise.)  Since ARGLIST is build on the decl_obstack, we must
+   copy it here to keep it from being reclaimed when the decl storage
+   is reclaimed.
 
    IN_DECL, if non-NULL, is the template declaration we are trying to
    instantiate.  
 
+   If ENTERING_SCOPE is non-zero, we are about to enter the scope of
+   the class we are looking up.
+
    If the template class is really a local class in a template
    function, then the FUNCTION_CONTEXT is the function in which it is
    being instantiated.  */
 
 tree
-lookup_template_class (d1, arglist, in_decl, context)
+lookup_template_class (d1, arglist, in_decl, context, entering_scope)
      tree d1, arglist;
      tree in_decl;
      tree context;
+     int entering_scope;
 {
   tree template = NULL_TREE, parmlist;
   char *mangled_name;
@@ -3070,161 +3081,185 @@ lookup_template_class (d1, arglist, in_decl, context)
       TYPE_SIZE (parm) = 0;
       return parm;
     }
-  else if (PRIMARY_TEMPLATE_P (template)
-          || (TREE_CODE (TYPE_CONTEXT (TREE_TYPE (template))) 
-              == FUNCTION_DECL))
+  else 
     {
-      tree arglist_for_mangling;
+      tree template_type = TREE_TYPE (template);
+      tree type_decl;
+      tree found = NULL_TREE;
+      int arg_depth;
+      int parm_depth;
 
-      parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
+      template = most_general_template (template);
+      parmlist = DECL_TEMPLATE_PARMS (template);
+      parm_depth = TMPL_PARMS_DEPTH (parmlist);
+      arg_depth = TMPL_ARGS_DEPTH (arglist);
+
+      if (arg_depth == 1 && parm_depth > 1)
+       {
+         /* We've been with an incomplete set of template arguments.
+            For example, given:
+
+              template <class T> struct S1 {
+                template <class U> struct S2 {};
+                template <class U> struct S2<U*> {};
+               };
+            
+            we will be called with an ARGLIST of `U*', but the
+            TEMPLATE will be `template <class T> template
+            <class U> struct S1<T>::S2'.  We must fill in the missing
+            arguments.  */
+         my_friendly_assert (context != NULL_TREE, 0);
+         while (!IS_AGGR_TYPE_CODE (TREE_CODE (context)))
+           context = DECL_REAL_CONTEXT (context);
+         arglist = add_to_template_args (CLASSTYPE_TI_ARGS (context),
+                                         arglist);
+         arg_depth = TMPL_ARGS_DEPTH (arglist);
+       }
 
-      if (/* ARGLIST can be NULL_TREE if there are default arguments.  */
-         arglist != NULL_TREE
-         && TREE_CODE (arglist) == TREE_VEC 
-         && TREE_VEC_LENGTH (arglist) > 1
-         && list_length (DECL_TEMPLATE_PARMS (template)) > 1)
+      my_friendly_assert (parm_depth == arg_depth, 0);
+      
+      /* Calculate the BOUND_ARGS.  These will be the args that are
+        actually tsubst'd into the definition to create the
+        instantiation.  */
+      if (parm_depth > 1)
        {
          /* We have multiple levels of arguments to coerce, at once.  */
-         tree new_args = 
-           make_tree_vec (list_length (DECL_TEMPLATE_PARMS (template)));
          int i;
+
+         tree bound_args = make_tree_vec (parm_depth);
          
          for (i = TREE_VEC_LENGTH (arglist) - 1, 
                 t = DECL_TEMPLATE_PARMS (template); 
               i >= 0 && t != NULL_TREE;
               --i, t = TREE_CHAIN (t))
-           TREE_VEC_ELT (new_args, i) =
+           TREE_VEC_ELT (bound_args, i) =
              coerce_template_parms (TREE_VALUE (t),
                                     TREE_VEC_ELT (arglist, i),
                                     template, 1, 1);
-         arglist = new_args;
+         arglist = bound_args;
        }
       else
-       arglist = coerce_template_parms (parmlist, 
-                                        innermost_args (arglist, 0),
-                                        template, 1, 1);
-     if (arglist == error_mark_node)
+       arglist
+         = coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parmlist),
+                                  innermost_args (arglist),
+                                  template, 1, 1);
+
+      if (arglist == error_mark_node)
+       /* We were unable to bind the arguments.  */
        return error_mark_node;
-      if (uses_template_parms (arglist))
-       {
-         tree found;
-         if (comp_template_args
-             (CLASSTYPE_TI_ARGS (TREE_TYPE (template)), arglist))
-           found = TREE_TYPE (template);
-         else
-           {
-             for (found = DECL_TEMPLATE_INSTANTIATIONS (template);
-                  found; found = TREE_CHAIN (found))
-               {
-                 if (TI_USES_TEMPLATE_PARMS (found)
-                     && comp_template_args (TREE_PURPOSE (found), arglist))
-                   break;
-               }
-             if (found)
-               found = TREE_VALUE (found);
-           }
 
-         if (found)
+      /* In the scope of a template class, explicit references to the
+        template class refer to the type of the template, not any
+        instantiation of it.  For example, in:
+        
+          template <class T> class C { void f(C<T>); }
+
+        the `C<T>' is just the same as `C'.  Outside of the
+        class, however, such a reference is an instantiation.  */
+      if (comp_template_args (CLASSTYPE_TI_ARGS (template_type),
+                             arglist))
+       {
+         found = template_type;
+         
+         if (!entering_scope && PRIMARY_TEMPLATE_P (template))
            {
-             if (can_free (&permanent_obstack, arglist))
-               obstack_free (&permanent_obstack, arglist);
-             return found;
+             tree ctx;
+             
+             /* Note that we use DECL_CONTEXT, rather than
+                CP_DECL_CONTEXT, so that the termination test is
+                always just `ctx'.  We're not interested in namepace
+                scopes.  */
+             for (ctx = current_class_type; 
+                  ctx; 
+                  ctx = (TREE_CODE_CLASS (TREE_CODE (ctx)) == 't') 
+                    ? TYPE_CONTEXT (ctx) : DECL_CONTEXT (ctx))
+               if (comptypes (ctx, template_type, 1))
+                 break;
+             
+             if (!ctx)
+               /* We're not in the scope of the class, so the
+                  TEMPLATE_TYPE is not the type we want after
+                  all.  */
+               found = NULL_TREE;
            }
        }
-
-      if (TREE_CODE (arglist) == TREE_VEC)
-       arglist_for_mangling = innermost_args (arglist, 0);
-      else
-       arglist_for_mangling = arglist;
-
-      /* FIXME avoid duplication.  */
-      mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
-                                                    parmlist,
-                                                    arglist_for_mangling,
-                                                    context);
-      id = get_identifier (mangled_name);
-      IDENTIFIER_TEMPLATE (id) = d1;
-
-      maybe_push_to_top_level (uses_template_parms (arglist));
-      t = xref_tag_from_type (TREE_TYPE (template), id, 1);
-
-      if (context != NULL_TREE)
+      
+      if (!found)
        {
-         /* Set up the context for the type_decl correctly.  Note
-            that we must clear DECL_ASSEMBLER_NAME to fool
-            build_overload_name into creating a new name.  */
-         tree type_decl = TYPE_STUB_DECL (t);
-
-         TYPE_CONTEXT (t) = FROB_CONTEXT (context);
-         DECL_CONTEXT (type_decl) = FROB_CONTEXT (context);
-         DECL_ASSEMBLER_NAME (type_decl) = DECL_NAME (type_decl);
-         DECL_ASSEMBLER_NAME (type_decl) = 
-           get_identifier (build_overload_name (t, 1, 1));
-       }
+         for (found = DECL_TEMPLATE_INSTANTIATIONS (template);
+              found; found = TREE_CHAIN (found))
+           if (comp_template_args (TREE_PURPOSE (found), arglist))
+             break;
 
-      pop_from_top_level ();
-    }
-  else
-    {
-      tree type_ctx = TYPE_CONTEXT (TREE_TYPE (template));
-      tree args = tsubst (CLASSTYPE_TI_ARGS (type_ctx), arglist, in_decl);
-      tree ctx = lookup_template_class (type_ctx, args,
-                                       in_decl, NULL_TREE);
-      id = d1;
-      arglist = CLASSTYPE_TI_ARGS (ctx);
-
-      if (TYPE_BEING_DEFINED (ctx) && ctx == current_class_type)
-       {
-         int save_temp = processing_template_decl;
-         processing_template_decl = 0;
-         t = xref_tag_from_type (TREE_TYPE (template), id, 0);
-         processing_template_decl = save_temp;
+         if (found)
+           found = TREE_VALUE (found);
        }
-      else
+      
+      if (found)
        {
-         t = lookup_nested_type_by_name (ctx, id);
-         my_friendly_assert (t != NULL_TREE, 42);
+         if (can_free (&permanent_obstack, arglist))
+           obstack_free (&permanent_obstack, arglist);
+         return found;
        }
-    }
 
-  /* Seems to be wanted.  */
-  CLASSTYPE_GOT_SEMICOLON (t) = 1;
+      /* Since we didn't find the type, we'll have to create it.
+        Since we'll be saving this type on the
+        DECL_TEMPLATE_INSTANTIATIONS list, it must be permanent.  */
+      push_obstacks (&permanent_obstack, &permanent_obstack);
+      
+      /* Create the type.  */
+      t = make_lang_type (TREE_CODE (template_type));
+      CLASSTYPE_DECLARED_CLASS (t) 
+       = CLASSTYPE_DECLARED_CLASS (template_type);
+      TYPE_CONTEXT (t) = FROB_CONTEXT (context);
+         
+      /* Create a stub TYPE_DECL for it.  */
+      type_decl = build_decl (TYPE_DECL, DECL_NAME (template), t);
+      SET_DECL_ARTIFICIAL (type_decl);
+      DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);
+      DECL_SOURCE_FILE (type_decl) 
+       = DECL_SOURCE_FILE (TYPE_STUB_DECL (template_type));
+      DECL_SOURCE_LINE (type_decl) 
+       = DECL_SOURCE_LINE (TYPE_STUB_DECL (template_type));
+      TYPE_STUB_DECL (t) = TYPE_NAME (t) = type_decl;
+
+      /* We're done with the permanent obstack, now.  */
+      pop_obstacks ();
+
+      /* Seems to be wanted.  */
+      CLASSTYPE_GOT_SEMICOLON (t) = 1;
 
-  if (! CLASSTYPE_TEMPLATE_INFO (t))
-    {
+      /* Set up the template information.  */
       arglist = copy_to_permanent (arglist);
       CLASSTYPE_TEMPLATE_INFO (t)
        = perm_tree_cons (template, arglist, NULL_TREE);
       DECL_TEMPLATE_INSTANTIATIONS (template) = perm_tree_cons
        (arglist, t, DECL_TEMPLATE_INSTANTIATIONS (template));
-      TI_USES_TEMPLATE_PARMS (DECL_TEMPLATE_INSTANTIATIONS (template))
-       = uses_template_parms (arglist);
-
       SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t);
 
-      /* We need to set this again after CLASSTYPE_TEMPLATE_INFO is set up.  */
-      DECL_ASSEMBLER_NAME (TYPE_MAIN_DECL (t)) = id;
+      /* Reset the name of the type, now that CLASSTYPE_TEMPLATE_INFO
+        is set up.  */
+      DECL_NAME (type_decl) = classtype_mangled_name (t);
+      DECL_ASSEMBLER_NAME (type_decl) = DECL_NAME (type_decl);
       if (! uses_template_parms (arglist))
-       DECL_ASSEMBLER_NAME (TYPE_MAIN_DECL (t)) 
-         = get_identifier (build_overload_name (t, 1, 1));
-
-      if (flag_external_templates && ! uses_template_parms (arglist)
-         && CLASSTYPE_INTERFACE_KNOWN (TREE_TYPE (template))
-         && ! CLASSTYPE_INTERFACE_ONLY (TREE_TYPE (template)))
-       add_pending_template (t);
-
-      if (uses_template_parms (arglist))
+       {
+         DECL_ASSEMBLER_NAME (type_decl)
+           = get_identifier (build_overload_name (t, 1, 1));
+         
+         if (flag_external_templates
+             && CLASSTYPE_INTERFACE_KNOWN (TREE_TYPE (template))
+             && ! CLASSTYPE_INTERFACE_ONLY (TREE_TYPE (template)))
+           add_pending_template (t);
+       }
+      else
        /* If the type makes use of template parameters, the
           code that generates debugging information will crash.  */
        DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1;
-    }
 
-  return t;
+      return t;
+    }
 }
 \f
-/* Should be defined in parse.h.  */
-extern int yychar;
-
 /* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM, or
    TEMPLATE_PARM_INDEX in T, call FN with the parameter and the DATA.
    If FN returns non-zero, the iteration is terminated, and
@@ -3626,32 +3661,26 @@ tsubst_friend_function (decl, args)
       tree template_id;
       tree new_args;
       tree tmpl;
-      tree tinfo;
 
       template_id
        = lookup_template_function (tsubst_expr (DECL_TI_TEMPLATE (decl),
                                                 args, NULL_TREE),
                                    tsubst (DECL_TI_ARGS (decl),
                                            args, NULL_TREE));
-      
-      /* Temporarily remove the DECL_TEMPLATE_INFO so as not to
-        confuse tsubst.  */
-      tinfo = DECL_TEMPLATE_INFO (decl);
-      DECL_TEMPLATE_INFO (decl) = NULL_TREE;
+      /* FIXME: The decl we create via the next tsubst be created on a
+        temporary obstack.  */
       new_friend = tsubst (decl, args, NULL_TREE);
-      DECL_TEMPLATE_INFO (decl) = tinfo;
-
-      tmpl = determine_specialization (template_id,
-                                      new_friend,
-                                      &new_args,
-                                      0, 1);
+      tmpl = determine_specialization (template_id, new_friend,
+                                      &new_args, 
+                                      /*need_member_template=*/0, 
+                                      /*complain=*/1);
       new_friend = instantiate_template (tmpl, new_args);
       goto done;
     }
-  else
-    new_friend = tsubst (decl, args, NULL_TREE);
+
+  new_friend = tsubst (decl, args, NULL_TREE);
        
-  /* The new_friend will look like an instantiation, to the
+  /* The NEW_FRIEND will look like an instantiation, to the
      compiler, but is not an instantiation from the point of view of
      the language.  For example, we might have had:
      
@@ -3664,15 +3693,110 @@ tsubst_friend_function (decl, args)
   DECL_USE_TEMPLATE (new_friend) = 0;
   if (TREE_CODE (decl) == TEMPLATE_DECL)
     DECL_USE_TEMPLATE (DECL_TEMPLATE_RESULT (new_friend)) = 0;
-  
+
+  /* The mangled name for the NEW_FRIEND is incorrect.  The call to
+     tsubst will have resulted in a call to
+     set_mangled_name_for_template_decl.  But, the function is not a
+     template instantiation and should not be mangled like one.
+     Therefore, we remangle the function name.  We don't have to do
+     this if the NEW_FRIEND is a template since
+     set_mangled_name_for_template_decl doesn't do anything if the
+     function declaration still uses template arguments.  */
+  if (TREE_CODE (new_friend) != TEMPLATE_DECL)
+    {
+      set_mangled_name_for_decl (new_friend);
+      DECL_RTL (new_friend) = 0;
+      make_decl_rtl (new_friend, NULL_PTR, 1);
+    }
+      
   if (DECL_NAMESPACE_SCOPE_P (new_friend))
     {
+      tree old_decl;
+      tree new_friend_args;
+
       if (TREE_CODE (new_friend) == TEMPLATE_DECL)
        /* This declaration is a `primary' template.  */
-       TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (new_friend))
-           = new_friend;
+       DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
+
+      /* We must save the DECL_TI_ARGS for NEW_FRIEND here because
+        pushdecl may call duplicate_decls which will free NEW_FRIEND
+        if possible.  */
+      new_friend_args = DECL_TI_ARGS (new_friend);
+      old_decl = pushdecl_namespace_level (new_friend);
+
+      if (old_decl != new_friend)
+       {
+         /* This new friend declaration matched an existing
+            declaration.  For example, given:
+
+              template <class T> void f(T);
+              template <class U> class C { 
+                template <class T> friend void f(T) {} 
+              };
+
+            the friend declaration actually provides the definition
+            of `f', once C has been instantiated for some type.  So,
+            old_decl will be the out-of-class template declaration,
+            while new_friend is the in-class definition.
+
+            But, if `f' was called before this point, the
+            instantiation of `f' will have DECL_TI_ARGS corresponding
+            to `T' but not to `U', references to which might appear
+            in the definition of `f'.  Previously, the most general
+            template for an instantiation of `f' was the out-of-class
+            version; now it is the in-class version.  Therefore, we
+            run through all specialization of `f', adding to their
+            DECL_TI_ARGS appropriately.  In particular, they need a
+            new set of outer arguments, corresponding to the
+            arguments for this class instantiation.  
+
+            The same situation can arise with something like this:
+
+              friend void f(int);
+              template <class T> class C { 
+                friend void f(T) {}
+               };
+
+            when `C<int>' is instantiated.  Now, `f(int)' is defined
+            in the class.  */
+
+         if (TREE_CODE (old_decl) != TEMPLATE_DECL)
+           /* duplicate_decls will take care of this case.  */
+           ;
+         else 
+           {
+             tree t;
+
+             for (t = DECL_TEMPLATE_SPECIALIZATIONS (old_decl); 
+                  t != NULL_TREE;
+                  t = TREE_CHAIN (t))
+               {
+                 tree spec = TREE_VALUE (t);
+                 
+                 DECL_TI_ARGS (spec) 
+                   = add_outermost_template_args (new_friend_args,
+                                                  DECL_TI_ARGS (spec));
+                 DECL_TI_ARGS (spec)
+                   = copy_to_permanent (DECL_TI_ARGS (spec));
+               }
 
-       new_friend = pushdecl_namespace_level (new_friend);
+             /* Now, since specializations are always supposed to
+                hang off of the most general template, we must move
+                them.  */
+             t = most_general_template (old_decl);
+             if (t != old_decl)
+               {
+                 DECL_TEMPLATE_SPECIALIZATIONS (t)
+                   = chainon (DECL_TEMPLATE_SPECIALIZATIONS (t),
+                              DECL_TEMPLATE_SPECIALIZATIONS (old_decl));
+                 DECL_TEMPLATE_SPECIALIZATIONS (old_decl) = NULL_TREE;
+               }
+           }
+
+         /* The information from NEW_FRIEND has been merged into OLD_DECL
+            by duplicate_decls.  */
+         new_friend = old_decl;
+       }
     }
   else if (TYPE_SIZE (DECL_CONTEXT (new_friend)))
     {
@@ -3709,9 +3833,15 @@ tsubst_friend_class (friend_tmpl, args)
   if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl))
     {
       /* The friend template has already been declared.  Just
-        check to see that the declarations match.  */
-      redeclare_class_template (TREE_TYPE (tmpl),
-                               DECL_TEMPLATE_PARMS (friend_tmpl));
+        check to see that the declarations match, and install any new
+        default parameters.  We must tsubst the default parameters,
+        of course.  We only need the innermost template parameters
+        because that is all that redeclare_class_template will look
+        at.  */
+      tree parms 
+       = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl),
+                                args);
+      redeclare_class_template (TREE_TYPE (tmpl), parms);
       friend_type = TREE_TYPE (tmpl);
     }
   else
@@ -3740,32 +3870,19 @@ tree
 instantiate_class_template (type)
      tree type;
 {
-  tree template, template_info, args, pattern, t, *field_chain;
-  tree typedecl, outer_args;
+  tree template, args, pattern, t, *field_chain;
+  tree typedecl;
 
   if (type == error_mark_node)
     return error_mark_node;
 
-  template_info = CLASSTYPE_TEMPLATE_INFO (type);
-
   if (TYPE_BEING_DEFINED (type) || TYPE_SIZE (type))
     return type;
 
-  template = TI_TEMPLATE (template_info);
+  template = most_general_template (CLASSTYPE_TI_TEMPLATE (type));
+  args = CLASSTYPE_TI_ARGS (type);
   my_friendly_assert (TREE_CODE (template) == TEMPLATE_DECL, 279);
-  args = TI_ARGS (template_info);
-
-  if (DECL_TEMPLATE_INFO (template))
-    {
-      outer_args = DECL_TI_ARGS (template);
-      while (DECL_TEMPLATE_INFO (template))
-       template = DECL_TI_TEMPLATE (template);
-    }
-  else
-    outer_args = NULL_TREE;
-
-  t = most_specialized_class
-    (DECL_TEMPLATE_SPECIALIZATIONS (template), args, outer_args);
+  t = most_specialized_class (template, args);
 
   if (t == error_mark_node)
     {
@@ -3774,7 +3891,7 @@ instantiate_class_template (type)
       for (t = DECL_TEMPLATE_SPECIALIZATIONS (template); t; t = TREE_CHAIN (t))
        {
          if (get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t),
-                                 args, outer_args))
+                                 args))
            {
              cp_error_at ("%s %+#T", str, TREE_TYPE (t));
              str = "               ";
@@ -3792,8 +3909,32 @@ instantiate_class_template (type)
     return type;
 
   if (t)
-    args = get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t),
-                              args, outer_args);
+    {
+      /* This TYPE is actually a instantiation of of a partial
+        specialization.  We replace the innermost set of ARGS with
+        the arguments appropriate for substitution.  For example,
+        given:
+
+          template <class T> struct S {};
+          template <class T> struct S<T*> {};
+        
+        and supposing that we are instantiating S<int*>, ARGS will
+        present be {int*} but we need {int}.  */
+      tree inner_args 
+       = get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t),
+                             args);
+
+      /* If there were multiple levels in ARGS, replacing the
+        innermost level would alter CLASSTYPE_TI_ARGS, which we don't
+        want, so we make a copy first.  */
+      if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
+       {
+         args = copy_node (args);
+         SET_TMPL_ARGS_LEVEL (args, TMPL_ARGS_DEPTH (args), inner_args);
+       }
+      else
+       args = inner_args;
+    }
 
   if (pedantic && uses_template_parms (args))
     /* If there are still template parameters amongst the args, then
@@ -3802,11 +3943,6 @@ instantiate_class_template (type)
        value that results in a specialization being used.  */
     return type;
 
-  /* We must copy the arguments to the permanent obstack since
-     during the tsubst'ing below they may wind up in the
-     DECL_TI_ARGS of some instantiated member template.  */
-  args = copy_to_permanent (args);
-
   TYPE_BEING_DEFINED (type) = 1;
 
   if (! push_tinst_level (type))
@@ -3815,8 +3951,10 @@ instantiate_class_template (type)
   maybe_push_to_top_level (uses_template_parms (type));
   pushclass (type, 0);
 
-  if (outer_args)
-    args = add_to_template_args (outer_args, args);
+  /* We must copy the arguments to the permanent obstack since
+     during the tsubst'ing below they may wind up in the
+     DECL_TI_ARGS of some instantiated member template.  */
+  args = copy_to_permanent (args);
 
   if (flag_external_templates)
     {
@@ -3936,11 +4074,12 @@ instantiate_class_template (type)
   for (t = CLASSTYPE_TAGS (pattern); t; t = TREE_CHAIN (t))
     {
       tree tag = TREE_VALUE (t);
+      tree name = TYPE_IDENTIFIER (tag);
+      tree newtag;
 
-      /* These will add themselves to CLASSTYPE_TAGS for the new type.  */
       if (TREE_CODE (tag) == ENUMERAL_TYPE)
        {
-         (void) tsubst_enum (tag, args, field_chain);
+         newtag = tsubst_enum (tag, args, field_chain);
          while (*field_chain)
            {
              DECL_FIELD_CONTEXT (*field_chain) = type;
@@ -3948,7 +4087,14 @@ instantiate_class_template (type)
            }
        }
       else
-       tsubst (tag, args, NULL_TREE);
+       newtag = tsubst (tag, args, NULL_TREE);
+
+      /* Now, we call pushtag to put this NEWTAG into the scope of
+        TYPE.  We first set up the IDENTIFIER_TYPE_VALUE to avoid
+        pushtag calling push_template_decl.  */
+      if (name)
+       SET_IDENTIFIER_TYPE_VALUE (name, newtag);
+      pushtag (name, newtag, /*globalize=*/0);
     }
 
   /* Don't replace enum constants here.  */
@@ -4014,14 +4160,16 @@ instantiate_class_template (type)
       tree friend_type = TREE_VALUE (t);
       tree new_friend_type;
 
-      if (TREE_CODE (friend_type) != TEMPLATE_DECL)
+      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
+       new_friend_type = tsubst_friend_class (friend_type, args);
+      else if (uses_template_parms (friend_type))
+       new_friend_type = tsubst (friend_type, args, NULL_TREE);
+      else 
        /* The call to xref_tag_from_type does injection for friend
           classes.  */
        new_friend_type = 
-         xref_tag_from_type (tsubst (friend_type, args, NULL_TREE),
-                             NULL_TREE, 1);
-      else
-       new_friend_type = tsubst_friend_class (friend_type, args);
+         xref_tag_from_type (friend_type, NULL_TREE, 1);
+
 
       if (TREE_CODE (friend_type) == TEMPLATE_DECL)
        /* Trick make_friend_class into realizing that the friend
@@ -4138,20 +4286,14 @@ maybe_fold_nontype_arg (arg)
 }
 
 /* Return the TREE_VEC with the arguments for the innermost template header,
-   where ARGS is either that or the VEC of VECs for all the arguments.
-
-   If is_spec, then we are dealing with a specialization of a member
-   template, and want the second-innermost args, the innermost ones that
-   are instantiated.  */
+   where ARGS is either that or the VEC of VECs for all the
+   arguments.  */
 
 tree
-innermost_args (args, is_spec)
+innermost_args (args)
      tree args;
-     int is_spec;
 {
-  if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
-    return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1 - is_spec);
-  return args;
+  return TMPL_ARGS_LEVEL (args, TMPL_ARGS_DEPTH (args));
 }
 
 /* Substitute ARGS into the vector of template arguments T.  */
@@ -4189,6 +4331,121 @@ tsubst_template_arg_vector (t, args)
   return t;
 }
 
+/* Return the result of substituting ARGS into the template parameters
+   given by PARMS.  If there are m levels of ARGS and m + n levels of
+   PARMS, then the result will contain n levels of PARMS.  For
+   example, if PARMS is `template <class T> template <class U>
+   template <T*, U, class V>' and ARGS is {{int}, {double}} then the
+   result will be `template <int*, double, class V>'.  */
+
+tree
+tsubst_template_parms (parms, args)
+     tree parms;
+     tree args;
+{
+  tree r;
+  tree* new_parms = &r;
+
+  for (new_parms = &r;
+       TMPL_PARMS_DEPTH (parms) > TMPL_ARGS_DEPTH (args);
+       new_parms = &(TREE_CHAIN (*new_parms)),
+        parms = TREE_CHAIN (parms))
+    {
+      tree new_vec = 
+       make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms)));
+      int i;
+      
+      for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i)
+       {
+         tree default_value =
+           TREE_PURPOSE (TREE_VEC_ELT (TREE_VALUE (parms), i));
+         tree parm_decl = 
+           TREE_VALUE (TREE_VEC_ELT (TREE_VALUE (parms), i));
+         
+         TREE_VEC_ELT (new_vec, i)
+           = build_tree_list (tsubst (default_value, args, NULL_TREE),
+                              tsubst (parm_decl, args, NULL_TREE));
+         
+       }
+      
+      *new_parms = 
+       tree_cons (build_int_2 (0, (TMPL_PARMS_DEPTH (parms) 
+                                   - TMPL_ARGS_DEPTH (args))),
+                  new_vec, NULL_TREE);
+    }
+
+  return r;
+}
+
+/* Substitute the ARGS into the indicated aggregate type T.  If T is
+   not an aggregate type, it is handled as if by tsubst.  IN_DECL is
+   as for tsubst.  If ENTERING_SCOPE is non-zero, T is the context for
+   a template which we are presently tsubst'ing.  Return the
+   subsituted value.  */
+
+tree
+tsubst_aggr_type (t, args, in_decl, entering_scope)
+     tree t;
+     tree args;
+     tree in_decl;
+     int entering_scope;
+{
+  if (t == NULL_TREE)
+    return NULL_TREE;
+
+  switch (TREE_CODE (t))
+    {
+    case RECORD_TYPE:
+      if (TYPE_PTRMEMFUNC_P (t))
+       {
+         tree r = build_ptrmemfunc_type
+           (tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, in_decl));
+         return cp_build_type_variant (r, TYPE_READONLY (t),
+                                       TYPE_VOLATILE (t));
+       }
+
+      /* else fall through */
+    case UNION_TYPE:
+      if (uses_template_parms (t))
+       {
+         tree argvec;
+         tree context;
+         tree r;
+
+         /* First, determine the context for the type we are looking
+            up.  */
+         if (TYPE_CONTEXT (t) != NULL_TREE)
+           context = tsubst_aggr_type (TYPE_CONTEXT (t), args,
+                                       in_decl, /*entering_scope=*/1);
+         else
+           context = NULL_TREE;
+
+         /* Then, figure out what arguments are appropriate for the
+            type we are trying to find.  For example, given:
+
+              template <class T> struct S;
+              template <class T, class U> void f(T, U) { S<U> su; }
+
+            and supposing that we are instantiating f<int, double>,
+            then our ARGS will be {int, double}, but, when looking up
+            S we only want {double}.  */
+         argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
+
+         r = lookup_template_class (t, argvec, in_decl, context,
+                                    entering_scope);
+
+         return cp_build_type_variant (r, TYPE_READONLY (t),
+                                       TYPE_VOLATILE (t));
+       }
+      else 
+       /* This is not a template type, so there's nothing to do.  */
+       return t;
+
+    default:
+      return tsubst (t, args, in_decl);
+    }
+}
+
 /* Take the tree structure T and replace template parameters used therein
    with the argument vector ARGS.  IN_DECL is an associated decl for
    diagnostics.
@@ -4226,52 +4483,9 @@ tsubst (t, args, in_decl)
   switch (TREE_CODE (t))
     {
     case RECORD_TYPE:
-      if (TYPE_PTRMEMFUNC_P (t))
-       {
-         tree r = build_ptrmemfunc_type
-           (tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, in_decl));
-         return cp_build_type_variant (r, TYPE_READONLY (t),
-                                       TYPE_VOLATILE (t));
-       }
-
-      /* else fall through */
     case UNION_TYPE:
-      if (uses_template_parms (t))
-       {
-         tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
-         tree context;
-         tree r;
+      return tsubst_aggr_type (t, args, in_decl, /*entering_scope=*/0);
 
-         if (TYPE_CONTEXT (t) != NULL_TREE)
-           {
-             context = tsubst (TYPE_CONTEXT (t), args, in_decl);
-         
-             if (TREE_CODE (context) != FUNCTION_DECL
-                 && TREE_CODE (context) != NAMESPACE_DECL)
-               {
-                 /* For a member class template, we need all the
-                    template arguments.  */
-                 if (CLASSTYPE_IS_TEMPLATE (TYPE_CONTEXT (t)))
-                   argvec = 
-                     add_to_template_args (CLASSTYPE_TI_ARGS (context),
-                                           argvec);
-
-                 if (CLASSTYPE_TEMPLATE_INFO (context))
-                   argvec = 
-                     complete_template_args (CLASSTYPE_TI_TEMPLATE (context),
-                                             argvec, 0);
-               }
-           }
-         else
-           context = NULL_TREE;
-
-         r = lookup_template_class (t, argvec, in_decl, context);
-
-         return cp_build_type_variant (r, TYPE_READONLY (t),
-                                       TYPE_VOLATILE (t));
-       }
-
-      /* else fall through */
     case ERROR_MARK:
     case IDENTIFIER_NODE:
     case OP_IDENTIFIER:
@@ -4287,7 +4501,8 @@ tsubst (t, args, in_decl)
 
     case ENUMERAL_TYPE:
       {
-       tree ctx = tsubst (TYPE_CONTEXT (t), args, in_decl);
+       tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, in_decl,
+                                    /*entering_scope=*/1);
        if (ctx == NULL_TREE || TREE_CODE (ctx) == NAMESPACE_DECL)
          return t;
        else if (ctx == current_function_decl)
@@ -4345,19 +4560,9 @@ tsubst (t, args, in_decl)
          {
            tree arg = NULL_TREE;
 
-           if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
-             {
-               levels = TREE_VEC_LENGTH (args);
-               if (level <= levels)
-                 arg = TREE_VEC_ELT
-                   (TREE_VEC_ELT (args, level - 1), idx);
-             }
-           else
-             {
-               levels = 1;
-               if (level == 1)
-                 arg = TREE_VEC_ELT (args, idx);
-             }
+           levels = TMPL_ARGS_DEPTH (args);
+           if (level <= levels)
+             arg = TMPL_ARG (args, level, idx);
 
            if (arg != NULL_TREE)
              {
@@ -4385,7 +4590,8 @@ tsubst (t, args, in_decl)
 
                        r = lookup_template_class (DECL_NAME (arg), 
                                                   argvec, in_decl, 
-                                                  DECL_CONTEXT (arg));
+                                                  DECL_CONTEXT (arg),
+                                                  /*entering_scope=*/0);
                        return cp_build_type_variant (r, TYPE_READONLY (t),
                                                      TYPE_VOLATILE (t));
                      }
@@ -4453,8 +4659,21 @@ tsubst (t, args, in_decl)
 
        if (!is_template_template_parm)
          {
-           /* We might already have an instance of this template. */
-           spec = retrieve_specialization (t, args);
+           /* We might already have an instance of this template.
+              The ARGS are for the surrounding class type, so the
+              full args contain the tsubst'd args for the context,
+              plus the innermost args from the template decl.  */
+           tree tmpl_args = DECL_CLASS_TEMPLATE_P (t) 
+             ? CLASSTYPE_TI_ARGS (TREE_TYPE (t))
+             : DECL_TI_ARGS (DECL_RESULT (t));
+           tree full_args = tsubst (tmpl_args, args, in_decl);
+
+           /* tsubst_template_arg_vector doesn't copy the vector if
+              nothing changed.  But, *something* should have
+              changed.  */
+           my_friendly_assert (full_args != tmpl_args, 0);
+
+           spec = retrieve_specialization (t, full_args);
            if (spec != NULL_TREE)
              return spec;
          }
@@ -4477,10 +4696,12 @@ tsubst (t, args, in_decl)
            return tmpl;
          }
 
-       DECL_CONTEXT (tmpl) = tsubst (DECL_CONTEXT (t),
-                                     args, in_decl);
-       DECL_CLASS_CONTEXT (tmpl) = tsubst (DECL_CLASS_CONTEXT (t),
-                                           args, in_decl);
+       DECL_CONTEXT (tmpl) 
+         = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
+                             /*entering_scope=*/1);
+       DECL_CLASS_CONTEXT (tmpl) 
+         = tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, in_decl,
+                             /*entering_scope=*/1);
        DECL_TEMPLATE_INFO (tmpl) = build_tree_list (t, args);
 
        if (TREE_CODE (decl) == TYPE_DECL)
@@ -4489,6 +4710,7 @@ tsubst (t, args, in_decl)
            TREE_TYPE (tmpl) = new_type;
            CLASSTYPE_TI_TEMPLATE (new_type) = tmpl;
            DECL_RESULT (tmpl) = TYPE_MAIN_DECL (new_type);
+           DECL_TI_ARGS (tmpl) = CLASSTYPE_TI_ARGS (new_type);
          }
        else
          {
@@ -4496,44 +4718,18 @@ tsubst (t, args, in_decl)
            DECL_RESULT (tmpl) = new_decl;
            DECL_TI_TEMPLATE (new_decl) = tmpl;
            TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
+           DECL_TI_ARGS (tmpl) = DECL_TI_ARGS (new_decl);
          }
 
-       DECL_TEMPLATE_INSTANTIATIONS (tmpl) = NULL_TREE;
        SET_DECL_IMPLICIT_INSTANTIATION (tmpl);
+       DECL_TEMPLATE_INSTANTIATIONS (tmpl) = NULL_TREE;
+       DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = NULL_TREE;
 
        /* The template parameters for this new template are all the
           template parameters for the old template, except the
           outermost level of parameters. */
-       for (new_parms = &DECL_TEMPLATE_PARMS (tmpl),
-              parms = DECL_TEMPLATE_PARMS (t);
-            TREE_CHAIN (parms) != NULL_TREE;
-            new_parms = &(TREE_CHAIN (*new_parms)),
-              parms = TREE_CHAIN (parms))
-         {
-           tree new_vec = 
-             make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms)));
-           int i;
-
-           for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i)
-             {
-               tree default_value =
-                 TREE_PURPOSE (TREE_VEC_ELT (TREE_VALUE (parms), i));
-               tree parm_decl = 
-                 TREE_VALUE (TREE_VEC_ELT (TREE_VALUE (parms), i));
-                 
-               TREE_VEC_ELT (new_vec, i)
-                 = build_tree_list (tsubst (default_value, args, in_decl),
-                                    tsubst (parm_decl, args, in_decl));
-                 
-             }
-
-           *new_parms = 
-             tree_cons (build_int_2 (0, 
-                                     TREE_INT_CST_HIGH 
-                                     (TREE_PURPOSE (parms)) - 1),
-                        new_vec,
-                        NULL_TREE);
-         }
+       DECL_TEMPLATE_PARMS (tmpl) 
+         = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args);
 
        if (PRIMARY_TEMPLATE_P (t))
          DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
@@ -4542,12 +4738,6 @@ tsubst (t, args, in_decl)
        if (TREE_CODE (decl) == TYPE_DECL)
          return tmpl;
 
-       /* What should we do with the specializations of this member
-          template?  Are they specializations of this new template,
-          or instantiations of the templates they previously were?
-          this new template?  And where should their
-          DECL_TI_TEMPLATES point?  */ 
-       DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = NULL_TREE;
        for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
             spec != NULL_TREE;
             spec = TREE_CHAIN (spec))
@@ -4588,17 +4778,22 @@ tsubst (t, args, in_decl)
                 no concern to us.  */
              continue;
 
-           spec_args = tsubst (DECL_TI_ARGS (fn), args,
-                               in_decl); 
-           new_fn = tsubst (DECL_RESULT (fn), args,
-                            in_decl); 
-           DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = 
-             perm_tree_cons (spec_args, new_fn, 
-                             DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+           if (TREE_CODE (fn) != TEMPLATE_DECL)
+             /* A full specialization.  There's no need to record
+                that here.  */
+             continue;
+
+           spec_args = tsubst (DECL_TI_ARGS (fn), args, in_decl); 
+           new_fn = tsubst (DECL_RESULT (most_general_template (fn)), 
+                            spec_args, in_decl); 
+           DECL_TI_TEMPLATE (new_fn) = fn;
+           register_specialization (new_fn, tmpl, 
+                                    innermost_args (spec_args));
          }
 
        /* Record this partial instantiation.  */
-       register_specialization (tmpl, t, args);
+       register_specialization (tmpl, t, 
+                                DECL_TI_ARGS (DECL_RESULT (tmpl)));
 
        return tmpl;
       }
@@ -4608,16 +4803,53 @@ tsubst (t, args, in_decl)
        tree r = NULL_TREE;
        tree ctx;
        tree argvec;
-       tree tmpl = NULL_TREE;
+       tree gen_tmpl;
        int member;
 
+       /* Nobody should be tsubst'ing into non-template functions.  */
+       my_friendly_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE, 0);
+
+       if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
+         {
+           tree spec;
+
+           /* Calculate the most general template of which R is a
+              specialization, and the complete set of arguments used to
+              specialize R.  */
+           gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
+           argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
+
+           /* Check to see if we already have this specialization.  */
+           spec = retrieve_specialization (gen_tmpl, argvec);
+           if (spec)
+             return spec;
+         }
+       else
+         {
+           /* This special case arises when we have something like this:
+
+                template <class T> struct S { 
+                  friend void f<int>(int, double); 
+                };
+
+              Here, the DECL_TI_TEMPLATE for the friend declaration
+              will be a LOOKUP_EXPR.  We are being called from
+              tsubst_friend_function, and we want only to create a
+              new decl (R) with appropriate types so that we can call
+              determine_specialization.  */
+           my_friendly_assert (TREE_CODE (DECL_TI_TEMPLATE (t)) 
+                               == LOOKUP_EXPR, 0);
+           gen_tmpl = NULL_TREE;
+         }
+
        if (DECL_CLASS_SCOPE_P (t))
          {
            if (DECL_NAME (t) == constructor_name (DECL_CONTEXT (t)))
              member = 2;
            else
              member = 1;
-           ctx = tsubst (DECL_CLASS_CONTEXT (t), args, t);
+           ctx = tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, t,
+                                   /*entering_scope=*/1);
          }
        else
          {
@@ -4626,28 +4858,6 @@ tsubst (t, args, in_decl)
          }
        type = tsubst (type, args, in_decl);
 
-       /* If we are instantiating a specialization, get the other args.  */
-       if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
-         {
-           tree spec;
-
-           tmpl = DECL_TI_TEMPLATE (t);
-
-           /* Start by getting the innermost args.  */
-           if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
-             argvec = args;
-           else
-             argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
-
-           if (DECL_TEMPLATE_INFO (tmpl))
-             argvec = complete_template_args (tmpl, argvec, 0);
-
-           /* Do we already have this instantiation?  */
-           spec = retrieve_specialization (tmpl, argvec);
-           if (spec)
-             return spec;
-         }
-
        /* We do NOT check for matching decls pushed separately at this
            point, as they may not represent instantiations of this
            template, and in any case are considered separate under the
@@ -4659,7 +4869,7 @@ tsubst (t, args, in_decl)
        TREE_TYPE (r) = type;
 
        DECL_CONTEXT (r)
-         = tsubst (DECL_CONTEXT (t), args, t);
+         = tsubst_aggr_type (DECL_CONTEXT (t), args, t, /*entering_scope=*/1);
        DECL_CLASS_CONTEXT (r) = ctx;
 
        if (member && !strncmp (OPERATOR_TYPENAME_FORMAT,
@@ -4693,122 +4903,48 @@ tsubst (t, args, in_decl)
        if (IDENTIFIER_OPNAME_P (DECL_NAME (r)))
          grok_op_properties (r, DECL_VIRTUAL_P (r), DECL_FRIEND_P (r));
 
-       if (DECL_DESTRUCTOR_P (t))
-         DECL_ASSEMBLER_NAME (r) = build_destructor_name (ctx);
-       else 
+       /* Set up the DECL_TEMPLATE_INFO for R and compute its mangled
+          name.  There's no need to do this in the special friend
+          case mentioned above where GEN_TMPL is NULL.  */
+       if (gen_tmpl)
          {
-           /* Instantiations of template functions must be mangled
-              specially, in order to conform to 14.5.5.1
-              [temp.over.link].  We use in_decl below rather than
-              DECL_TI_TEMPLATE (r) because the latter is set to
-              NULL_TREE in instantiate_decl.  */
-           tree tmpl;
-           tree arg_types;
-
-           if (DECL_TEMPLATE_INFO (r))
-             tmpl = DECL_TI_TEMPLATE (r);
-           else
-             tmpl = in_decl;
-
-           /* tmpl will be NULL if this is a specialization of a
-              member function of a template class.  */
-           if (name_mangling_version < 1
-               || tmpl == NULL_TREE
-               || (member && !is_member_template (tmpl)
-                   && !DECL_TEMPLATE_INFO (tmpl)))
+           DECL_TEMPLATE_INFO (r) 
+             = perm_tree_cons (gen_tmpl, argvec, NULL_TREE);
+           SET_DECL_IMPLICIT_INSTANTIATION (r);
+           register_specialization (r, gen_tmpl, argvec);
+
+           /* Set the mangled name for R.  */
+           if (DECL_DESTRUCTOR_P (t))
+             DECL_ASSEMBLER_NAME (r) = build_destructor_name (ctx);
+           else 
              {
-               arg_types = TYPE_ARG_TYPES (type);
-               if (member && TREE_CODE (type) == FUNCTION_TYPE)
-                 arg_types = hash_tree_chain 
-                   (build_pointer_type (DECL_CONTEXT (r)),
-                    arg_types); 
+               /* Instantiations of template functions must be mangled
+                  specially, in order to conform to 14.5.5.1
+                  [temp.over.link].  */
+               tree tmpl = DECL_TI_TEMPLATE (t);
                
-               DECL_ASSEMBLER_NAME (r) 
-                 = build_decl_overload (DECL_NAME (r), arg_types,
-                                        member);
-             }
-           else
-             {
-               tree tparms; 
-               tree targs;
-
-               if (!DECL_TEMPLATE_SPECIALIZATION (tmpl)) 
-                 {
-                   /* We pass the outermost template parameters to
-                      build_template_decl_overload, since the innermost
-                      template parameters are still just template
-                      parameters; there are no corresponding subsitution
-                      arguments.  Levels of parms that have been bound
-                      before are not represented in DECL_TEMPLATE_PARMS.  */
-                   tparms = DECL_TEMPLATE_PARMS (tmpl);
-                   while (tparms && TREE_CHAIN (tparms) != NULL_TREE)
-                     tparms = TREE_CHAIN (tparms);
-                   
-                   targs = innermost_args (args, 0);
-                 }
+               /* TMPL will be NULL if this is a specialization of a
+                  member function of a template class.  */
+               if (name_mangling_version < 1
+                   || tmpl == NULL_TREE
+                   || (member && !is_member_template (tmpl)
+                       && !DECL_TEMPLATE_INFO (tmpl)))
+                 set_mangled_name_for_decl (r);
                else
-                 {
-                   /* If the template is a specialization, then it is
-                      a member template specialization.  We have
-                      something like:
-
-                      template <class T> struct S {
-                        template <int i> void f();
-                        template <> void f<7>();
-                      };
-
-                      and now we are forming S<double>::f<7>.
-                      Therefore, the template parameters of interest
-                      are those that are specialized by the template
-                      (i.e., the int), not those we are using to
-                      instantiate the template, i.e. the double.  */
-                   tparms = DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (tmpl));
-                   targs = DECL_TI_ARGS (tmpl);
-                 }
-                   
-               my_friendly_assert (tparms != NULL_TREE
-                                   && TREE_CODE (tparms) == TREE_LIST,
-                                   0);
-               tparms = TREE_VALUE (tparms);
-                
-               arg_types = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
-               if (member && TREE_CODE (type) == FUNCTION_TYPE)
-                 arg_types = hash_tree_chain 
-                   (build_pointer_type (DECL_CONTEXT (r)),
-                    arg_types); 
-
-               DECL_ASSEMBLER_NAME (r)
-                 = build_template_decl_overload 
-                 (r, arg_types, TREE_TYPE (TREE_TYPE (tmpl)),
-                  tparms, targs, member);
+                 set_mangled_name_for_template_decl (r);
              }
+           
+           DECL_RTL (r) = 0;
+           make_decl_rtl (r, NULL_PTR, 1);
+           
+           /* Like grokfndecl.  If we don't do this, pushdecl will
+              mess up our TREE_CHAIN because it doesn't find a
+              previous decl.  Sigh.  */
+           if (member
+               && (IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r)) 
+                   == NULL_TREE))
+             SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
          }
-       DECL_RTL (r) = 0;
-       make_decl_rtl (r, NULL_PTR, 1);
-
-       if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
-         {
-           DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
-
-           /* If we're not using ANSI overloading, then we might have
-              called duplicate_decls above, and gotten back an
-              preexisting version of this function.  We treat such a
-              function as a specialization.  Otherwise, we cleared
-              both TREE_STATIC and DECL_TEMPLATE_SPECIALIZATION, so
-              this condition will be false.  */
-           if (TREE_STATIC (r) || DECL_TEMPLATE_SPECIALIZATION (r))
-             SET_DECL_TEMPLATE_SPECIALIZATION (r);
-           else
-             SET_DECL_IMPLICIT_INSTANTIATION (r);
-
-           register_specialization (r, tmpl, argvec);
-         }
-
-       /* Like grokfndecl.  If we don't do this, pushdecl will mess up our
-          TREE_CHAIN because it doesn't find a previous decl.  Sigh.  */
-       if (member
-           && IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r)) == NULL_TREE)
-         SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
 
        return r;
       }
@@ -4861,18 +4997,25 @@ tsubst (t, args, in_decl)
     case VAR_DECL:
       {
        tree r;
-       tree ctx = tsubst_copy (DECL_CONTEXT (t), args, in_decl);
-
-       /* Do we already have this instantiation?  */
-       if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
-         {
-           tree tmpl = DECL_TI_TEMPLATE (t);
-           tree decls = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
+       tree argvec;
+       tree gen_tmpl;
+       tree spec;
+       tree tmpl;
+       tree ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
+                                    /*entering_scope=*/1);
+       
+       /* Nobody should be tsubst'ing into non-template variables.  */
+       my_friendly_assert (DECL_LANG_SPECIFIC (t) 
+                           && DECL_TEMPLATE_INFO (t) != NULL_TREE, 0);
 
-           for (; decls; decls = TREE_CHAIN (decls))
-             if (DECL_CONTEXT (TREE_VALUE (decls)) == ctx)
-               return TREE_VALUE (decls);
-         }
+       /* Check to see if we already have this specialization.  */
+       tmpl = DECL_TI_TEMPLATE (t);
+       gen_tmpl = most_general_template (tmpl);
+       argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
+       spec = retrieve_specialization (gen_tmpl, argvec);
+       
+       if (spec)
+         return spec;
 
        r = copy_node (t);
        TREE_TYPE (r) = type;
@@ -4884,26 +5027,15 @@ tsubst (t, args, in_decl)
        /* Don't try to expand the initializer until someone tries to use
           this variable; otherwise we run into circular dependencies.  */
        DECL_INITIAL (r) = NULL_TREE;
-
        DECL_RTL (r) = 0;
        DECL_SIZE (r) = 0;
+       copy_lang_decl (r);
+       DECL_CLASS_CONTEXT (r) = DECL_CONTEXT (r);
 
-       if (DECL_LANG_SPECIFIC (r))
-         {
-           copy_lang_decl (r);
-           DECL_CLASS_CONTEXT (r) = DECL_CONTEXT (r);
-         }
-
-       if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
-         {
-           tree tmpl = DECL_TI_TEMPLATE (t);
-           tree *declsp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
-           tree argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
+       DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
+       SET_DECL_IMPLICIT_INSTANTIATION (r);
+       register_specialization (r, gen_tmpl, argvec);
 
-           DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
-           *declsp = perm_tree_cons (argvec, r, *declsp);
-           SET_DECL_IMPLICIT_INSTANTIATION (r);
-         }
        TREE_CHAIN (r) = NULL_TREE;
        if (TREE_CODE (type) == VOID_TYPE)
          cp_error_at ("instantiation of `%D' as type void", r);
@@ -5136,7 +5268,8 @@ tsubst (t, args, in_decl)
 
     case TYPENAME_TYPE:
       {
-       tree ctx = tsubst (TYPE_CONTEXT (t), args, in_decl);
+       tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, in_decl,
+                                    /*entering_scope=*/1);
        tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args, in_decl);
        f = make_typename_type (ctx, f);
        return cp_build_type_variant
@@ -5234,7 +5367,8 @@ tsubst_copy (t, args, in_decl)
          if (TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL)
            return lookup_name (DECL_NAME (t), 0);
 
-         ctx = tsubst (DECL_CONTEXT (t), args, in_decl);
+         ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
+                                 /*entering_scope=*/1);
          if (ctx != DECL_CONTEXT (t))
            return lookup_field (ctx, DECL_NAME (t), 0, 0);
        }
@@ -5709,58 +5843,77 @@ tsubst_expr (t, args, in_decl)
   return NULL_TREE;
 }
 
+/* Instantiate the indicated variable of function template TMPL with
+   the template arguments in TARG_PTR.  */
+
 tree
 instantiate_template (tmpl, targ_ptr)
      tree tmpl, targ_ptr;
 {
   tree fndecl;
+  tree gen_tmpl;
+  tree spec;
   int i, len;
   struct obstack *old_fmp_obstack;
   extern struct obstack *function_maybepermanent_obstack;
+  tree inner_args;
 
   if (tmpl == error_mark_node)
     return error_mark_node;
 
   my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283);
 
-  /* Check to see if we already have this specialization.  This does work
-     for member template specializations; the list is set up from the
-     tsubst TEMPLATE_DECL case when the containing class is instantiated.  */
-  if (DECL_FUNCTION_TEMPLATE_P (tmpl))
+  /* Check to see if we already have this specialization.  */
+  spec = retrieve_specialization (tmpl, targ_ptr);
+  if (spec != NULL_TREE)
+    return spec;
+
+  if (DECL_TEMPLATE_INFO (tmpl))
     {
-      tree spec = retrieve_specialization (tmpl, targ_ptr);
-      
+      /* The TMPL is a partial instantiation.  To get a full set of
+        arguments we must add the arguments used to perform the
+        partial instantiation.  */
+      targ_ptr = add_outermost_template_args (DECL_TI_ARGS (tmpl),
+                                             targ_ptr);
+      gen_tmpl = most_general_template (tmpl);
+
+      /* Check to see if we already have this specialization.  */
+      spec = retrieve_specialization (gen_tmpl, targ_ptr);
       if (spec != NULL_TREE)
        return spec;
     }
+  else
+    gen_tmpl = tmpl;
 
   push_obstacks (&permanent_obstack, &permanent_obstack);
   old_fmp_obstack = function_maybepermanent_obstack;
   function_maybepermanent_obstack = &permanent_obstack;
 
-  len = DECL_NTPARMS (tmpl);
-
+  len = DECL_NTPARMS (gen_tmpl);
+  inner_args = innermost_args (targ_ptr);
   i = len;
   while (i--)
     {
-      tree t = TREE_VEC_ELT (targ_ptr, i);
+      tree t = TREE_VEC_ELT (inner_args, i);
       if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
        {
          tree nt = target_type (t);
          if (IS_AGGR_TYPE (nt) && decl_function_context (TYPE_MAIN_DECL (nt)))
            {
              cp_error ("type `%T' composed from a local class is not a valid template-argument", t);
-             cp_error ("  trying to instantiate `%D'", tmpl);
+             cp_error ("  trying to instantiate `%D'", gen_tmpl);
              fndecl = error_mark_node;
              goto out;
            }
        }
-      TREE_VEC_ELT (targ_ptr, i) = copy_to_permanent (t);
     }
   targ_ptr = copy_to_permanent (targ_ptr);
 
   /* substitute template parameters */
-  fndecl = tsubst (DECL_RESULT (tmpl), targ_ptr, tmpl);
+  fndecl = tsubst (DECL_RESULT (gen_tmpl), targ_ptr, gen_tmpl);
+  /* The DECL_TI_TEMPLATE should always be the immediate parent
+     template, not the most general template.  */
+  DECL_TI_TEMPLATE (fndecl) = tmpl;
 
   if (flag_external_templates)
     add_pending_template (fndecl);
@@ -6682,15 +6835,11 @@ more_specialized (pat1, pat2, explicit_args)
 
   targs = get_bindings_overload (pat1, pat2, explicit_args);
   if (targs)
-    {
-      --winner;
-    }
+    --winner;
 
   targs = get_bindings_overload (pat2, pat1, explicit_args);
   if (targs)
-    {
-      ++winner;
-    }
+    ++winner;
 
   return winner;
 }
@@ -6708,15 +6857,13 @@ more_specialized_class (pat1, pat2)
   tree targs;
   int winner = 0;
 
-  targs = get_class_bindings
-    (TREE_VALUE (pat1), TREE_PURPOSE (pat1),
-     TREE_PURPOSE (pat2), NULL_TREE);
+  targs = get_class_bindings (TREE_VALUE (pat1), TREE_PURPOSE (pat1),
+                             TREE_PURPOSE (pat2));
   if (targs)
     --winner;
 
-  targs = get_class_bindings
-    (TREE_VALUE (pat2), TREE_PURPOSE (pat2),
-     TREE_PURPOSE (pat1), NULL_TREE);
+  targs = get_class_bindings (TREE_VALUE (pat2), TREE_PURPOSE (pat2),
+                             TREE_PURPOSE (pat1));
   if (targs)
     ++winner;
 
@@ -6771,8 +6918,7 @@ get_bindings_real (fn, decl, explicit_args, check_rettype)
   if (check_rettype)
     {
       /* Check to see that the resulting return type is also OK.  */
-      tree t = tsubst (TREE_TYPE (TREE_TYPE (fn)),
-                      complete_template_args (fn, targs, 1),
+      tree t = tsubst (TREE_TYPE (TREE_TYPE (fn)), targs,
                       NULL_TREE);
 
       if (!comptypes (t, TREE_TYPE (TREE_TYPE (decl)), 1))
@@ -6800,18 +6946,29 @@ get_bindings_overload (fn, decl, explicit_args)
   return get_bindings_real (fn, decl, explicit_args, 0);
 }
 
+/* Return the innermost template arguments that, when applied to a
+   template specialization whose innermost template parameters are
+   TPARMS, and whose specialization arguments are ARGS, yield the
+   ARGS.  
+
+   For example, suppose we have:
+
+     template <class T, class U> struct S {};
+     template <class T> struct S<T*, int> {};
+
+   Then, suppose we want to get `S<double*, int>'.  The TPARMS will be
+   {T}, the PARMS will be {T*, int} and the ARGS will be {double*,
+   int}.  The resulting vector will be {double}, indicating that `T'
+   is bound to `double'.  */
+
 static tree
-get_class_bindings (tparms, parms, args, outer_args)
-     tree tparms, parms, args, outer_args;
+get_class_bindings (tparms, parms, args)
+     tree tparms, parms, args;
 {
   int i, ntparms = TREE_VEC_LENGTH (tparms);
   tree vec = make_temp_vec (ntparms);
 
-  if (outer_args)
-    {
-      tparms = tsubst (tparms, outer_args, NULL_TREE);
-      parms = tsubst (parms, outer_args, NULL_TREE);
-    }
+  args = innermost_args (args);
 
   for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
     {
@@ -6841,27 +6998,25 @@ tree
 most_specialized (fns, decl, explicit_args)
      tree fns, decl, explicit_args;
 {
-  tree fn, champ, args, *p;
+  tree candidates = NULL_TREE;
+  tree fn, champ, args;
   int fate;
 
-  for (p = &fns; *p; )
+  for (fn = fns; fn; fn = TREE_CHAIN (fn))
     {
-      args = get_bindings (TREE_VALUE (*p), decl, explicit_args);
+      tree candidate = TREE_VALUE (fn);
+
+      args = get_bindings (candidate, decl, explicit_args);
       if (args)
-       {
-         p = &TREE_CHAIN (*p);
-       }
-      else
-       *p = TREE_CHAIN (*p);
+       candidates = scratch_tree_cons (NULL_TREE, candidate, 
+                                       candidates);
     }
 
-  if (! fns)
+  if (!candidates)
     return NULL_TREE;
 
-  fn = fns;
-  champ = TREE_VALUE (fn);
-  fn = TREE_CHAIN (fn);
-  for (; fn; fn = TREE_CHAIN (fn))
+  champ = TREE_VALUE (candidates);
+  for (fn = TREE_CHAIN (candidates); fn; fn = TREE_CHAIN (fn))
     {
       fate = more_specialized (champ, TREE_VALUE (fn), explicit_args);
       if (fate == 1)
@@ -6878,7 +7033,7 @@ most_specialized (fns, decl, explicit_args)
        }
     }
 
-  for (fn = fns; fn && TREE_VALUE (fn) != champ; fn = TREE_CHAIN (fn))
+  for (fn = candidates; fn && TREE_VALUE (fn) != champ; fn = TREE_CHAIN (fn))
     {
       fate = more_specialized (champ, TREE_VALUE (fn), explicit_args);
       if (fate != 1)
@@ -6888,21 +7043,50 @@ most_specialized (fns, decl, explicit_args)
   return champ;
 }
 
-/* Return the most specialized of the class template specializations in
-   SPECS that can produce an instantiation matching ARGS.  */
+/* If DECL is a specialization of some template, return the most
+   general such template.  For example, given:
+
+     template <class T> struct S { template <class U> void f(U); };
+
+   if TMPL is `template <class U> void S<int>::f(U)' this will return
+   the full template.  This function will not trace past partial
+   specializations, however.  For example, given in addition:
+
+     template <class T> struct S<T*> { template <class U> void f(U); };
+
+   if TMPL is `template <class U> void S<int*>::f(U)' this will return
+   `template <class T> template <class U> S<T*>::f(U)'.  */
 
 tree
-most_specialized_class (specs, mainargs, outer_args)
-     tree specs, mainargs, outer_args;
+most_general_template (decl)
+     tree decl;
 {
-  tree list = NULL_TREE, t, args, champ;
+  while (DECL_TEMPLATE_INFO (decl))
+    decl = DECL_TI_TEMPLATE (decl);
+
+  return decl;
+}
+
+/* Return the most specialized of the class template specializations
+   of TMPL which can produce an instantiation matching ARGS, or
+   error_mark_node if the choice is ambiguous.  */
+
+tree
+most_specialized_class (tmpl, args)
+     tree tmpl;
+     tree args;
+{
+  tree list = NULL_TREE;
+  tree t;
+  tree champ;
   int fate;
 
-  for (t = specs; t; t = TREE_CHAIN (t))
+  tmpl = most_general_template (tmpl);
+  for (t = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); t; t = TREE_CHAIN (t))
     {
-      args = get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t),
-                                mainargs, outer_args);
-      if (args)
+      tree spec_args 
+       = get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t), args);
+      if (spec_args)
        {
          list = decl_tree_cons (TREE_PURPOSE (t), TREE_VALUE (t), list);
          TREE_TYPE (list) = TREE_TYPE (t);
@@ -7108,9 +7292,10 @@ do_type_instantiation (t, storage)
   }
 }
 
-/* Given a function DECL, which is a specialization of TEMP, modify
-   DECL to be a re-instantiation of TEMPL with the same template
-   arguments.
+/* Given a function DECL, which is a specialization of TMPL, modify
+   DECL to be a re-instantiation of TMPL with the same template
+   arguments.  TMPL should be the template into which tsubst'ing
+   should occur for DECL, not the most general template.
 
    One reason for doing this is a scenario like this:
 
@@ -7136,18 +7321,27 @@ regenerate_decl_from_template (decl, tmpl)
   tree save_ti;
   tree code_pattern;
   tree new_decl;
+  tree gen_tmpl;
+  int unregistered;
 
   args = DECL_TI_ARGS (decl);
   code_pattern = DECL_TEMPLATE_RESULT (tmpl);
 
-  /* Trick tsubst into giving us a new decl.  CODE_PATTERN must be the
-     most distant ancestor of DECL, since that's the one that will
-     actually be altered by a redefinition.  */
-  save_ti = DECL_TEMPLATE_INFO (code_pattern);
-  DECL_TEMPLATE_INFO (code_pattern) = NULL_TREE;
+  /* Unregister the specialization so that when we tsubst we will not
+     just return DECL.  We don't have to unregister DECL from TMPL
+     because if would only be registered there if it were a partial
+     instantiation of a specialization, which it isn't: it's a full
+     instantiation.  */
+  gen_tmpl = most_general_template (tmpl);
+  unregistered = unregister_specialization (decl, gen_tmpl);
+
+  /* If the DECL was not unregistered then something peculiar is
+     happening: we created a specialization but did not call
+     register_specialization for it.  */
+  my_friendly_assert (unregistered, 0);
+
+  /* Do the substitution to get the new declaration.  */
   new_decl = tsubst (code_pattern, args, NULL_TREE);
-  SET_DECL_IMPLICIT_INSTANTIATION (new_decl);
-  DECL_TEMPLATE_INFO (code_pattern) = save_ti;
 
   if (TREE_CODE (decl) == VAR_DECL)
     {
@@ -7160,21 +7354,29 @@ regenerate_decl_from_template (decl, tmpl)
     }
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
-        new decl.  */ 
-      DECL_INITIAL (new_decl) = error_mark_node;
-
-      if (DECL_TEMPLATE_SPECIALIZATION (new_decl) 
-         && !DECL_TEMPLATE_INFO (new_decl))
-       /* Set up the information about what is being specialized. */
-       DECL_TEMPLATE_INFO (new_decl) = DECL_TEMPLATE_INFO (decl);
-    }
-
+    /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
+       new decl.  */ 
+    DECL_INITIAL (new_decl) = error_mark_node;
+
+  /* The immediate parent of the new template is still whatever it was
+     before, even though tsubst sets DECL_TI_TEMPLATE up as the most
+     general template.  We also reset the DECL_ASSEMBLER_NAME since
+     tsubst always calculates the name as if the function in question
+     were really a template instance, and sometimes, with friend
+     functions, this is not so.  See tsubst_friend_function for
+     details.  */
+  DECL_TI_TEMPLATE (new_decl) = DECL_TI_TEMPLATE (decl);
+  DECL_ASSEMBLER_NAME (new_decl) = DECL_ASSEMBLER_NAME (decl);
+  DECL_RTL (new_decl) = DECL_RTL (decl);
+
+  /* Call duplicate decls to merge the old and new declarations.  */
   duplicate_decls (new_decl, decl);
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
     DECL_INITIAL (new_decl) = NULL_TREE;
+
+  /* Now, re-register the specialization.  */
+  register_specialization (decl, gen_tmpl, args);
 }
 
 /* Produce the definition of D, a _DECL generated from a template.  */
@@ -7183,17 +7385,41 @@ tree
 instantiate_decl (d)
      tree d;
 {
-  tree ti = DECL_TEMPLATE_INFO (d);
-  tree tmpl = TI_TEMPLATE (ti);
-  tree args = TI_ARGS (ti);
+  tree tmpl = DECL_TI_TEMPLATE (d);
+  tree args = DECL_TI_ARGS (d);
   tree td;
-  tree decl_pattern, code_pattern;
+  tree code_pattern;
+  tree spec;
+  tree gen_tmpl;
   int nested = in_function_p ();
-  int d_defined;
   int pattern_defined;
   int line = lineno;
   char *file = input_filename;
 
+  /* This function should only be used to instantiate templates for
+     functions and static member variables.  */
+  my_friendly_assert (TREE_CODE (d) == FUNCTION_DECL
+                     || TREE_CODE (d) == VAR_DECL, 0);
+
+  if ((TREE_CODE (d) == FUNCTION_DECL && DECL_INITIAL (d))
+      || (TREE_CODE (d) == VAR_DECL && !DECL_IN_AGGR_P (d)))
+    /* D has already been instantiated.  */
+    return d;
+
+  /* If we already have a specialization of this declaration, then
+     there's no reason to instantiate it.  Note that
+     retrieve_specialization gives us both instantiations and
+     specializations, so we must explicitly check
+     DECL_TEMPLATE_SPECIALIZATION.  */
+  gen_tmpl = most_general_template (tmpl);
+  spec = retrieve_specialization (gen_tmpl, args);
+  if (spec != NULL_TREE && DECL_TEMPLATE_SPECIALIZATION (spec))
+    return spec;
+
+  /* This needs to happen before any tsubsting.  */
+  if (! push_tinst_level (d))
+    return d;
+
   for (td = tmpl; 
        DECL_TEMPLATE_INSTANTIATION (td) 
         /* This next clause handles friend templates defined inside
@@ -7205,38 +7431,12 @@ instantiate_decl (d)
        )
     td = DECL_TI_TEMPLATE (td);
 
-  /* In the case of a member template, decl_pattern is the partially
-     instantiated declaration (in the instantiated class), and code_pattern
-     is the original template definition.  */
-  decl_pattern = DECL_TEMPLATE_RESULT (tmpl);
   code_pattern = DECL_TEMPLATE_RESULT (td);
 
   if (TREE_CODE (d) == FUNCTION_DECL)
-    {
-      d_defined = (DECL_INITIAL (d) != NULL_TREE);
-      pattern_defined = (DECL_INITIAL (code_pattern) != NULL_TREE);
-    }
+    pattern_defined = (DECL_INITIAL (code_pattern) != NULL_TREE);
   else
-    {
-      d_defined = ! DECL_IN_AGGR_P (d);
-      pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
-    }
-
-  if (d_defined)
-    return d;
-
-  if (TREE_CODE (d) == FUNCTION_DECL) 
-    {
-      tree spec = retrieve_specialization (tmpl, args);
-      
-      if (spec != NULL_TREE 
-         && DECL_TEMPLATE_SPECIALIZATION (spec))
-       return spec;
-    }
-
-  /* This needs to happen before any tsubsting.  */
-  if (! push_tinst_level (d))
-    return d;
+    pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
 
   push_to_top_level ();
   lineno = DECL_SOURCE_LINE (d);
@@ -7481,3 +7681,148 @@ tsubst_enum (tag, args, field_chain)
 
   return newtag;
 }
+
+/* Set the DECL_ASSEMBLER_NAME for DECL, which is a FUNCTION_DECL that
+   is either an instantiation or specialization of a template
+   function.  */
+
+static void
+set_mangled_name_for_template_decl (decl)
+     tree decl;
+{
+  tree saved_namespace;
+  tree context;
+  tree fn_type;
+  tree ret_type;
+  tree parm_types;
+  tree tparms;
+  tree targs;
+  tree tmpl;
+  int parm_depth;
+
+  my_friendly_assert (TREE_CODE (decl) == FUNCTION_DECL, 0);
+  my_friendly_assert (DECL_TEMPLATE_INFO (decl) != NULL_TREE, 0);
+
+  /* The names of template functions must be mangled so as to indicate
+     what template is being specialized with what template arguments.
+     For example, each of the following three functions must get
+     different mangled names:
+
+       void f(int);                  
+       template <> void f<7>(int);
+       template <> void f<8>(int);  */
+
+  targs = DECL_TI_ARGS (decl);
+  if (uses_template_parms (targs))
+    /* This DECL is for a partial instantiation.  There's no need to
+       mangle the name of such an entity.  */
+    return;
+
+  tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
+  tparms = DECL_TEMPLATE_PARMS (tmpl);
+  parm_depth = TMPL_PARMS_DEPTH (tparms);
+
+  /* There should be as many levels of arguments as there are levels
+     of parameters.  */
+  my_friendly_assert (parm_depth == TMPL_ARGS_DEPTH (targs), 0);
+
+  /* We now compute the PARMS and RET_TYPE to give to
+     build_decl_overload_real.  The PARMS and RET_TYPE are the
+     parameter and return types of the template, after all but the
+     innermost template arguments have been substituted, not the
+     parameter and return types of the function DECL.  For example,
+     given:
+
+       template <class T> T f(T);
+
+     both PARMS and RET_TYPE should be `T' even if DECL is `int f(int)'.  
+     A more subtle example is:
+
+       template <class T> struct S { template <class U> void f(T, U); }
+
+     Here, if DECL is `void S<int>::f(int, double)', PARMS should be
+     {int, U}.  Thus, the args that we want to subsitute into the
+     return and parameter type for the function are those in TARGS,
+     with the innermost level omitted.  */
+  fn_type = TREE_TYPE (tmpl);
+  if (DECL_STATIC_FUNCTION_P (decl))
+      context = DECL_CLASS_CONTEXT (decl);
+
+  if (parm_depth == 1)
+    /* No substitution is necessary.  */
+    ;
+  else
+    {
+      int i;
+      tree partial_args;
+
+      /* Replace the innermost level of the TARGS with NULL_TREEs to
+        let tsubst know not to subsitute for those parameters.  */
+      partial_args = make_temp_vec (TREE_VEC_LENGTH (targs));
+      for (i = 1; i < TMPL_ARGS_DEPTH (targs); ++i)
+       SET_TMPL_ARGS_LEVEL (partial_args, i,
+                            TMPL_ARGS_LEVEL (targs, i));
+      SET_TMPL_ARGS_LEVEL (partial_args,
+                          TMPL_ARGS_DEPTH (targs),
+                          make_temp_vec (DECL_NTPARMS (tmpl)));
+
+      /* Now, do the (partial) substitution to figure out the
+        appropriate function type.  */
+      fn_type = tsubst (fn_type, partial_args, NULL_TREE);
+      if (DECL_STATIC_FUNCTION_P (decl))
+       context = tsubst (context, partial_args, NULL_TREE);
+
+      /* Substitute into the template parameters to obtain the real
+        innermost set of parameters.  This step is important if the
+        innermost set of template parameters contains value
+        parameters whose types depend on outer template parameters.  */
+      TREE_VEC_LENGTH (partial_args)--;
+      tparms = tsubst_template_parms (tparms, partial_args);
+    }
+
+  /* Now, get the innermost parameters and arguments, and figure out
+     the parameter and return types.  */
+  tparms = INNERMOST_TEMPLATE_PARMS (tparms);
+  targs = innermost_args (targs);
+  ret_type = TREE_TYPE (fn_type);
+  parm_types = TYPE_ARG_TYPES (fn_type);
+
+  /* For a static member function, we generate a fake `this' pointer,
+     for the purposes of mangling.  This indicates of which class the
+     function is a member.  Because of:
+
+       [class.static] 
+
+       There shall not be a static and a nonstatic member function
+       with the same name and the same parameter types
+
+     we don't have to worry that this will result in a clash with a
+     non-static member function.  */
+  if (DECL_STATIC_FUNCTION_P (decl))
+    parm_types = hash_tree_chain (build_pointer_type (context), parm_types);
+
+  /* There should be the same number of template parameters as
+     template arguments.  */
+  my_friendly_assert (TREE_VEC_LENGTH (tparms) == TREE_VEC_LENGTH (targs),
+                     0);
+
+  /* If the template is in a namespace, we need to put that into the
+     mangled name. Unfortunately, build_decl_overload_real does not
+     get the decl to mangle, so it relies on the current
+     namespace. Therefore, we set that here temporarily. */
+  my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd', 980702);
+  saved_namespace = current_namespace;
+  current_namespace = CP_DECL_CONTEXT (decl);  
+
+  /* Actually set the DCL_ASSEMBLER_NAME.  */
+  DECL_ASSEMBLER_NAME (decl)
+    = build_decl_overload_real (DECL_NAME (decl), parm_types, ret_type,
+                               tparms, targs, 
+                               DECL_FUNCTION_MEMBER_P (decl) 
+                               + DECL_CONSTRUCTOR_P (decl));
+
+  /* Restore the previously active namespace.  */
+  current_namespace = saved_namespace;
+}
+
+
index 50685129e08fdf4d63e5ea96bde2a368cd7a518e..a6d03e1a256bcf5d0fda8e815235d82282f25564 100644 (file)
@@ -1235,18 +1235,7 @@ begin_class_definition (t)
     push_template_decl (TYPE_STUB_DECL (t));
   pushclass (t, 0);
   TYPE_BEING_DEFINED (t) = 1;
-  if (IS_AGGR_TYPE (t) && CLASSTYPE_USE_TEMPLATE (t))
-    {
-      if (CLASSTYPE_IMPLICIT_INSTANTIATION (t)
-         && TYPE_SIZE (t) == NULL_TREE)
-       {
-         SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t);
-         if (processing_template_decl)
-           push_template_decl (TYPE_MAIN_DECL (t));
-       }
-      else if (CLASSTYPE_TEMPLATE_INSTANTIATION (t))
-       cp_error ("specialization after instantiation of `%T'", t);
-    }
+  maybe_process_partial_specialization (t);
   /* Reset the interface data, at the earliest possible
      moment, as it might have been set via a class foo;
      before.  */
@@ -1378,6 +1367,15 @@ finish_member_class_template (parms, types)
      tree parms;
      tree types;
 {
+  tree t;
+
+  /* If there are declared, but undefined, partial specializations
+     mixed in with the typespecs they will not yet have passed through
+     maybe_process_partial_specialization, so we do that here.  */
+  for (t = types; t != NULL_TREE; t = TREE_CHAIN (t))
+    if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_VALUE (t))))
+      maybe_process_partial_specialization (TREE_VALUE (t));
+
   note_list_got_semicolon (types);
   grok_x_components (types, NULL_TREE); 
   if (TYPE_CONTEXT (TREE_VALUE (types)) != current_class_type)
@@ -1391,3 +1389,37 @@ finish_member_class_template (parms, types)
      component_decls.  */
   return NULL_TREE;
 }
+
+/* Finish processsing a complete template declaration.  The PARMS are
+   the template parameters.  */
+
+void
+finish_template_decl (parms)
+     tree parms;
+{
+  if (parms)
+    end_template_decl ();
+  else
+    end_specialization ();
+}
+
+/* Finish processing a a template-id (which names a type) of the form
+   NAME < ARGS >.  Return the TYPE_DECL for the type named by the
+   template-id.  If ENTERING_SCOPE is non-zero we are about to enter
+   the scope of template-id indicated.  */
+
+tree
+finish_template_type (name, args, entering_scope)
+     tree name;
+     tree args;
+     int entering_scope;
+{
+  tree decl;
+
+  decl = lookup_template_class (name, args,
+                               NULL_TREE, NULL_TREE, entering_scope);
+  if (decl != error_mark_node)
+    decl = TYPE_STUB_DECL (decl);
+
+  return decl;
+}
index a1c1394d17b3c62a5fa9461eeefa4e139cca7f4f..0ae703b2d325b8c9b766d445adab1429ead509e6 100644 (file)
@@ -587,7 +587,10 @@ common_type (t1, t2)
       else if (binfo_or_else (t2, t1))
        return build_type_attribute_variant (t2, attributes);
       else
-       compiler_error ("common_type called with uncommon aggregate types");
+       {
+         compiler_error ("common_type called with uncommon aggregate types");
+         return error_mark_node;
+       }
 
     case METHOD_TYPE:
       if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
index 7b470678a78f8849372c54b66e6b3b3c489f44a5..b5e997cc6ee62fb7e3c431f0a23ed6fa2a4df48c 100644 (file)
@@ -1,5 +1,7 @@
 // Build don't link: 
 // GROUPS passed old-abort
+// Special g++ Options:
+
 const bool FALSE = 0;
 const bool TRUE = 1;
 class ListDProto {
@@ -41,8 +43,8 @@ public:
     enum Action { NORMAL, REMOVE_CURRENT };
     Vix first() const;
     void first(Vix& x) const;
-    void next(Vix& x) const;// ERROR - candidate for call
-    void next(Vix& x, Action a = NORMAL);// ERROR - list of candidates
+    void next(Vix& x) const;
+    void next(Vix& x, Action a = NORMAL);
     Vix last() const;
     void last(Vix& x) const;
     void prev(Vix& x) const;
index 2b5dece65c1bd545d72da8c1be9dc6ef465d7219..8990c4656774d6cbc5f3f04188e1419d8ddec679 100644 (file)
@@ -6,7 +6,7 @@ class Elvis
 } ;
 
 template<int a>
-class Elvis<0>// ERROR - .*
-{ // ERROR - 
+class Elvis<0>
+{ // ERROR - incorrect number of parameters
    int geta() { return a ; }
 } ;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash11.C b/gcc/testsuite/g++.old-deja/g++.pt/crash11.C
new file mode 100644 (file)
index 0000000..30c72a6
--- /dev/null
@@ -0,0 +1,13 @@
+// Build don't link:
+
+class A
+{
+      class A_impl;
+   public: 
+      A(){}
+};
+
+
+template <class j> class A::A_impl 
+{ // ERROR - does not declare a template
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash13.C b/gcc/testsuite/g++.old-deja/g++.pt/crash13.C
new file mode 100644 (file)
index 0000000..f3de38e
--- /dev/null
@@ -0,0 +1,6 @@
+// Build don't link:
+
+template <class T> struct A {};
+template <class T> struct A<T>;    // ERROR - does not specialize args
+template <class T> const struct A; // ERROR - parse error
+template <class T> template A<int>; // ERROR - .*
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash14.C b/gcc/testsuite/g++.old-deja/g++.pt/crash14.C
new file mode 100644 (file)
index 0000000..f698316
--- /dev/null
@@ -0,0 +1,5 @@
+// Build don't link:
+
+template <class T> struct A {};
+template <class T> struct A<T*>;
+A<int*> ai; // ERROR - incomplete type
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash8.C b/gcc/testsuite/g++.old-deja/g++.pt/crash8.C
new file mode 100644 (file)
index 0000000..2fd687a
--- /dev/null
@@ -0,0 +1,34 @@
+// Build don't link:
+
+template<class T>
+class TestClass1 {
+public:
+  TestClass1() { } 
+};
+
+template<class T>
+class TestClass2 {
+public:
+  TestClass2() { } 
+  T operator()(int) { }
+};
+
+template<class T>
+void doit(T x) {
+  TestClass1<T> q1;
+  q1 = TestClass1<T>();
+  TestClass2<T> q2;
+  q2 = TestClass2<T>();
+
+  TestClass1<T> p1;
+  p1 = TestClass1(); // ERROR - template used as expression
+
+  TestClass2<T> p2;
+  p2 = TestClass2(); // ERROR - template used as expression
+}
+
+main() {
+  double x;
+  doit(x);
+}
+
index c724f8c992f0e0f3e631ad8c5f2d070d6d5d4802..c89fe1dc1d2b7db9bdd1231e0170e936f7fec26e 100644 (file)
@@ -13,7 +13,7 @@ template <class T> class B
 template <class T> class C
 {
   template <class U>
-  friend class A<U>;
+  friend class A;
 
   static int i;
 };
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend22.C b/gcc/testsuite/g++.old-deja/g++.pt/friend22.C
new file mode 100644 (file)
index 0000000..ed459d7
--- /dev/null
@@ -0,0 +1,10 @@
+// Build don't link:
+
+template <class T = int>
+struct S
+{
+  template <class U>
+  friend class S;
+};
+
+template struct S<int>;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend23.C b/gcc/testsuite/g++.old-deja/g++.pt/friend23.C
new file mode 100644 (file)
index 0000000..efb24b1
--- /dev/null
@@ -0,0 +1,10 @@
+// Build don't link:
+
+template <class T = int> // ERROR - original definition
+struct S
+{
+  template <class U = int>
+  friend class S;
+};
+
+template struct S<int>; // ERROR - redefinition of default arg
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend24.C b/gcc/testsuite/g++.old-deja/g++.pt/friend24.C
new file mode 100644 (file)
index 0000000..d312b38
--- /dev/null
@@ -0,0 +1,18 @@
+// Build don't link:
+
+template <class T>
+struct S
+{
+  template <class U = T>
+  friend class S;
+
+  void f(T);
+};
+
+template struct S<int>;
+
+void g()
+{
+  S<> s;
+  s.f(3);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend25.C b/gcc/testsuite/g++.old-deja/g++.pt/friend25.C
new file mode 100644 (file)
index 0000000..f93e73b
--- /dev/null
@@ -0,0 +1,15 @@
+// Build don't link:
+
+template <class T> struct A;
+
+struct B
+{
+  template <class U>
+  friend class A<U>;  // ERROR - does not specialize any args
+};
+
+struct C
+{
+  template <class U>
+  friend class A<U*>; // ERROR - partial specialization
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend26.C b/gcc/testsuite/g++.old-deja/g++.pt/friend26.C
new file mode 100644 (file)
index 0000000..a426f8b
--- /dev/null
@@ -0,0 +1,6 @@
+// Build don't link:
+
+struct S
+{
+  friend void f<>(int); // ERROR - does not match any template
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend27.C b/gcc/testsuite/g++.old-deja/g++.pt/friend27.C
new file mode 100644 (file)
index 0000000..0f11a49
--- /dev/null
@@ -0,0 +1,7 @@
+// Build don't link:
+
+class S
+{
+  friend void f<>(int); // ERROR - does not match any template
+  int i;
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memclass13.C b/gcc/testsuite/g++.old-deja/g++.pt/memclass13.C
new file mode 100644 (file)
index 0000000..7eddc27
--- /dev/null
@@ -0,0 +1,16 @@
+// Build don't link:
+
+template <class X, class Y>
+struct Inner;
+
+template <class T>
+struct S
+{
+  template <class U>
+  struct Inner
+  {
+  };
+};
+
+
+S<double>::Inner<int> si;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memclass14.C b/gcc/testsuite/g++.old-deja/g++.pt/memclass14.C
new file mode 100644 (file)
index 0000000..ad1b2b4
--- /dev/null
@@ -0,0 +1,15 @@
+// Build don't link:
+
+template <class X, class Y>
+struct Inner;
+
+struct S
+{
+  template <class U>
+  struct Inner
+  {
+  };
+};
+
+
+S::Inner<int> si;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memclass15.C b/gcc/testsuite/g++.old-deja/g++.pt/memclass15.C
new file mode 100644 (file)
index 0000000..52f92bf
--- /dev/null
@@ -0,0 +1,27 @@
+// Build don't link:
+
+template <class T>
+struct S1
+{
+  template <class U>
+  struct S2 {};
+
+  template <class X, class Y, class Z>
+  void f(X, Y, Z)
+    {
+      S2<Z> s2z;
+    }
+
+  template <class X, class Z>
+  void g(X, Z)
+    {
+      S2<Z> s2z;
+    }
+};
+
+
+void h()
+{
+  S1<int> si;
+  si.g(3, 4);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C
new file mode 100644 (file)
index 0000000..e6f62cf
--- /dev/null
@@ -0,0 +1,25 @@
+extern "C" int strcmp(const char*, const char*);
+
+template <class T>
+struct S3
+{
+  template <class U>
+  static char* h(U);
+};
+
+template <class T>
+template <>
+char* S3<T>::h(int) { return __PRETTY_FUNCTION__; }
+
+template <>
+template <>
+char* S3<char>::h(int) { return __PRETTY_FUNCTION__; }
+
+int main()
+{
+  if (strcmp (S3<double>::h(7), 
+             "static char * S3<double>::h<int>(int)") == 0)
+    return 0;
+  else 
+    return 1;
+}
index 3a0fb5941f3bf902592b9e68682fdce4375c7447..fb841b96ea760ec3c1c5dfa3ea2441c6cdc3e15c 100644 (file)
@@ -12,7 +12,7 @@ class base
 
 // specialization
 template<class Key, class Value>
-class base<Key, Value, mymap<int, int > >      // ERROR - mymap<...> is not a template
-{                                              // ERROR - Bad class name
+class base<Key, Value, mymap<int, int > >      
+{                                              // ERROR - type/value mismatch
   
 };
index 4a8f05b08e32f368b0ff29681f344563eace88db..0b19d54723ea6e23fae2ccac4ce039182960b02e 100644 (file)
@@ -1,4 +1,5 @@
 // Build don't link:
+// Special g++ Options:
 
 template <class T>
 struct A
index 67ac939b58a84de6ed47cb00820261541e3a3661..6f9362fe8e79a5f620b48e3a1fff4f024d578588 100644 (file)
@@ -1,4 +1,5 @@
 // Build don't link:
+// Special g++ Options:
 
 template <class T>
 struct A
index 202dadf12b61571be38a1cb78d5e35b550a5cdb8..e967d143f371661faa0e07c680aff513e765e9e4 100644 (file)
@@ -1,4 +1,5 @@
 // Build don't link:
+// Special g++ Options:
 
 template <class T>
 struct A
index 4a8f05b08e32f368b0ff29681f344563eace88db..0b19d54723ea6e23fae2ccac4ce039182960b02e 100644 (file)
@@ -1,4 +1,5 @@
 // Build don't link:
+// Special g++ Options:
 
 template <class T>
 struct A
index b940f01237f73026eec878d01cb7bcbfab5a0614..5faa28087c8469049bc3f30574166d83ee086fd2 100644 (file)
@@ -7,7 +7,7 @@ void test<class BOX> (test_box *);   // ERROR - illegal code
 
 class test_square
     {
-    friend void test<class BOX> (test_box *);
+      friend void test<class BOX> (test_box *); // ERROR - does not match
     }
 
 
index eb69dfd0715329cc02f427db872a09701f790c6d..f41ead5313f41c448d122a91ba5e4e5015858a11 100644 (file)
@@ -1,5 +1,5 @@
 // Build don't link:
-// excess errors test - XFAIL *-*-*
+// excess errors test
 
 // Here we declare ::S
 typedef struct s1 *S;