]> gcc.gnu.org Git - gcc.git/commitdiff
decl.c (start_decl): Don't allow duplicate definitions of static data members.
authorMark Mitchell <mmitchell@usa.net>
Mon, 19 Jan 1998 22:41:40 +0000 (22:41 +0000)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 19 Jan 1998 22:41:40 +0000 (17:41 -0500)
* decl.c (start_decl): Don't allow duplicate definitions of static
data members.
* call.c (build_user_type_conversion_1): Handle user-defined
template conversion operators correctly.
* decl2.c (build_expr_from_tree): Issue an error message if the
object in a COMPONENT_REF is a TEMPLATE_DECL.
* typeck.c (incomplete_type_error): Handle TEMPLATE_TYPE_PARMs.
* class.c (is_local_class): New function.
* cp-tree.h (is_local_class): Declare it.
(last_tree): Likewise.
(begin_tree): Likewise.
(end_tree): Likewise.
(lookup_template_class): Change prototype.
* decl.c (cp_finish_decl): Check for NULL where necesary.
Consider FUNCTION_DECLS to declare objects with top-level binding,
when calling make_decl_rtl.
(grokdeclarator): Give members of local classes internal linkage.
(start_function): Remove declaration of last_tree.
(finish_function): Set flag_keep_inline_functions around call to
rest_of_compilation if we are processing a member function in a
local class.
(start_method): Call push_template_decl for member functions of
local classes in template functions.
* decl2.c (import_export_decl): Don't give external linkage to
instantiations of templates with internal linkage.
* parse.y (last_tree): Remove declaration.
(template_type): Pass extra parameter to lookup_template_class.
(self_template_type): Likewise.
(structsp): Move call to reset_specialization into left_curly.
(left_curly): Call reset_specialization, and begin_tree.
* pt.c (saved_trees): New variable.
(mangle_class_name_for_template): Change prototype.  Use
additional function context to name local classes in templates
correctly.
(classtype_mangled_name): Pass the context.
(push_template_decl): Handle local classes and templates, and
member functions for such classes.
(convert_nontype_parameter): Fix handling of pointer-to-member
constants.
(lookup_template_class): Handle local classes in templates.
(tsubst): Likewise.  Don't assume that template instantiations
have external linkage; pay attention to the template declaration.
(mark_decl_instantiated): Likewise.
(begin_tree): New function.
(end_tree): Likewise.
* decl.c (xref_basetypes): Don't call complete_type for basetypes
that involve template parameters; that can lead to infinite
recursion unnecessarily.
* pt.c (register_specialization): Do not register specializations
that aren't ready to be registered yet.
(check_explicit_specialization): Handle explicit specialization of
constructors and destructors.
(build_template_decl): New function.
(push_template_delc): Handle out-of-class specializations of
member templates.
        * pt.c (check_explicit_specialization): Set up the template
        information before registering the specialization.
        (coerce_template_parms): Fix thinko.
        (tsubst): Handle specializations of member templates correctly.
* class.c (finish_struct_methods): Remove calls to
check_explicit_specialization from here.
(finish_struct): And insert them here.
* cp-tree.h (perform_qualification_conversions): New function.
(perform_array_to_pointer_conversion): Likewise.
(begin_explicit_instantiation): Likewise.
(end_explicit_instantiation): Likewise.
(determine_specialization): Renamed from
determine_explicit_specialization.
(comp_template_parms): New function.
(processing_explicit_instantiation): New variable.
* cvt.c (perform_qualification_conversions): New function.
(perform_array_to_pointer_conversion): Likewise.
* decl.c (duplicate_decls): Don't consider template functions
alike unless they have the same parameters.  Refine handling of
instantiation/specialization mismatches.
(start_decl): Don't call pushdecl for template specializations,
since they don't affect overloading.
(start_function): Likewise
(grokfndecl): Call check_explicit_specialization a little later.
Don't call duplicate_decls for memberm template specializations.
(grokdeclarator): Don't update template_count for classes that are
themselves specializations.  Remove use of `2' as parameter to
grokfndecl since that value isn't used.
* lex.c (cons_up_default_function): Save and restore
processing_explicit_instantiation around calls to grokfield.
* parse.y (finish_member_template_decl): New function.
(component_decl_1): Use it.
(fn.def2): Likewise.
(template_arg_list_opt): New nonterminal.
(template_type): Use it.
(self_template_type): Likewise.
(template_id): Likewise.
(object_template_id): Likewise.
(notype_template_declarator): Likwise.
(begin_explicit_instantiation): Likewise.
(end_explicit_instantiation): Likewise.
(explicit_instantiation): Use them.
* pt.c (coerce_template_parms): Add parameters.
(processing_explicit_instantiation): New variable.
(convert_nontype_parameter): New function.
(determine_overloaded_function): Likewise.
(begin_explicit_instantiation): Likewise.
(end_explicit_instantiation): Likewise.
(retrieve_specialization): Likewise.
(register_specialization): Likewise.
(processing_explicit_specialization): Removed.
(determine_specialization): Handle specializations of member
functions of template class instantiations.
(check_explicit_specialization): Refine to conform to standard.
(comp_template_parms): New function.
(coerce_template_parms): Call convert_nontype_parameter.
(tsubst): Refine handling of member templates.  Use
register_specialization.
(instantiate_template): Use retrieve_specialization.
(do_decl_instantiation): Likewise.
(instantiate_decl): Likewise.
(type_unification): Improve handling of explict template
arguments.
* tree.c (mapcar): Return error_mark_node, rather than aborting,
on VAR_DECLS, FUNCTION_DECLS, and CONST_DECLS.
* typeck.c (build_unary_op): Call determine_specialization, rather
than determine_explicit_specialization.

From-SVN: r17426

14 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/lex.c
gcc/cp/parse.y
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/cp/typeck2.c

index e6e78f6fd33d49ac1566779e1d020d0875473b85..aa4b3cbbda50f603ca2f2efedeb278692d4d4c96 100644 (file)
@@ -1,3 +1,136 @@
+Mon Jan 19 22:40:03 1998  Mark Mitchell  <mmitchell@usa.net>
+
+       * decl.c (start_decl): Don't allow duplicate definitions of static
+       data members.
+
+       * call.c (build_user_type_conversion_1): Handle user-defined
+       template conversion operators correctly.
+
+       * decl2.c (build_expr_from_tree): Issue an error message if the
+       object in a COMPONENT_REF is a TEMPLATE_DECL.
+       
+       * typeck.c (incomplete_type_error): Handle TEMPLATE_TYPE_PARMs.
+       
+       * class.c (is_local_class): New function.
+       * cp-tree.h (is_local_class): Declare it.
+       (last_tree): Likewise.
+       (begin_tree): Likewise.
+       (end_tree): Likewise.
+       (lookup_template_class): Change prototype.
+       * decl.c (cp_finish_decl): Check for NULL where necesary.
+       Consider FUNCTION_DECLS to declare objects with top-level binding,
+       when calling make_decl_rtl.
+       (grokdeclarator): Give members of local classes internal linkage.
+       (start_function): Remove declaration of last_tree.
+       (finish_function): Set flag_keep_inline_functions around call to
+       rest_of_compilation if we are processing a member function in a
+       local class.
+       (start_method): Call push_template_decl for member functions of
+       local classes in template functions.
+       * decl2.c (import_export_decl): Don't give external linkage to
+       instantiations of templates with internal linkage.
+       * parse.y (last_tree): Remove declaration.
+       (template_type): Pass extra parameter to lookup_template_class.
+       (self_template_type): Likewise.
+       (structsp): Move call to reset_specialization into left_curly.
+       (left_curly): Call reset_specialization, and begin_tree.
+       * pt.c (saved_trees): New variable.
+       (mangle_class_name_for_template): Change prototype.  Use
+       additional function context to name local classes in templates
+       correctly. 
+       (classtype_mangled_name): Pass the context.
+       (push_template_decl): Handle local classes and templates, and
+       member functions for such classes.
+       (convert_nontype_parameter): Fix handling of pointer-to-member
+       constants. 
+       (lookup_template_class): Handle local classes in templates.
+       (tsubst): Likewise.  Don't assume that template instantiations
+       have external linkage; pay attention to the template declaration. 
+       (mark_decl_instantiated): Likewise.
+       (begin_tree): New function.
+       (end_tree): Likewise.
+       
+       * decl.c (xref_basetypes): Don't call complete_type for basetypes
+       that involve template parameters; that can lead to infinite
+       recursion unnecessarily.
+
+       * pt.c (register_specialization): Do not register specializations
+       that aren't ready to be registered yet.
+       (check_explicit_specialization): Handle explicit specialization of
+       constructors and destructors.
+       (build_template_decl): New function.
+       (push_template_delc): Handle out-of-class specializations of
+       member templates.
+       
+        * pt.c (check_explicit_specialization): Set up the template
+        information before registering the specialization.
+        (coerce_template_parms): Fix thinko.
+        (tsubst): Handle specializations of member templates correctly.
+
+       * class.c (finish_struct_methods): Remove calls to
+       check_explicit_specialization from here.
+       (finish_struct): And insert them here.
+       * cp-tree.h (perform_qualification_conversions): New function.
+       (perform_array_to_pointer_conversion): Likewise.
+       (begin_explicit_instantiation): Likewise.
+       (end_explicit_instantiation): Likewise.
+       (determine_specialization): Renamed from
+       determine_explicit_specialization. 
+       (comp_template_parms): New function.
+       (processing_explicit_instantiation): New variable.
+       * cvt.c (perform_qualification_conversions): New function.
+       (perform_array_to_pointer_conversion): Likewise.
+       * decl.c (duplicate_decls): Don't consider template functions
+       alike unless they have the same parameters.  Refine handling of
+       instantiation/specialization mismatches.
+       (start_decl): Don't call pushdecl for template specializations,
+       since they don't affect overloading.
+       (start_function): Likewise
+       (grokfndecl): Call check_explicit_specialization a little later.
+       Don't call duplicate_decls for memberm template specializations.
+       (grokdeclarator): Don't update template_count for classes that are
+       themselves specializations.  Remove use of `2' as parameter to
+       grokfndecl since that value isn't used.
+       * lex.c (cons_up_default_function): Save and restore
+       processing_explicit_instantiation around calls to grokfield.
+       * parse.y (finish_member_template_decl): New function.
+       (component_decl_1): Use it.
+       (fn.def2): Likewise.
+       (template_arg_list_opt): New nonterminal.       
+       (template_type): Use it.
+       (self_template_type): Likewise.
+       (template_id): Likewise.
+       (object_template_id): Likewise.
+       (notype_template_declarator): Likwise.
+       (begin_explicit_instantiation): Likewise.
+       (end_explicit_instantiation): Likewise.
+       (explicit_instantiation): Use them.
+       * pt.c (coerce_template_parms): Add parameters.
+       (processing_explicit_instantiation): New variable.
+       (convert_nontype_parameter): New function.
+       (determine_overloaded_function): Likewise.
+       (begin_explicit_instantiation): Likewise.
+       (end_explicit_instantiation): Likewise.
+       (retrieve_specialization): Likewise.
+       (register_specialization): Likewise.
+       (processing_explicit_specialization): Removed.
+       (determine_specialization): Handle specializations of member
+       functions of template class instantiations.
+       (check_explicit_specialization): Refine to conform to standard.
+       (comp_template_parms): New function.
+       (coerce_template_parms): Call convert_nontype_parameter.
+       (tsubst): Refine handling of member templates.  Use
+       register_specialization. 
+       (instantiate_template): Use retrieve_specialization.
+       (do_decl_instantiation): Likewise.
+       (instantiate_decl): Likewise.
+       (type_unification): Improve handling of explict template
+       arguments. 
+       * tree.c (mapcar): Return error_mark_node, rather than aborting,
+       on VAR_DECLS, FUNCTION_DECLS, and CONST_DECLS.
+       * typeck.c (build_unary_op): Call determine_specialization, rather
+       than determine_explicit_specialization.
+
 Mon Jan 19 13:18:51 1998  Jason Merrill  <jason@yorick.cygnus.com>
 
        * cvt.c (build_up_reference): A TARGET_EXPR has side effects.
index 848a821ee953511b26c24f9ab56c29ca25a0abb0..ca0e5b4d3e86296ab480e19e90952378649a7846 100644 (file)
@@ -4356,8 +4356,11 @@ build_user_type_conversion_1 (totype, expr, flags)
       if (TREE_CODE (totype) == REFERENCE_TYPE)
        convflags |= LOOKUP_NO_TEMP_BIND;
 
-      ics = implicit_conversion
-       (totype, TREE_TYPE (TREE_TYPE (fn)), 0, convflags);
+      if (TREE_CODE (fn) != TEMPLATE_DECL)
+       ics = implicit_conversion
+         (totype, TREE_TYPE (TREE_TYPE (fn)), 0, convflags);
+      else
+       ics = implicit_conversion (totype, totype, 0, convflags);
 
       if (TREE_CODE (totype) == REFERENCE_TYPE && ics && ICS_BAD_FLAG (ics))
        /* ignore the near match.  */;
index 87a0eeb06240cfcfa54f18ddd9204a6e7fe81a91..7dd43f076581208f077f7edc0e9efba0ef892cdb 100644 (file)
@@ -2107,53 +2107,6 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
        obstack_free (current_obstack, baselink_vec);
     }
 
-  /* Now, figure out what any member template specializations were
-     specializing.  */
-  for (i = 0; i < TREE_VEC_LENGTH (method_vec); ++i)
-    {
-      tree fn;
-      for (fn = TREE_VEC_ELT (method_vec, i);
-          fn != NULL_TREE;
-          fn = DECL_CHAIN (fn))
-       if (DECL_TEMPLATE_SPECIALIZATION (fn))
-         {
-           tree f;
-           tree spec_args;
-
-           /* If there is a template, and t uses template parms, we
-              are dealing with a specialization of a member
-              template in a template class, and we must grab the
-              template, rather than the function.  */
-           if (DECL_TI_TEMPLATE (fn) && uses_template_parms (t))
-             f = DECL_TI_TEMPLATE (fn);
-           else
-             f = fn;
-
-           /* We want the specialization arguments, which will be the
-              innermost ones.  */
-           if (DECL_TI_ARGS (f) 
-               && TREE_CODE (DECL_TI_ARGS (f)) == TREE_VEC)
-             spec_args 
-               = TREE_VEC_ELT (DECL_TI_ARGS (f), 0);
-           else
-             spec_args = DECL_TI_ARGS (f);
-               
-           check_explicit_specialization 
-             (lookup_template_function (DECL_NAME (f), spec_args),
-              f, 0, 1);
-
-           /* Now, the assembler name will be correct for fn, so we
-              make its RTL.  */
-           DECL_RTL (f) = 0;
-           make_decl_rtl (f, NULL_PTR, 1);
-           if (f != fn)
-             {
-               DECL_RTL (fn) = 0;
-               make_decl_rtl (fn, NULL_PTR, 1);
-             }
-         }
-    }
-
   return method_vec;
 }
 
@@ -4350,10 +4303,13 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
 {
   tree fields = NULL_TREE;
   tree *tail = &TYPE_METHODS (t);
+  tree specializations = NULL_TREE;
+  tree *specialization_tail = &specializations;
   tree name = TYPE_NAME (t);
   tree x, last_x = NULL_TREE;
   tree access;
   tree dummy = NULL_TREE;
+  tree next_x = NULL_TREE;
 
   if (TREE_CODE (name) == TYPE_DECL)
     {
@@ -4402,8 +4358,10 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
            access = access_private_node;
        }
 
-      for (x = TREE_VALUE (list_of_fieldlists); x; x = TREE_CHAIN (x))
+      for (x = TREE_VALUE (list_of_fieldlists); x; x = next_x)
        {
+         next_x = TREE_CHAIN (x);
+
          TREE_PRIVATE (x) = access == access_private_node;
          TREE_PROTECTED (x) = access == access_protected_node;
 
@@ -4441,8 +4399,23 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
              || DECL_FUNCTION_TEMPLATE_P (x))
            {
              DECL_CLASS_CONTEXT (x) = t;
+
              if (last_x)
-               TREE_CHAIN (last_x) = TREE_CHAIN (x);
+               TREE_CHAIN (last_x) = next_x;
+
+             if (DECL_TEMPLATE_SPECIALIZATION (x))
+               /* We don't enter the specialization into the class
+                  method vector since specializations don't affect
+                  overloading.  Instead we keep track of the
+                  specializations, and process them after the method
+                  vector is complete.  */
+               {
+                 *specialization_tail = x;
+                 specialization_tail = &TREE_CHAIN (x);
+                 TREE_CHAIN (x) = NULL_TREE;
+                 continue;
+               }
+
              /* Link x onto end of TYPE_METHODS.  */
              *tail = x;
              tail = &TREE_CHAIN (x);
@@ -4525,6 +4498,53 @@ finish_struct (t, list_of_fieldlists, attributes, warn_anon)
 
   TYPE_BEING_DEFINED (t) = 0;
 
+  /* Now, figure out what any member template specializations were
+     specializing.  */
+  for (x = specializations; x != NULL_TREE; x = TREE_CHAIN (x))
+    {
+      tree spec_args;
+      tree fn;
+
+      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);
+      
+      check_explicit_specialization 
+       (lookup_template_function (DECL_NAME (fn), spec_args),
+        fn, 0, 1 | (8 * (int) TREE_CHAIN (DECL_TEMPLATE_INFO (fn))));
+
+      TREE_CHAIN (DECL_TEMPLATE_INFO (fn)) = NULL_TREE;
+
+      /* 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);
+       }
+    }
+
   if (current_class_type)
     popclass (0);
   else
@@ -5484,3 +5504,21 @@ build_self_reference ()
   pushdecl_class_level (value);
   return value;
 }
+
+
+/* Returns non-zero iff the TYPE is a local class; i.e., if it is
+   declared in a function context, or within a local class.  */
+
+int
+is_local_class (type)
+     tree type;
+{
+  if (type == NULL_TREE || TYPE_CONTEXT (type) == NULL_TREE)
+    return 0;
+
+  if (TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL)
+    return 1;
+
+  return is_local_class (TYPE_CONTEXT (type));
+}
+
index e7856f00a77ea08dc6d1eddc70b1f876e377eec2..73b185d331f579e2fd3ee1023e37c6e2dd7358ee 100644 (file)
@@ -1539,6 +1539,7 @@ extern tree null_node;
 
 extern tree current_template_parms;
 extern HOST_WIDE_INT processing_template_decl;
+extern tree last_tree;
 
 /* The template currently being instantiated, and where the instantiation
    was triggered.  */
@@ -1983,6 +1984,7 @@ extern void maybe_push_cache_obstack              PROTO((void));
 extern unsigned HOST_WIDE_INT skip_rtti_stuff  PROTO((tree *));
 extern tree build_self_reference               PROTO((void));
 extern void warn_hidden                                PROTO((tree));
+extern int is_local_class                       PROTO((tree));
 
 /* in cvt.c */
 extern tree convert_to_reference               PROTO((tree, tree, int, int, tree));
@@ -1998,6 +2000,8 @@ extern tree build_type_conversion         PROTO((enum tree_code, tree, tree, int));
 extern tree build_expr_type_conversion         PROTO((int, tree, int));
 extern int build_default_binary_type_conversion        PROTO((enum tree_code, tree *, tree *));
 extern tree type_promotes_to                   PROTO((tree));
+extern tree perform_qualification_conversions   PROTO((tree, tree));
+extern tree perform_array_to_pointer_conversion PROTO((tree));
 
 /* decl.c */
 /* resume_binding_level */
@@ -2317,14 +2321,16 @@ extern void begin_template_parm_list            PROTO((void));
 extern void begin_specialization                PROTO((void));
 extern void reset_specialization                PROTO((void));
 extern void end_specialization                  PROTO((void));
-extern tree determine_explicit_specialization   PROTO((tree, tree, tree *, int, int));
-extern int check_explicit_specialization       PROTO((tree, tree, int, int));
+extern void begin_explicit_instantiation        PROTO((void));
+extern void end_explicit_instantiation          PROTO((void));
+extern tree determine_specialization            PROTO((tree, tree, tree *, int, int));
+extern int check_explicit_specialization        PROTO((tree, tree, int, int));
 extern tree process_template_parm              PROTO((tree, tree));
 extern tree end_template_parm_list             PROTO((tree));
 extern void end_template_decl                  PROTO((void));
 extern tree current_template_args              PROTO((void));
 extern void push_template_decl                 PROTO((tree));
-extern tree lookup_template_class              PROTO((tree, tree, tree));
+extern tree lookup_template_class              PROTO((tree, tree, tree, tree));
 extern tree lookup_template_function            PROTO((tree, tree));
 extern int uses_template_parms                 PROTO((tree));
 extern tree instantiate_class_template         PROTO((tree));
@@ -2344,6 +2350,8 @@ extern tree do_poplevel                           PROTO((void));
 extern tree get_bindings                       PROTO((tree, tree));
 /* CONT ... */
 extern void add_tree                           PROTO((tree));
+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));
@@ -2351,7 +2359,9 @@ extern tree most_specialized_class                PROTO((tree, tree));
 extern int more_specialized_class              PROTO((tree, tree));
 extern void do_pushlevel                       PROTO((void));
 extern int is_member_template                   PROTO((tree));
+extern int comp_template_parms                  PROTO((tree, tree));
 extern int processing_specialization;
+extern int processing_explicit_instantiation;
 
 /* in repo.c */
 extern void repo_template_used                 PROTO((tree));
index 687ac5cf4828c98223ef5a4cafdae381ec3ad59d..341b83a46ac77f6337c90e4fa08040605ab61c5d 100644 (file)
@@ -1682,3 +1682,134 @@ type_promotes_to (type)
 
   return cp_build_type_variant (type, constp, volatilep);
 }
+
+
+/* The routines below this point are carefully written to conform to
+   the standard.  They use the same terminology, and follow the rules
+   closely.  Although they are used only in pt.c at the moment, they
+   should presumably be used everywhere in the future.  */
+
+tree 
+perform_qualification_conversions (type, expr)
+     tree type;
+     tree expr;
+{
+  tree expr_type = TREE_TYPE (expr);
+  tree t1;
+  tree t2;
+  int j;
+  int all_have_const = 1;
+
+  if (comptypes (type, expr_type, 1))
+    /* The two types are already the same, so there is nothing to do.  */
+    return expr;
+
+  j = 0;
+  t1 = expr_type;
+  t2 = type; 
+
+  while (1)
+    {
+      if (TREE_CODE (type) != TREE_CODE (expr_type))
+       return error_mark_node;
+
+      if (j > 0 
+         && TREE_CODE (type) == POINTER_TYPE)
+       {
+         if (TYPE_READONLY (t1) > TYPE_READONLY (t2)
+             || TYPE_VOLATILE (t1) > TYPE_VOLATILE (t2))
+           /* For every j>0, if const is in cv1,j the const is in
+              cv2,j, and similarly for volatile.  */
+           return error_mark_node;
+       }
+
+      if (!all_have_const 
+         && (TYPE_READONLY (t1) != TYPE_READONLY (t2)
+             || TYPE_READONLY (t1) != TYPE_READONLY (t2)))
+       /* If the cv1,j and cv2,j are different, then const is in every
+          cv2,k for 0<k<j.  */
+       return error_mark_node;
+       
+      if (j > 0 && !TYPE_READONLY (t2))
+       all_have_const = 0;
+
+      if (TREE_CODE (type) != POINTER_TYPE)
+       {
+         if (j == 0)
+           /* The two things to be converted weren't even pointer
+              types.  */
+           return error_mark_node;
+         
+         if (TYPE_PTRMEMFUNC_P (type))
+           {
+             t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+             t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+           }
+
+         if (comptypes (TYPE_MAIN_VARIANT (t1),
+                        TYPE_MAIN_VARIANT (t2), 1))
+           return build1 (NOP_EXPR, type, expr);
+         else
+           /* The pointers were not similar.  */
+           return error_mark_node;
+       }
+
+      if (TYPE_PTRMEM_P (type) 
+         && !comptypes (TYPE_OFFSET_BASETYPE (TREE_TYPE (t1)),
+                        TYPE_OFFSET_BASETYPE (TREE_TYPE (t2)),
+                        1))
+       /* One type is X::* and the other is Y::*.  */
+       return error_mark_node;
+
+      if (TYPE_PTRMEM_P (type))
+       {
+         t1 = TREE_TYPE (TREE_TYPE (t1));
+         t2 = TREE_TYPE (TREE_TYPE (t2));
+       }
+      else
+       {
+         t1 = TREE_TYPE (t1);
+         t2 = TREE_TYPE (t2);
+       }
+    }
+}
+
+
+/* Perform array-to-pointer conversion on EXPR, if appropriate.
+   Return the converted expression, or EXPR if no
+   conversion was performed, or error_mark_node if the conversion was
+   attempted, but failed.  (For example, if an attempt is made to take
+   the address of a non-addressable object.)  */
+
+tree 
+perform_array_to_pointer_conversion (expr)
+     tree expr;
+{
+  tree result = expr;
+
+  if (TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE)
+    {
+      tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (expr)));
+      
+      /* This section is copied from decay_conversion.  */
+      if (TREE_CODE (expr) == VAR_DECL)
+       {
+         /* ??? This is not really quite correct
+            in that the type of the operand of ADDR_EXPR
+            is not the target type of the type of the ADDR_EXPR itself.
+            Question is, can this lossage be avoided?  */
+         result = build1 (ADDR_EXPR, type, expr);
+         if (mark_addressable (expr) == 0)
+           return error_mark_node;
+         TREE_CONSTANT (result) = staticp (expr);
+         TREE_SIDE_EFFECTS (result) = 0; /* Default would be, same as
+                                            EXPR.  */ 
+       }
+      else 
+       /* This way is better for a COMPONENT_REF since it can
+          simplify the offset for a component.  */
+       result = build_unary_op (ADDR_EXPR, expr, 1);
+    }
+
+  return result;
+}
index 8ffcc9d453de27320a19a6aa6d772a03843623a6..7bdc60706e91c0e3709b3cadbeda4d38b9948a5d 100644 (file)
@@ -2529,7 +2529,9 @@ duplicate_decls (newdecl, olddecl)
          else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
                   && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
                   && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))),
-                                TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))), 3))
+                                TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))), 3)
+                  && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
+                                          DECL_TEMPLATE_PARMS (olddecl)))
            {
              cp_error ("new declaration `%#D'", newdecl);
              cp_error_at ("ambiguates old declaration `%#D'", olddecl);
@@ -2563,19 +2565,31 @@ duplicate_decls (newdecl, olddecl)
          cp_error_at ("previous declaration as `%#D'", olddecl);
        }
     }
-  else if ((TREE_CODE (olddecl) == FUNCTION_DECL 
-           && DECL_TEMPLATE_SPECIALIZATION (olddecl)
-           && (!DECL_TEMPLATE_SPECIALIZATION (newdecl)
-               || (DECL_TI_TEMPLATE (newdecl) 
-                   != DECL_TI_TEMPLATE (olddecl))))
-          || (TREE_CODE (newdecl) == FUNCTION_DECL
-              && DECL_TEMPLATE_SPECIALIZATION (newdecl)
-              && (!DECL_TEMPLATE_SPECIALIZATION (olddecl)
-                  || (DECL_TI_TEMPLATE (olddecl) != DECL_TI_TEMPLATE
-                      (newdecl)))))
+  else if (TREE_CODE (newdecl) == FUNCTION_DECL 
+           && ((DECL_TEMPLATE_SPECIALIZATION (olddecl)
+                && (!DECL_TEMPLATE_INFO (newdecl)
+                    || (DECL_TI_TEMPLATE (newdecl) 
+                        != DECL_TI_TEMPLATE (olddecl))))
+               || (DECL_TEMPLATE_SPECIALIZATION (newdecl)
+                   && (!DECL_TEMPLATE_INFO (olddecl)
+                       || (DECL_TI_TEMPLATE (olddecl) 
+                           != DECL_TI_TEMPLATE (newdecl))))))
     /* It's OK to have a template specialization and a non-template
        with the same type, or to have specializations of two
-       different templates with the same type. */
+       different templates with the same type.  Note that if one is a
+       specialization, and the other is an instantiation of the same
+       template, that we do not exit at this point.  That situation
+       can occur if we instantiate a template class, and then
+       specialize one of its methods.  This situation is legal, but
+       the declarations must be merged in the usual way.  */
+    return 0;
+  else if (TREE_CODE (newdecl) == FUNCTION_DECL 
+          && ((DECL_TEMPLATE_INSTANTIATION (olddecl) 
+               && !DECL_USE_TEMPLATE (newdecl))
+              || (DECL_TEMPLATE_INSTANTIATION (newdecl)
+                  && !DECL_USE_TEMPLATE (olddecl))))
+    /* One of the declarations is a template instantiation, and the
+       other is not a template at all.  That's OK.  */
     return 0;
   else
     {
@@ -2860,9 +2874,29 @@ duplicate_decls (newdecl, olddecl)
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
-      if (DECL_TEMPLATE_INSTANTIATION (olddecl) &&
-         !DECL_TEMPLATE_INSTANTIATION (newdecl)) 
-       DECL_USE_TEMPLATE (olddecl) = DECL_USE_TEMPLATE (newdecl);
+      if (DECL_TEMPLATE_INSTANTIATION (olddecl) 
+         && !DECL_TEMPLATE_INSTANTIATION (newdecl)) 
+       {
+         /* If newdecl is not a specialization, then it is not a
+            template-related function at all.  And that means that we
+            shoud have exited above, returning 0.  */
+         my_friendly_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl),
+                             0);
+
+         if (TREE_USED (olddecl)) 
+           /* From [temp.expl.spec]:
+              
+              If a template, a member template or the member of a class
+              template is explicitly specialized then that
+              specialization shall be declared before the first use of
+              that specialization that would cause an implicit
+              instantiation to take place, in every translation unit in
+              which such a use occurs.  */
+           cp_error ("explicit specialization of %D after first use", 
+                     olddecl);
+
+         SET_DECL_TEMPLATE_SPECIALIZATION (olddecl);
+       }
       DECL_THIS_INLINE (newdecl) |= DECL_THIS_INLINE (olddecl);
 
       /* If either decl says `inline', this fn is inline, unless its
@@ -2922,8 +2956,8 @@ duplicate_decls (newdecl, olddecl)
 
   if (TREE_CODE (newdecl) == TEMPLATE_DECL)
     {
-      DECL_TEMPLATE_INSTANTIATIONS (newdecl)
-       = DECL_TEMPLATE_INSTANTIATIONS (olddecl);
+      DECL_TEMPLATE_SPECIALIZATIONS (newdecl)
+       = DECL_TEMPLATE_SPECIALIZATIONS (olddecl);
       if (DECL_CHAIN (newdecl) == NULL_TREE)
        DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
     }
@@ -2965,6 +2999,38 @@ duplicate_decls (newdecl, olddecl)
 #define ROUND(x) ((x + obstack_alignment_mask (&permanent_obstack)) \
                  & ~ obstack_alignment_mask (&permanent_obstack))
 
+      if (DECL_TEMPLATE_INSTANTIATION (newdecl))
+       {
+         /* If newdecl is a template instantiation, it is possible that
+            the following sequence of events has occurred:
+
+            o A friend function was declared in a class template.  The
+            class template was instantiated.  
+
+            o The instantiation of the friend declaration was 
+            recorded on the instantiation list, and is newdecl.  
+
+            o Later, however, instantiate_class_template called pushdecl
+            on the newdecl to perform name injection.  But, pushdecl in
+            turn called duplicate_decls when it discovered that another
+            declaration of a global function with the same name already
+            existed. 
+
+            o Here, in duplicate_decls, we decided to clobber newdecl.
+
+            If we're going to do that, we'd better make sure that
+            olddecl, and not newdecl, is on the list of
+            instantiations so that if we try to do the instantiation
+            again we won't get the clobbered declaration.  */
+
+         tree tmpl = DECL_TI_TEMPLATE (newdecl); 
+         tree decls = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); 
+
+         for (; decls; decls = TREE_CHAIN (decls))
+           if (TREE_VALUE (decls) == newdecl)
+             TREE_VALUE (decls) = olddecl;
+       }
+
       if ((char *)newdecl + ROUND (function_size)
          + ROUND (sizeof (struct lang_decl))
          == obstack_next_free (&permanent_obstack))
@@ -6024,6 +6090,13 @@ start_decl (declarator, declspecs, initialized)
                              context, DECL_NAME (decl));
                  DECL_CONTEXT (decl) = DECL_CONTEXT (field);
                }
+             /* Static data member are tricky; an in-class initialization
+                still doesn't provide a definition, so the in-class
+                declaration will have DECL_EXTERNAL set, but will have an
+                initialization.  Thus, duplicate_decls won't warn
+                about this situation, and so we check here.  */
+             if (DECL_INITIAL (decl) && DECL_INITIAL (field))
+               cp_error ("duplicate initialization of %D", decl);
              if (duplicate_decls (decl, field))
                decl = field;
            }
@@ -6056,7 +6129,13 @@ start_decl (declarator, declspecs, initialized)
   
   if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE)
       || (TREE_CODE (decl) == TEMPLATE_DECL && !global_bindings_p ())
-      || TREE_CODE (type) == LANG_TYPE)
+      || TREE_CODE (type) == LANG_TYPE
+      /* The declaration of template specializations does not affect
+        the functions available for overload resolution, so we do not
+        call pushdecl.  */
+      || (!flag_guiding_decls 
+         && TREE_CODE (decl) == FUNCTION_DECL
+         && DECL_TEMPLATE_SPECIALIZATION (decl)))
     tem = decl;
   else
     tem = pushdecl (decl);
@@ -6397,9 +6476,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
       if (minimal_parse_mode && ! DECL_ARTIFICIAL (decl))
        {
          tree stmt = DECL_VINDEX (decl);
-         DECL_VINDEX (decl) = NULL_TREE;
-         TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
-         add_tree (stmt);
+         if (stmt != NULL_TREE)
+           {
+             DECL_VINDEX (decl) = NULL_TREE;
+             TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
+             add_tree (stmt);
+           }
        }
 
       goto finish_end0;
@@ -6685,7 +6767,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
       || TREE_CODE (decl) == RESULT_DECL)
     {
       /* ??? FIXME: What about nested classes?  */
-      int toplev = toplevel_bindings_p () || pseudo_global_level_p ();
+      /* We check for FUNCTION_DECL here so that member functions of
+        local classes, which will have internal linkage, are not
+        given bizarre names by make_decl_rtl.  */
+      int toplev = toplevel_bindings_p () || pseudo_global_level_p ()
+       || TREE_CODE (decl) == FUNCTION_DECL;
       int was_temp
        = (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)
           && allocation_temporary_p ());
@@ -7367,12 +7453,12 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
        break;
       }
 
-  /* Caller will do the rest of this.  */
-  check_explicit_specialization (orig_declarator, decl,
-                                template_count, 
-                                funcdef_flag ? 2 : 
-                                (friendp ? 3 : 0));
+  if (friendp && 
+      TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
+    /* A friend declaration of the form friend void f<>().  */
+    SET_DECL_IMPLICIT_INSTANTIATION (decl);
 
+  /* Caller will do the rest of this.  */
   if (check < 0)
     return decl;
 
@@ -7391,6 +7477,11 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
 
       grokclassfn (ctype, declarator, decl, flags, quals);
 
+      check_explicit_specialization (orig_declarator, decl,
+                                    template_count, 
+                                    funcdef_flag ? 2 : 
+                                    (friendp ? 3 : 0));
+
       if (check)
        {
          tmp = check_classfn (ctype, decl);
@@ -7433,12 +7524,17 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
       if (ctype != NULL_TREE)
        grokclassfn (ctype, cname, decl, flags, quals);
 
+      check_explicit_specialization (orig_declarator, decl,
+                                    template_count, 
+                                    funcdef_flag ? 2 : 
+                                    (friendp ? 3 : 0));
+
       if (ctype != NULL_TREE && check)
        {
          tmp = check_classfn (ctype, decl);
 
          if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
-           tmp = DECL_TEMPLATE_RESULT(tmp);
+           tmp = DECL_TEMPLATE_RESULT (tmp);
              
          if (tmp && DECL_STATIC_FUNCTION_P (tmp)
              && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
@@ -7466,19 +7562,27 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
         methods, though.  */
       if (! current_function_decl)
        {
-         /* FIXME: this should only need to look at
-             IDENTIFIER_GLOBAL_VALUE.  */
-         tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
-         if (tmp == NULL_TREE)
-           IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
-         else if (TREE_CODE (tmp) != TREE_CODE (decl))
-           cp_error ("inconsistent declarations for `%D'", decl);
-         else
+         if (!DECL_TEMPLATE_SPECIALIZATION (decl))
            {
-             duplicate_decls (decl, tmp);
-             decl = tmp;
-             /* avoid creating circularities.  */
-             DECL_CHAIN (decl) = NULL_TREE;
+             /* We don't do this for specializations since the
+                equivalent checks will be done later.  Also, at this
+                point the DECL_ASSEMBLER_NAME is not yet fully
+                accurate.  */
+
+             /* FIXME: this should only need to look at
+                IDENTIFIER_GLOBAL_VALUE.  */
+             tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
+             if (tmp == NULL_TREE)
+               IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
+             else if (TREE_CODE (tmp) != TREE_CODE (decl))
+               cp_error ("inconsistent declarations for `%D'", decl);
+             else
+               {
+                 duplicate_decls (decl, tmp);
+                 decl = tmp;
+                 /* avoid creating circularities.  */
+                 DECL_CHAIN (decl) = NULL_TREE;
+               }
            }
 
          if (attrlist)
@@ -9169,7 +9273,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            t = ctype;
            while (t != NULL_TREE) 
              {
-               if (CLASSTYPE_TEMPLATE_INFO (t))
+               if (CLASSTYPE_TEMPLATE_INFO (t) &&
+                   !CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
                  template_count += 1;
                t = TYPE_MAIN_DECL (t);
                if (DECL_LANG_SPECIFIC (t))
@@ -9595,7 +9700,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              }
 
            /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node.  */
-           publicp = (! friendp || ! staticp);
+           publicp = (! friendp || ! staticp) && !is_local_class (ctype);
            decl = grokfndecl (ctype, type, 
                               TREE_CODE (declarator) != TEMPLATE_ID_EXPR
                               ? declarator : dname,
@@ -9811,7 +9916,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
        decl = grokfndecl (ctype, type, original_name, declarator,
                           virtualp, flags, quals, raises, attrlist,
-                          friendp ? 2 : 1, friendp,
+                          1, friendp,
                           publicp, inlinep, funcdef_flag, 
                           template_count);
        if (decl == NULL_TREE)
@@ -10926,8 +11031,8 @@ xref_basetypes (code_type_node, name, ref, binfo)
        }
 #if 1
       /* This code replaces similar code in layout_basetypes.  */
-      else if (TYPE_SIZE (complete_type (basetype)) == NULL_TREE
-              && ! (current_template_parms && uses_template_parms (basetype)))
+      else if (! (current_template_parms && uses_template_parms (basetype))
+              && TYPE_SIZE (complete_type (basetype)) == NULL_TREE)
        {
          cp_error ("base class `%T' has incomplete type", basetype);
          continue;
@@ -11506,7 +11611,10 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
     push_template_decl (decl1);
   else if (pre_parsed_p == 0)
     {
-      decl1 = pushdecl (decl1);
+      /* A specialization is not used to guide overload resolution.  */
+      if (flag_guiding_decls 
+         || !DECL_TEMPLATE_SPECIALIZATION (decl1))
+       decl1 = pushdecl (decl1);
       DECL_MAIN_VARIANT (decl1) = decl1;
       fntype = TREE_TYPE (decl1);
     }
@@ -11637,7 +11745,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
 
   if (processing_template_decl)
     {
-      extern tree last_tree;
       ++minimal_parse_mode;
       last_tree = DECL_SAVED_TREE (decl1)
        = build_nt (EXPR_STMT, void_zero_node);
@@ -12361,9 +12468,21 @@ finish_function (lineno, call_poplevel, nested)
 
   if (! processing_template_decl)
     {
+      int saved_flag_keep_inline_functions =
+       flag_keep_inline_functions;
+
       /* So we can tell if jump_optimize sets it to 1.  */
       can_reach_end = 0;
 
+      if (DECL_CONTEXT (fndecl) != NULL_TREE
+         && is_local_class (DECL_CONTEXT (fndecl)))
+       /* Trick rest_of_compilation into not deferring output of this
+          function, even if it is inline, since the rtl_obstack for
+          this function is the function_obstack of the enclosing
+          function and will be deallocated when the enclosing
+          function is gone.  See save_tree_status.  */
+       flag_keep_inline_functions = 1;
+
       /* Run the optimizers and output the assembler code for this
          function.  */
 
@@ -12384,6 +12503,8 @@ finish_function (lineno, call_poplevel, nested)
       else
        rest_of_compilation (fndecl);
 
+      flag_keep_inline_functions = saved_flag_keep_inline_functions;
+
       if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl))
        {
          /* Set DECL_EXTERNAL so that assemble_external will be called as
@@ -12529,7 +12650,7 @@ start_method (declspecs, declarator)
   if (flag_default_inline)
     DECL_INLINE (fndecl) = 1;
 
-  if (processing_template_decl && ! current_function_decl)
+  if (processing_template_decl)
     push_template_decl (fndecl);
 
   /* We read in the parameters on the maybepermanent_obstack,
index 971a3e4d27bce0a3cf00cf1e4a86b4f7becc7133..f10390d54a7c1fcdacf9d623a28a50fc33717cde 100644 (file)
@@ -2785,7 +2785,11 @@ import_export_decl (decl)
       if (DECL_IMPLICIT_INSTANTIATION (decl)
          && (flag_implicit_templates || DECL_THIS_INLINE (decl)))
        {
-         if (TREE_CODE (decl) == FUNCTION_DECL)
+         if (!TREE_PUBLIC (decl))
+           /* Templates are allowed to have internal linkage.  See 
+              [basic.link].  */
+           ;
+         else if (TREE_CODE (decl) == FUNCTION_DECL)
            comdat_linkage (decl);
          else
            DECL_COMDAT (decl) = 1;
@@ -3600,9 +3604,20 @@ build_expr_from_tree (t)
       }
 
     case COMPONENT_REF:
-      return build_x_component_ref
-       (build_expr_from_tree (TREE_OPERAND (t, 0)),
-        TREE_OPERAND (t, 1), NULL_TREE, 1);
+      {
+       tree object = build_expr_from_tree (TREE_OPERAND (t, 0));
+
+       if (object != NULL_TREE 
+           && TREE_CODE (object) == TEMPLATE_DECL)
+         {
+           cp_error ("invalid use of %D", object);
+           object = error_mark_node;
+         }
+
+       return build_x_component_ref
+         (object,
+          TREE_OPERAND (t, 1), NULL_TREE, 1);
+      }
 
     case THROW_EXPR:
       return build_throw (build_expr_from_tree (TREE_OPERAND (t, 0)));
index d2cad749a421846e2d21e3526c0eb0197eb4ceb4..cc264e619b6da07e3d73f1a4cadcafc3bfea4ba4 100644 (file)
@@ -952,71 +952,89 @@ dump_function_name (t)
   else
     dump_decl (name, 0);
 
-  if (DECL_LANG_SPECIFIC (t)
-      && (DECL_TEMPLATE_SPECIALIZATION (t) || DECL_IMPLICIT_INSTANTIATION (t))
-      && (DECL_CLASS_CONTEXT (t) == NULL_TREE || is_member_template (t)))
+  if (DECL_LANG_SPECIFIC (t) && DECL_USE_TEMPLATE (t))
     {
-      tree args = DECL_TEMPLATE_INFO (t) 
-       ? DECL_TI_ARGS (t) : NULL_TREE; 
-
-      OB_PUTC ('<');
-
-      /* Be careful only to print things when we have them, so as not
-        to crash producing error messages.  */
-      if (args)
+      tree args = DECL_TEMPLATE_INFO (t) ? DECL_TI_ARGS (t) : NULL_TREE; 
+
+      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
        {
-         if (TREE_CODE (args) == TREE_LIST)
-           {
-             tree arg;
-             int need_comma = 0;
+         OB_PUTC ('<');
 
-             for (arg = args; arg; arg = TREE_CHAIN (arg))
+         /* 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)
                {
-                 tree a = TREE_VALUE (arg);
-
-                 if (need_comma)
-                   OB_PUTS (", ");
+                 tree arg;
+                 int need_comma = 0;
 
-                 if (a)
+                 for (arg = args; arg; arg = TREE_CHAIN (arg))
                    {
-                     if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
-                       dump_type (a, 0);
-                     else
-                       dump_expr (a, 0);
-                   }
+                     tree a = TREE_VALUE (arg);
+
+                     if (need_comma)
+                       OB_PUTS (", ");
+
+                     if (a)
+                       {
+                         if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
+                           dump_type (a, 0);
+                         else
+                           dump_expr (a, 0);
+                       }
                  
-                 need_comma = 1;
+                     need_comma = 1;
+                   }
                }
-           }
-         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, 0);
-
-             for (i = 0; i < TREE_VEC_LENGTH (args); i++)
+             else if (TREE_CODE (args) == TREE_VEC)
                {
-                 tree a = TREE_VEC_ELT (args, i);
+                 int i;
+                 int need_comma = 0;
 
-                 if (need_comma)
-                   OB_PUTS (", ");
+                 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);
 
-                 if (a)
+                 for (i = 0; i < TREE_VEC_LENGTH (args); i++)
                    {
-                     if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
-                       dump_type (a, 0);
-                     else
-                       dump_expr (a, 0);
-                   }
+                     tree a = TREE_VEC_ELT (args, i);
+
+                     if (need_comma)
+                       OB_PUTS (", ");
+
+                     if (a)
+                       {
+                         if (TREE_CODE_CLASS (TREE_CODE (a)) == 't')
+                           dump_type (a, 0);
+                         else
+                           dump_expr (a, 0);
+                       }
                  
-                 need_comma = 1;
+                     need_comma = 1;
+                   }
                }
            }
+         OB_PUTC ('>');
        }
-      OB_PUTC ('>');
     }
 }
 
index 88068e3b2a99d83c0e1cf98acb1ea8858f0fcd62..1114a631e5c1acd8bf7512bb0fc9f1b2366b8550 100644 (file)
@@ -1995,15 +1995,21 @@ cons_up_default_function (type, full_name, kind)
   {
     tree declarator = make_call_declarator (name, args, NULL_TREE, NULL_TREE);
     int saved_processing_specialization;
+    int saved_processing_explicit_instantiation;
     if (retref)
       declarator = build_parse_node (ADDR_EXPR, declarator);
 
     /* The following is in case we're generating the default
        implementation in the midst of handling a specialization. */
     saved_processing_specialization = processing_specialization;
+    saved_processing_explicit_instantiation =
+      processing_explicit_instantiation; 
     processing_specialization = 0;
+    processing_explicit_instantiation = 0;
     fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE, NULL_TREE);
     processing_specialization = saved_processing_specialization;
+    processing_explicit_instantiation = 
+      saved_processing_explicit_instantiation;
   }
   
   if (fn == void_type_node)
index 43655139ba0761b9bd1e78e8b582f57385a47f4c..054479edc705d86a62bd3c74241e6ef9c2385ca5 100644 (file)
@@ -56,7 +56,6 @@ extern int errno;
 
 extern int end_of_file;
 extern int current_class_depth;
-extern tree last_tree;
 
 /* FSF LOCAL dje prefix attributes */
 extern tree strip_attrs                PROTO((tree));
@@ -73,6 +72,7 @@ extern tree strip_attrs               PROTO((tree));
 static char *cond_stmt_keyword;
 
 static tree empty_parms PROTO((void));
+static tree finish_member_template_decl PROTO((tree, tree));
 
 /* Nonzero if we have an `extern "C"' acting as an extern specifier.  */
 int have_extern_spec;
@@ -94,6 +94,32 @@ empty_parms ()
     parms = NULL_TREE;
   return parms;
 }
+
+
+static tree
+finish_member_template_decl (template_arguments, decl)
+  tree template_arguments;
+  tree decl;
+{
+  if (template_arguments)
+    end_template_decl();
+  else
+    end_specialization();
+
+  if (decl && DECL_TEMPLATE_INFO (decl) &&
+      !DECL_TEMPLATE_SPECIALIZATION (decl))
+    {
+      check_member_template (DECL_TI_TEMPLATE (decl));
+      return DECL_TI_TEMPLATE (decl);
+    }
+
+  if (decl)
+    return decl;
+
+  cp_error ("invalid member template declaration");
+  return NULL_TREE;
+}
+
 %}
 
 %start program
@@ -260,7 +286,7 @@ empty_parms ()
 %type <ttype> template_header template_parm_list template_parm
 %type <ttype> template_type_parm
 %type <code>  template_close_bracket
-%type <ttype> template_type template_arg_list template_arg
+%type <ttype> template_type template_arg_list template_arg_list_opt template_arg
 %type <ttype> condition xcond paren_cond_or_null
 %type <ttype> type_name nested_name_specifier nested_type ptr_to_mem
 %type <ttype> complete_type_name notype_identifier nonnested_type
@@ -716,26 +742,7 @@ fn.def2:
        | constructor_declarator
                { $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
         | template_header fn.def2 
-                { 
-                  if ($1)
-                    end_template_decl (); 
-                 else
-                   end_specialization ();
-
-                 if ($2 && DECL_TEMPLATE_INFO ($2)
-                     && !DECL_TEMPLATE_SPECIALIZATION ($2))
-                   {
-                     $$ = DECL_TI_TEMPLATE ($2); 
-                     check_member_template ($$);
-                   }
-                 else if ($2)
-                   $$ = $2;
-                 else 
-                   {
-                     cp_error("invalid member template declaration");
-                     $$ = NULL_TREE;
-                   }
-               }
+                { $$ = finish_member_template_decl ($1, $2); }
        ;
 
 return_id:
@@ -848,54 +855,57 @@ identifier_defn:
        ;
 
 explicit_instantiation:
-         TEMPLATE typespec ';'
-               { do_type_instantiation ($2.t, NULL_TREE);
-                 yyungetc (';', 1); }
-       | TEMPLATE typed_declspecs declarator
-               { tree specs = strip_attrs ($2.t);
-                 do_decl_instantiation (specs, $3, NULL_TREE); }
-       | TEMPLATE notype_declarator
-               { do_decl_instantiation (NULL_TREE, $2, NULL_TREE); }
-       | TEMPLATE constructor_declarator
-               { do_decl_instantiation (NULL_TREE, $2, NULL_TREE); }
-       | SCSPEC TEMPLATE typespec ';'
-               { do_type_instantiation ($3.t, $1);
+         TEMPLATE begin_explicit_instantiation typespec ';'
+               { do_type_instantiation ($3.t, NULL_TREE);
                  yyungetc (';', 1); }
-       | SCSPEC TEMPLATE typed_declspecs declarator
+          end_explicit_instantiation
+       | TEMPLATE begin_explicit_instantiation typed_declspecs declarator
                { tree specs = strip_attrs ($3.t);
-                 do_decl_instantiation (specs, $4, $1); }
-       | SCSPEC TEMPLATE notype_declarator
-               { do_decl_instantiation (NULL_TREE, $3, $1); }
-       | SCSPEC TEMPLATE constructor_declarator
-               { do_decl_instantiation (NULL_TREE, $3, $1); }
-       ;
+                 do_decl_instantiation (specs, $4, NULL_TREE); }
+          end_explicit_instantiation
+       | TEMPLATE begin_explicit_instantiation notype_declarator
+               { do_decl_instantiation (NULL_TREE, $3, NULL_TREE); }
+          end_explicit_instantiation
+       | TEMPLATE begin_explicit_instantiation constructor_declarator
+               { do_decl_instantiation (NULL_TREE, $3, NULL_TREE); }
+          end_explicit_instantiation
+       | SCSPEC TEMPLATE begin_explicit_instantiation typespec ';'
+               { do_type_instantiation ($4.t, $1);
+                 yyungetc (';', 1); }
+          end_explicit_instantiation
+       | SCSPEC TEMPLATE begin_explicit_instantiation typed_declspecs 
+          declarator
+               { tree specs = strip_attrs ($4.t);
+                 do_decl_instantiation (specs, $5, $1); }
+          end_explicit_instantiation
+       | SCSPEC TEMPLATE begin_explicit_instantiation notype_declarator
+               { do_decl_instantiation (NULL_TREE, $4, $1); }
+          end_explicit_instantiation
+       | SCSPEC TEMPLATE begin_explicit_instantiation constructor_declarator
+               { do_decl_instantiation (NULL_TREE, $4, $1); }
+          end_explicit_instantiation
+       ;
+
+begin_explicit_instantiation: 
+      { begin_explicit_instantiation(); }
+
+end_explicit_instantiation: 
+      { end_explicit_instantiation(); }
 
 /* The TYPENAME expansions are to deal with use of a template class name as
   a template within the class itself, where the template decl is hidden by
   a type decl.  Got all that?  */
 
 template_type:
-         PTYPENAME '<' template_arg_list template_close_bracket
+         PTYPENAME '<' template_arg_list_opt template_close_bracket
                {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE);
+                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
                  if ($$ != error_mark_node)
                    $$ = TYPE_STUB_DECL ($$);
                }
-       | PTYPENAME '<' template_close_bracket
+       | TYPENAME  '<' template_arg_list_opt template_close_bracket
                {
-                 $$ = lookup_template_class ($1, NULL_TREE, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
-       | TYPENAME  '<' template_arg_list template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
-       | TYPENAME '<' template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, NULL_TREE, NULL_TREE);
+                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
                  if ($$ != error_mark_node)
                    $$ = TYPE_STUB_DECL ($$);
                }
@@ -903,15 +913,9 @@ template_type:
        ;
 
 self_template_type:
-         SELFNAME  '<' template_arg_list template_close_bracket
+         SELFNAME  '<' template_arg_list_opt template_close_bracket
                {
-                 $$ = lookup_template_class ($1, $3, NULL_TREE);
-                 if ($$ != error_mark_node)
-                   $$ = TYPE_STUB_DECL ($$);
-               }
-       | SELFNAME '<' template_close_bracket
-               {
-                 $$ = lookup_template_class ($1, NULL_TREE, NULL_TREE);
+                 $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
                  if ($$ != error_mark_node)
                    $$ = TYPE_STUB_DECL ($$);
                }
@@ -927,8 +931,14 @@ template_close_bracket:
                }
        ;
 
+template_arg_list_opt:
+         /* empty */
+                 { $$ = NULL_TREE; }
+       | template_arg_list
+       ;
+
 template_arg_list:
-         template_arg
+        template_arg
                { $$ = build_tree_list (NULL_TREE, $$); }
        | template_arg_list ',' template_arg
                { $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); }
@@ -1297,22 +1307,19 @@ do_id:
                { $$ = do_identifier ($<ttype>-1, 1); }
 
 template_id:
-          PFUNCNAME '<' do_id template_arg_list template_close_bracket 
+          PFUNCNAME '<' do_id template_arg_list_opt template_close_bracket 
                 { $$ = lookup_template_function ($3, $4); }
-        | PFUNCNAME '<' do_id template_close_bracket
-                { $$ = lookup_template_function ($3, NULL_TREE); }
-        | operator_name '<' do_id template_arg_list template_close_bracket
+        | operator_name '<' do_id template_arg_list_opt template_close_bracket
                 { $$ = lookup_template_function ($3, $4); }
-        | operator_name '<' do_id template_close_bracket
-                { $$ = lookup_template_function ($3, NULL_TREE); }
        ;
 
 object_template_id:
-        TEMPLATE identifier '<' template_arg_list template_close_bracket
+        TEMPLATE identifier '<' template_arg_list_opt template_close_bracket
                 { $$ = lookup_template_function ($2, $4); }
-        | TEMPLATE PFUNCNAME '<' template_arg_list template_close_bracket
+        | TEMPLATE PFUNCNAME '<' template_arg_list_opt template_close_bracket
                 { $$ = lookup_template_function ($2, $4); }
-        | TEMPLATE operator_name '<' template_arg_list template_close_bracket
+        | TEMPLATE operator_name '<' template_arg_list_opt 
+          template_close_bracket
                 { $$ = lookup_template_function ($2, $4); }
         ;
 
@@ -1333,7 +1340,7 @@ expr_or_declarator:
        ;
 
 notype_template_declarator:
-         IDENTIFIER '<' template_arg_list template_close_bracket
+         IDENTIFIER '<' template_arg_list_opt template_close_bracket
                 { $$ = lookup_template_function ($1, $3); }
        | NSNAME '<' template_arg_list template_close_bracket
                 { $$ = lookup_template_function ($1, $3); }
@@ -2261,7 +2268,6 @@ structsp:
                  $$.new_type_flag = 0; }
        /* C++ extensions, merged with C to avoid shift/reduce conflicts */
        | class_head left_curly 
-                { reset_specialization(); }
           opt.component_decl_list '}' maybe_attribute
                {
                  int semi;
@@ -2285,7 +2291,7 @@ structsp:
                    ;
                  else
                    {
-                     $<ttype>$ = finish_struct ($1, $4, $6, semi);
+                     $<ttype>$ = finish_struct ($1, $3, $5, semi);
                      if (semi) note_got_semicolon ($<ttype>$);
                    }
 
@@ -2304,10 +2310,13 @@ structsp:
                }
          pending_inlines
                { 
-                 $$.t = $<ttype>7;
+                 $$.t = $<ttype>6;
                  $$.new_type_flag = 1; 
                  if (current_class_type == NULL_TREE)
                    clear_inline_text_obstack (); 
+
+                 /* Undo the begin_tree in left_curly.  */
+                 end_tree ();
                }
        | class_head  %prec EMPTY
                {
@@ -2670,6 +2679,12 @@ left_curly:
                  if (t && IDENTIFIER_TEMPLATE (t))
                    overload_template_name (t, 1);
 #endif
+                 reset_specialization();
+
+                 /* In case this is a local class within a template
+                    function, we save the current tree structure so
+                    that we can get it back later.  */
+                 begin_tree ();
                }
        ;
 
@@ -2791,26 +2806,7 @@ component_decl_1:
        | using_decl
                { $$ = do_class_using_decl ($1); }
         | template_header component_decl_1 
-                { 
-                  if ($1)
-                   end_template_decl (); 
-                  else
-                    end_specialization ();
-
-                 if ($2 && DECL_TEMPLATE_INFO ($2)
-                     && !DECL_TEMPLATE_SPECIALIZATION ($2))
-                   {
-                     $$ = DECL_TI_TEMPLATE ($2); 
-                     check_member_template ($$);
-                   }
-                 else if ($2)
-                   $$ = $2;
-                 else
-                   {
-                     cp_error("invalid member template declaration");
-                     $$ = NULL_TREE;
-                   }
-               }
+                { $$ = finish_member_template_decl ($1, $2); }
 
 /* The case of exactly one component is handled directly by component_decl.  */
 /* ??? Huh? ^^^ */
index 9476d1286f83c49a5fb7f324dbf64e76f3c6c256..b76a763dc33666b8bcff36652807a84fdf361c5b 100644 (file)
@@ -61,8 +61,11 @@ static tree *maybe_template_tail = &maybe_templates;
 int minimal_parse_mode;
 
 int processing_specialization;
+int processing_explicit_instantiation;
 static int template_header_count;
 
+static tree saved_trees;
+
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
@@ -70,19 +73,19 @@ static int unify PROTO((tree, tree *, int, 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));
+static char *mangle_class_name_for_template PROTO((char *, tree, tree, tree));
 static tree tsubst_expr_values PROTO((tree, tree));
 static int comp_template_args PROTO((tree, tree));
 static int list_eq PROTO((tree, tree));
 static tree get_class_bindings PROTO((tree, tree, tree));
-static tree coerce_template_parms PROTO((tree, tree, tree));
+static tree coerce_template_parms PROTO((tree, tree, tree, int, int));
 static tree tsubst_enum        PROTO((tree, tree, int, tree *));
 static tree add_to_template_args PROTO((tree, tree));
 static int  type_unification_real PROTO((tree, tree *, tree, tree, int*,
                                         int, int, int));
-static int processing_explicit_specialization PROTO((int));
 static void note_template_header PROTO((int));
 static tree maybe_fold_nontype_arg PROTO((tree));
+static tree convert_nontype_parameter PROTO((tree, tree));
 
 /* Restore the template parameter context. */
 
@@ -140,8 +143,19 @@ end_member_template_processing ()
   poplevel (0, 0, 0);
 }
 
-/* Returns non-zero iff T is a member template function.  Works if T
-   is either a FUNCTION_DECL or a TEMPLATE_DECL.  */
+/* Returns non-zero iff T is a member template function.  We must be
+   careful as in 
+
+     template <class T> class C { void f(); }
+
+   Here, f is a template function, and a member, but not a member
+   template.  This function does not concern itself with the origin of
+   T, only its present state.  So if we have 
+
+     template <class T> class C { template <class U> void f(U); }
+
+   then neither C<int>::f<char> nor C<T>::f<double> is considered
+   to be a member template.  */
 
 int
 is_member_template (t)
@@ -151,7 +165,7 @@ is_member_template (t)
 
   if (TREE_CODE (t) != FUNCTION_DECL
       && !DECL_FUNCTION_TEMPLATE_P (t))
-    /* Anything that isn't a template or a template function is
+    /* Anything that isn't a function or a template function is
        certainly not a member template.  */
     return 0;
 
@@ -175,33 +189,27 @@ is_member_template (t)
          int template_class_levels = 0;
          tree ctx = DECL_CLASS_CONTEXT (t);
 
-         if (CLASSTYPE_TEMPLATE_INFO (ctx))
-           {
-             tree args;
+         /* NB - The code below does not yet handle template class
+            members, e.g. 
+            
+              template <class T> class C { template <class U> class D; }}
 
-             /* Here, we should really count the number of levels
-                deep ctx is, making sure not to count any levels that
-                are just specializations.  Since there are no member
-                template classes yet, we don't have to do all that.  */
+            correctly.  In that case, the D should have level 2.  */
 
-             if (!CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
+         if (CLASSTYPE_TEMPLATE_INFO (ctx))
+           {
+             tree args = CLASSTYPE_TI_ARGS (ctx);
+             int i;
+             
+             if (args == NULL_TREE)
                template_class_levels = 1;
-             else
-               {
-                 int i;
-
-                 args = CLASSTYPE_TI_ARGS (ctx);
-
-                 if (args == NULL_TREE)
-                   template_class_levels = 1;
-                 else 
-                   for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
-                     if (uses_template_parms (TREE_VEC_ELT (args, i)))
-                       {
-                         template_class_levels++;
-                         break;
-                       }
-               }
+             else 
+               for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
+                 if (uses_template_parms (TREE_VEC_ELT (args, i)))
+                   {
+                     template_class_levels++;
+                     break;
+                   }
            }
 
          if (parm_levels > template_class_levels)
@@ -298,68 +306,145 @@ note_template_header (specialization)
 }
 
 
-/* Returns non-zero iff a declarator, in which the number of template
-   types that appeared was TEMPLATE_COUNT, is an explicit
-   specialization.  */
+/* We're beginning an explicit instantiation.  */
 
-static int
-processing_explicit_specialization (template_count)
-     int template_count;
+void
+begin_explicit_instantiation ()
 {
-  /* A function declaration is an explicit specialization of a member
-     template if all of the following conditions hold:
-     
-     o There was a template <...> preceeding the declaration.
-     o The last template <...> was in fact template <>.
-     o The number of template <...>'s preceeding the declaration, less
-       the number of template classes with arguments specified used to
-       qualify the function name, is 1.
+  ++processing_explicit_instantiation;
+}
 
-     For example:
 
-     template <> void S<int>::foo(); 
-     template <class T> template <> void S<T>::foo();
-     template <> struct S<int> { ... template <> void foo(); }
+void
+end_explicit_instantiation ()
+{
+  my_friendly_assert(processing_explicit_instantiation > 0, 0);
+  --processing_explicit_instantiation;
+}
 
-     The first of these is not a specialization of S<int>::foo() (it
-     is instead a specialization of S<T>::foo), while the next two are
-     specializations of member template functions.  */
 
-  return processing_specialization 
-    && template_header_count > template_count; 
+/* 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
+   no such specialization, return NULL_TREE.  The ARGS are a vector of
+   arguments, or a vector of vectors of arguments, in the case of
+   templates with more than one level of parameters.  */
+   
+static tree
+retrieve_specialization (tmpl, args)
+     tree tmpl;
+     tree args;
+{
+  tree s;
+
+  my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
+
+  for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+       s != NULL_TREE;
+       s = TREE_CHAIN (s))
+    if (comp_template_args (TREE_PURPOSE (s), args))
+      return TREE_VALUE (s);
+
+  return NULL_TREE;
 }
 
-/* Returns the template function specialized by TEMPLATE_ID, or
-   NULL_TREE if there is none.
 
-   The TEMPLATE_ID is a TEMPLATE_ID_EXPR.  The TYPE is
-   the type it has been declared to have.  Return the TEMPLATE_DECL
-   that is being specialized, and put the specialization arguments in
-   *TARGS.  If no appropriate specialization can be found, NULL_TREE is
-   returned, and *TARGS is assigned NULL_TREE.  If complain is
-   non-zero, error messages are printed where appropriate.  */
-   
+
+/* Register the specialization SPEC as a specialization of TMPL with
+   the indicated ARGS.  */
+
+static void
+register_specialization (spec, tmpl, args)
+     tree spec;
+     tree tmpl;
+     tree args;
+{
+  tree s;
+
+  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;
+    
+  for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+       s != NULL_TREE;
+       s = TREE_CHAIN (s))
+    if (comp_template_args (TREE_PURPOSE (s), args))
+      {
+       tree fn = TREE_VALUE (s);
+
+       if (DECL_TEMPLATE_SPECIALIZATION (spec))
+         {
+           if (DECL_TEMPLATE_INSTANTIATION (fn))
+             {
+               if (TREE_USED (fn) 
+                   || DECL_EXPLICIT_INSTANTIATION (fn))
+                 {
+                   cp_error ("specialization of %D after instantiation",
+                             fn);
+                   return;
+                 }
+               else
+                 {
+                   /* This situation should occur only if the first
+                      specialization is an implicit instantiation,
+                      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.  */
+
+                   /* FIXME: Should we call duplicate_decls here?  */
+                   TREE_VALUE (s) = spec;
+                   return;
+                 }
+             }
+           else if (DECL_TEMPLATE_SPECIALIZATION (fn))
+             {
+               if (DECL_INITIAL (fn))
+                 cp_error ("duplicate specialization of %D", fn);
+
+               /* FIXME: Should we call duplicate_decls here?  */
+               TREE_VALUE (s) = spec;
+               return;
+             }
+         }
+      }
+
+  DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
+     = perm_tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+}
+
+
+/* Returns the template (one of the functions given by TEMPLATE_ID)
+   which can be specialized to have the indicated TYPE with the
+   explicit template args given in TEMPLATE_ID.  TARGS_IN.  The
+   template args (those explicitly specified and those deduced) are
+   output in a newly created vector *TARGS_OUT.  If it is impossible
+   to determine the result, an error message is issued, unless
+   COMPLAIN is 0.  */
+
 tree
-determine_explicit_specialization (template_id, type, targs_out,
-                                  need_member_template,
-                                  complain)
+determine_specialization (template_id, type, targs_out, 
+                         need_member_template,
+                         complain)
      tree template_id;
      tree type;
      tree* targs_out;
      int need_member_template;
      int complain;
 {
-  int i;
-  int overloaded;
-  tree fns;
+  tree fns = TREE_OPERAND (template_id, 0);
+  tree targs_in = TREE_OPERAND (template_id, 1);
   tree matching_fns = NULL_TREE;
-  tree result;
   tree fn;
-
-  my_friendly_assert (TREE_CODE (template_id) == TEMPLATE_ID_EXPR
-                     && TREE_OPERAND (template_id, 0), 0); 
-                     
-  fns = TREE_OPERAND (template_id, 0);
+  int overloaded;
+  int i;
 
   if (is_overloaded_fn (fns))
     fn = get_first_fn (fns);
@@ -367,30 +452,38 @@ determine_explicit_specialization (template_id, type, targs_out,
     fn = NULL_TREE;
 
   overloaded = really_overloaded_fn (fns);
-
   for (; fn != NULL_TREE; 
        fn = overloaded ? DECL_CHAIN (fn) : NULL_TREE)
     {
       int dummy = 0;
       tree targs;
-
-      if (TREE_CODE (fn) != TEMPLATE_DECL
+      tree t;
+      tree tmpl;
+
+      if (!need_member_template 
+         && TREE_CODE (fn) == FUNCTION_DECL 
+         && DECL_USE_TEMPLATE (fn)
+         && DECL_TI_TEMPLATE (fn))
+       tmpl = DECL_TI_TEMPLATE (fn);
+      else if (TREE_CODE (fn) != TEMPLATE_DECL
          || (need_member_template && !is_member_template (fn)))
        continue;
+      else
+       tmpl = fn;
 
-      if (list_length (TREE_OPERAND (template_id, 1)) > DECL_NTPARMS (fn))
+      if (list_length (targs_in) > DECL_NTPARMS (tmpl))
        continue;
 
-      targs = make_scratch_vec (DECL_NTPARMS (fn));
+      targs = make_scratch_vec (DECL_NTPARMS (tmpl));
 
       /* We allow incomplete unification here, because we are going to
         check all the functions. */
-      i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
+      i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
                            &TREE_VEC_ELT (targs, 0),
                            type 
-                           ? TYPE_ARG_TYPES (TREE_TYPE (fn)) : NULL_TREE, 
+                           ? TYPE_ARG_TYPES (TREE_TYPE (tmpl)) : NULL_TREE, 
                            type ? TYPE_ARG_TYPES (type) : NULL_TREE,
-                           TREE_OPERAND (template_id, 1),
+                           targs_in,
                            &dummy, 1, 1);
       
       if (i == 0) 
@@ -399,9 +492,9 @@ determine_explicit_specialization (template_id, type, targs_out,
             match. */
          if (type != NULL_TREE)
            {
-             tree tmpl_return_type = tsubst (TREE_TYPE (TREE_TYPE (fn)),
+             tree tmpl_return_type = tsubst (TREE_TYPE (TREE_TYPE (tmpl)),
                                              targs,
-                                             DECL_NTPARMS (fn),
+                                             DECL_NTPARMS (tmpl),
                                              NULL_TREE);
              
              if (tmpl_return_type != TREE_TYPE (type))
@@ -412,35 +505,37 @@ determine_explicit_specialization (template_id, type, targs_out,
                     problem.  */
                  cp_error ("Return type of explicit specialization of");
                  cp_error ("`%D' is `%T', but should be `%T'.", 
-                           fn, TREE_TYPE (type), tmpl_return_type);
+                           tmpl, TREE_TYPE (type), tmpl_return_type);
                  *targs_out = NULL_TREE;
                  return NULL_TREE;
                }
            }
 
-         matching_fns = scratch_tree_cons (fn, targs, matching_fns);
+         matching_fns = scratch_tree_cons (tmpl, targs, matching_fns);
        }
     }
-
+  
   if (matching_fns == NULL_TREE)
     {
       if (complain)
        cp_error ("`%D' does not match any template declaration.",
                  template_id);
-
+      
       *targs_out = NULL_TREE;
       return NULL_TREE;
     }
-
+  
   if (TREE_CHAIN (matching_fns) != NULL_TREE) 
     {
       if (complain)
        {
-         tree fn;
+         tree tmpl;
          
          cp_error ("Ambiguous explicit specialization.  Candidates are:");
-         for (fn = matching_fns; fn != NULL_TREE; fn = TREE_CHAIN (fn))
-           cp_error ("    %D", TREE_PURPOSE (fn));
+         for (tmpl = matching_fns; 
+              tmpl != NULL_TREE; 
+              tmpl = TREE_CHAIN (tmpl)) 
+           cp_error ("    %D", TREE_PURPOSE (tmpl));
        }
 
       *targs_out = NULL_TREE;
@@ -454,14 +549,50 @@ determine_explicit_specialization (template_id, type, targs_out,
 
        
 /* Check to see if the function just declared, as indicated in
-   DECLARATOR, and in DECL, is a specialization.  Check that the
-   specialization is OK.  If FLAGS == 1, we are being called by
-   finish_struct_methods.  If FLAGS == 2, we are being called by
-   grokfndecl, and the function has a definition, or is a friend.  If
-   FLAGS == 3, this is a friend declaration.
-   Returns 0 if the decl is not an explicit specialization or
-   instantiation, 1 if it is an explicit specialization, and 2 if it
-   is an explicit instantiation.  */
+   DECLARATOR, and in DECL, is a specialization of a function
+   template.  We may also discover that the declaration is an explicit
+   instantiation at this point.
+
+   Returns:
+   
+     0: The function is not an explicit specialization or instantiation.
+     1: The function is an explicit specialization.
+     2: The function is an explicit instantiation.
+
+   FLAGS is a bitmask consisting of the following flags: 
+
+   1: We are being called by finish_struct.  (We are unable to
+      determine what template is specialized by an in-class
+      declaration until the class definition is complete, so
+      finish_struct_methods calls this function again later to finish
+      the job.)
+   2: The function has a definition.
+   4: The function is a friend.
+   8: The function is known to be a specialization of a member
+      template. 
+
+   The TEMPLATE_COUNT is the number of references to qualifying
+   template classes that appeared in the name of the function.  For
+   example, in
+
+     template <class T> struct S { void f(); };
+     void S<int>::f();
+     
+   the TEMPLATE_COUNT would be 1.  However, explicitly specialized
+   classes are not counted in the TEMPLATE_COUNT, so that in
+
+     template <class T> struct S {};
+     template <> struct S<int> { void f(); }
+     template <>
+     void S<int>::f();
+
+   the TEMPLATE_COUNT would be 0.  (Note that this declaration is
+   illegal; there should be no template <>.)
+
+   If the function is a specialization, it is marked as such via
+   DECL_TEMPLATE_SPECIALIZATION.  Furthermore, its DECL_TEMPLATE_INFO
+   is set up correctly, and it is added to the list of specializations 
+   for that template.  */
 
 int
 check_explicit_specialization (declarator, decl, template_count, flags)
@@ -470,49 +601,122 @@ check_explicit_specialization (declarator, decl, template_count, flags)
      int template_count;
      int flags;
 {
-  int finish_member = flags == 1;
-  int have_def = flags == 2;
-  int is_friend = flags == 3;
+  int finish_member = flags & 1;
+  int have_def = flags & 2;
+  int is_friend = flags & 4;
+  int specialization = 0;
+  int member_specialization = flags & 8;
+
+  tree ctype = DECL_CLASS_CONTEXT (decl);
+  tree dname = DECL_NAME (decl);
 
-  if (processing_explicit_specialization (template_count)
-      || finish_member
-      || TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
+  if (!finish_member)
     {
-      tree tmpl = NULL_TREE;
-      tree dname = DECL_NAME (decl);
-      tree ctype = DECL_CLASS_CONTEXT (decl);
-      tree targs;
+      if (processing_specialization) 
+       {
+         /* The last template header was of the form template <>.  */
+         
+         if (template_header_count > template_count) 
+           {
+             /* There were more template headers than qualifying template
+                classes.  */
+             if (template_header_count - template_count > 1)
+               /* There shouldn't be that many template parameter
+                  lists.  There can be at most one parameter list for
+                  every qualifying class, plus one for the function
+                  itself.  */
+               cp_error ("too many template parameter lists in declaration of `%D'", decl);
 
-      /* We've come across a declarator that looks like: U f<T1,
-        T2, ...>(A1, A2, ..).  This is an explicit template
-        specialization.  Check that: 
-              
-        o The explicitly specified parameters together with those
-        that can be deduced by template argument deduction
-        uniquely determine a particular specialization.  
-              
-        See [temp.expl.spec].  */
+             SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+             if (ctype)
+               member_specialization = 1;
+             else
+               specialization = 1;
+           }
+         else if (template_header_count == template_count)
+           {
+             /* The counts are equal.  So, this might be a
+                specialization, but it is not a specialization of a
+                member template.  It might be something like
+                
+                template <class T> struct S { 
+                void f(int i); 
+                };
+                template <>
+                void S<int>::f(int i) {}  */
+             specialization = 1;
+             SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+           }
+         else 
+           {
+             /* This cannot be an explicit specialization.  There are not
+                enough headers for all of the qualifying classes.  For
+                example, we might have:
+            
+                template <>
+                void S<int>::T<char>::f();
+
+                But, we're missing another template <>.  */
+             cp_error("too few template parameter lists in declaration of `%D'", decl);
+             return 0;
+           } 
+       }
+      else if (processing_explicit_instantiation)
+       {
+         if (template_header_count)
+           cp_error ("template parameter list used in explicit instantiation");
+         
+         if (have_def)
+           cp_error ("definition provided for explicit instantiation");
 
-      if (!finish_member
-         && TREE_CODE (declarator) == TEMPLATE_ID_EXPR
-         && !processing_explicit_specialization (template_count)
-         && !is_friend)
+         SET_DECL_EXPLICIT_INSTANTIATION (decl);
+
+         /* We don't try to figure out what's being explicitly
+            instantiated at this point, since do_decl_instantiation
+            will do that later.  */
+         return 2;
+       }
+      else if ((ctype != NULL_TREE
+               && !TYPE_BEING_DEFINED (ctype)
+               && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
+              || TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
        {
-         if (! have_def && ! template_header_count && ! ctype)
-           /* This is not an explict specialization.  It must be
-              an explicit instantiation.  */
-           return 2;
-         else if (template_header_count > template_count
-                  && !processing_specialization)
+         /* The first part of the above clause catches illegal code
+            that looks like this:
+
+            template <class T> struct S { void f(); }
+            void S<int>::f() {} // Missing template <>
+
+            We disable this check when the type is being defined to
+            avoid complaining about default compiler-generated
+            constructors, destructors, and assignment operators.
+            Since the type is an instantiation, not a specialization,
+            these are the only functions that can be defined before
+            the class is complete.
+
+            The second part handles bogus declarations like
+            template <> template <class T>
+            void f<int>();  */
+
+         if (template_header_count > template_count)
            {
              cp_error ("template-id `%D' in declaration of primary template",
                        declarator);
              return 0;
            }
-         else if (pedantic || uses_template_parms (decl))
-           pedwarn ("explicit specialization not preceded by `template <>'");
+         
+         cp_error ("explicit specialization not preceded by `template <>'");
+         return 0;
        }
+    }
 
+  if (specialization || member_specialization)
+    {
+      tree tmpl = NULL_TREE;
+      tree targs = NULL_TREE;
+      tree targs_in;
+
+      /* Make sure that the declarator is a TEMPLATE_ID_EXPR.  */
       if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
        {
          tree fns;
@@ -524,7 +728,8 @@ check_explicit_specialization (declarator, decl, template_count, flags)
          else
            fns = dname;
 
-         declarator = lookup_template_function (fns, NULL_TREE);
+         declarator = 
+           lookup_template_function (fns, NULL_TREE);
        }
 
       if (TREE_CODE (TREE_OPERAND (declarator, 0)) == LOOKUP_EXPR) 
@@ -536,50 +741,81 @@ check_explicit_specialization (declarator, decl, template_count, flags)
          return 1;
        } 
 
-      if (ctype 
-         && TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE)
+      if (ctype != NULL_TREE && TYPE_BEING_DEFINED (ctype))
+       {
+         /* Since finish_struct_1 has not been called yet, we
+            can't call lookup_fnfields.  We note that this
+            template is a specialization, and proceed, letting
+            finish_struct fix this up later.  */
+         DECL_TEMPLATE_INFO (decl) 
+           = perm_tree_cons (NULL_TREE, 
+                             TREE_OPERAND (declarator, 1),
+                             /* We remember whether or not this was a
+                                member specialization by recording
+                                this value, temporarily, in the
+                                TREE_CHAIN field.  Nobody looks at
+                                this, and we clear it in
+                                finish_struct.  */ 
+                             (tree) member_specialization);
+         return 1;
+       }
+      else if (ctype != NULL_TREE 
+              && (TREE_CODE (TREE_OPERAND (declarator, 0)) ==
+                  IDENTIFIER_NODE))
        {
+         /* Find the list of functions in ctype that have the same
+            name as the declared function.  */
+         tree name = TREE_OPERAND (declarator, 0);
          tree fns;
-         if (TYPE_BEING_DEFINED (ctype) && !finish_member)
+         
+         if (name == constructor_name (ctype) 
+             || name == constructor_name_full (ctype))
            {
-             /* Since finish_struct_1 has not been called yet, we
-                can't call lookup_fnfields.  We note that this
-                template is a specialization, and proceed, letting
-                finish_struct_methods fix this up later.  */
-             SET_DECL_TEMPLATE_SPECIALIZATION (decl);
-             DECL_TEMPLATE_INFO (decl) 
-               = perm_tree_cons (NULL_TREE, 
-                                 TREE_OPERAND (declarator, 1),
-                                 NULL_TREE);
-             return 1;
-           }
+             int is_constructor = DECL_CONSTRUCTOR_P (decl);
+             
+             if (is_constructor ? !TYPE_HAS_CONSTRUCTOR (ctype)
+                 : !TYPE_HAS_DESTRUCTOR (ctype))
+               {
+                 /* From [temp.expl.spec]:
+
+                    If such an explicit specialization for the member
+                    of a class template names an implicitly-declared
+                    special member function (clause _special_), the
+                    program is ill-formed.  */
+                 cp_error ("specialization of implicitly-declared special member function");
+
+                 return 1;
+               }
 
-         fns = lookup_fnfields (TYPE_BINFO (ctype), 
-                                TREE_OPERAND (declarator, 0),
-                                1);
+             fns = TREE_VEC_ELT(CLASSTYPE_METHOD_VEC (ctype),
+                                is_constructor ? 0 : 1);
+           }
+         else 
+           fns = lookup_fnfields (TYPE_BINFO (ctype), name,
+                                  1);
          
          if (fns == NULL_TREE) 
            {
-             cp_error ("No member template `%s' declared in `%T'",
-                       IDENTIFIER_POINTER (TREE_OPERAND (declarator,
-                                                         0)),
+             cp_error ("no member function `%s' declared in `%T'",
+                       IDENTIFIER_POINTER (name),
                        ctype);
              return 1;
            }
          else
            TREE_OPERAND (declarator, 0) = fns;
        }
-
-      tmpl = 
-       determine_explicit_specialization 
-       (declarator, TREE_TYPE (decl), &targs, 
-        TREE_CODE (decl) == TEMPLATE_DECL, 1);
+      
+      /* Figure out what exactly is being specialized at this point.  */
+      tmpl = determine_specialization (declarator,
+                                      TREE_TYPE (decl), &targs, 
+                                      member_specialization,
+                                      1);
            
       if (tmpl)
        {
          /* Mangle the function name appropriately.  */
-         if (name_mangling_version >= 1)
+         if ((member_specialization || ctype == NULL_TREE)
+             && name_mangling_version >= 1)
            {
              tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
 
@@ -606,16 +842,9 @@ check_explicit_specialization (declarator, decl, template_count, flags)
              SET_DECL_IMPLICIT_INSTANTIATION (decl);
              DECL_TEMPLATE_INFO (decl) 
                = perm_tree_cons (tmpl, targs, NULL_TREE);
-             return 1;
+             return 2;
            }
 
-         /* This function declaration is a template specialization.
-            Record that fact.  */
-         SET_DECL_TEMPLATE_SPECIALIZATION (decl);
-         DECL_TEMPLATE_SPECIALIZATIONS (tmpl) 
-           = perm_tree_cons (targs, decl, 
-                             DECL_TEMPLATE_SPECIALIZATIONS
-                             (tmpl));
          /* 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
@@ -635,13 +864,70 @@ check_explicit_specialization (declarator, decl, template_count, flags)
          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);
+
          return 1;
        }
     }
-
+  
   return 0;
 }
-                          
+
+
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+   parameters.  These are represented in the same format used for
+   DECL_TEMPLATE_PARMS.  */
+
+int comp_template_parms (parms1, parms2)
+     tree parms1;
+     tree parms2;
+{
+  tree p1;
+  tree p2;
+
+  if (parms1 == parms2)
+    return 1;
+
+  for (p1 = parms1, p2 = parms2; 
+       p1 != NULL_TREE && p2 != NULL_TREE;
+       p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2))
+    {
+      tree t1 = TREE_VALUE (p1);
+      tree t2 = TREE_VALUE (p2);
+      int i;
+
+      my_friendly_assert (TREE_CODE (t1) == TREE_VEC, 0);
+      my_friendly_assert (TREE_CODE (t2) == TREE_VEC, 0);
+
+      if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+       return 0;
+
+      for (i = 0; i < TREE_VEC_LENGTH (t2); ++i) 
+       {
+         tree parm1 = TREE_VALUE (TREE_VEC_ELT (t1, i));
+         tree parm2 = TREE_VALUE (TREE_VEC_ELT (t2, i));
+
+         if (TREE_CODE (parm1) != TREE_CODE (parm2))
+           return 0;
+
+         if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM)
+           continue;
+         else if (!comptypes (TREE_TYPE (parm1), 
+                              TREE_TYPE (parm2), 1))
+           return 0;
+       }
+    }
+
+  if ((p1 != NULL_TREE) != (p2 != NULL_TREE))
+    /* One set of parameters has more parameters lists than the
+       other.  */
+    return 0;
+
+  return 1;
+}
+
+
 /* Process information from new template parameter NEXT and append it to the
    LIST being built.  */
 
@@ -805,6 +1091,25 @@ current_template_args ()
 
   return args;
 }
+
+static tree
+build_template_decl (decl, parms)
+     tree decl;
+     tree parms;
+{
+  tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
+  DECL_TEMPLATE_PARMS (tmpl) = parms;
+  DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
+  if (DECL_LANG_SPECIFIC (decl))
+    {
+      DECL_CLASS_CONTEXT (tmpl) = DECL_CLASS_CONTEXT (decl);
+      DECL_STATIC_FUNCTION_P (tmpl) = 
+       DECL_STATIC_FUNCTION_P (decl);
+    }
+
+  return tmpl;
+}
+
   
 void
 push_template_decl (decl)
@@ -851,25 +1156,19 @@ push_template_decl (decl)
 
   args = current_template_args ();
 
-  if (! ctx || TYPE_BEING_DEFINED (ctx))
+  if (! ctx || TREE_CODE (ctx) == FUNCTION_DECL 
+      || TYPE_BEING_DEFINED (ctx))
     {
-      tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
-      DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
-      DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
-      if (DECL_LANG_SPECIFIC (decl))
+      tmpl = build_template_decl (decl, current_template_parms);
+      
+      if (DECL_LANG_SPECIFIC (decl)
+         && DECL_TEMPLATE_SPECIALIZATION (decl))
        {
-         DECL_CLASS_CONTEXT (tmpl) = DECL_CLASS_CONTEXT (decl);
-         DECL_STATIC_FUNCTION_P (tmpl) = 
-           DECL_STATIC_FUNCTION_P (decl);
-
-         if (DECL_TEMPLATE_SPECIALIZATION (decl))
-           {
-             /* A specialization of a member template of a template
-                class. */
-             SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
-             DECL_TEMPLATE_INFO (tmpl) = DECL_TEMPLATE_INFO (decl);
-             DECL_TEMPLATE_INFO (decl) = NULL_TREE;
-           }
+         /* A specialization of a member template of a template
+            class. */
+         SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
+         DECL_TEMPLATE_INFO (tmpl) = DECL_TEMPLATE_INFO (decl);
+         DECL_TEMPLATE_INFO (decl) = NULL_TREE;
        }
     }
   else
@@ -892,6 +1191,31 @@ push_template_decl (decl)
       
       if (is_member_template (tmpl))
        {
+         if (DECL_TEMPLATE_INFO (decl) && DECL_TI_ARGS (decl) 
+             && DECL_TEMPLATE_SPECIALIZATION (decl))
+           {
+             tree new_tmpl;
+
+             /* The declaration is a specialization of a member
+                template, declared outside the class.  Therefore, the
+                innermost template arguments will be NULL, so we
+                replace them with the arguments determined by the
+                earlier call to check_explicit_specialization.  */
+             args = DECL_TI_ARGS (decl);
+
+             new_tmpl 
+               = build_template_decl (decl, current_template_parms);
+             DECL_TEMPLATE_RESULT (new_tmpl) = decl;
+             TREE_TYPE (new_tmpl) = TREE_TYPE (decl);
+             DECL_TI_TEMPLATE (decl) = new_tmpl;
+             SET_DECL_TEMPLATE_SPECIALIZATION (new_tmpl);
+             DECL_TEMPLATE_INFO (new_tmpl) = 
+               perm_tree_cons (tmpl, args, NULL_TREE);
+
+             register_specialization (new_tmpl, tmpl, args);
+             return;
+           }
+         
          a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
          t = DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl));
          if (TREE_VEC_LENGTH (t) 
@@ -952,7 +1276,8 @@ push_template_decl (decl)
   if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
     {
       CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (tmpl)) = info;
-      DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));
+      if (!ctx || TREE_CODE (ctx) != FUNCTION_DECL)
+       DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));
     }
   else if (! DECL_LANG_SPECIFIC (decl))
     cp_error ("template declaration of `%#D'", decl);
@@ -960,17 +1285,359 @@ push_template_decl (decl)
     DECL_TEMPLATE_INFO (decl) = info;
 }
 
+
+/* Attempt to determine which of the overloaded functions given by
+   FNS has the indicated TYPE.  If this cannot be determined
+   unambiguously, return error_mark_node.  */
+
+static tree
+determine_overloaded_function (type, fns)
+     tree type;
+     tree fns;
+{
+  tree fn;
+
+  my_friendly_assert (fns != NULL_TREE, 0);
+  
+  if (!is_overloaded_fn (fns))
+    return error_mark_node;
+  
+  if (really_overloaded_fn (fns))
+    {
+      fn = instantiate_type (type, fns, 0);
+      if (fn == error_mark_node)
+       /* We couldn't resolve the overloading.  */
+       return error_mark_node;
+    }
+  else
+    fn = get_first_fn (fns);
+  
+  my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
+
+  return fn;
+}
+
+
+/* Attempt to convert the non-type template parameter EXPR to the
+   indicated TYPE.  If the conversion is successful, return the
+   converted value.  If the conversion is unsuccesful, return
+   NULL_TREE if we issued an error message, or error_mark_node if we
+   did not.  We issue error messages for out-and-out bad template
+   parameters, but not simply because the conversion failed, since we
+   might be just trying to do argument deduction.  By the time this
+   function is called, neither TYPE nor EXPR may make use of template
+   parameters.  */
+
+static tree
+convert_nontype_parameter (type, expr)
+     tree type;
+     tree expr;
+{
+  tree expr_type = TREE_TYPE (expr);
+
+  /* A template-argument for a non-type, non-template
+     template-parameter shall be one of:
+
+     --an integral constant-expression of integral or enumeration
+     type; or
+     
+     --the name of a non-type template-parameter; or
+     
+     --the name of an object or function with external linkage,
+     including function templates and function template-ids but
+     excluding non- tatic class members, expressed as id-expression;
+     or
+     
+     --the address of an object or function with external linkage,
+     including function templates and function template-ids but
+     excluding non-static class members, expressed as & id-expression
+     where the & is optional if the name refers to a function or
+     array; or
+     
+     --a pointer to member expressed as described in _expr.unary.op_.  */
+
+  if (INTEGRAL_TYPE_P (expr_type) 
+      || TYPE_PTRMEM_P (expr_type) 
+      || TYPE_PTRMEMFUNC_P (expr_type))
+    {
+      if (!TREE_CONSTANT (expr) 
+         /* FIXME: Should this case be handled by fold()?  Why not?  */
+         && !(TREE_CODE (expr) == VAR_DECL && TREE_READONLY (expr)))
+       {
+         cp_error ("non-constant `%E' cannot be used as template argument",
+                   expr);
+         return NULL_TREE;
+       }
+    }
+  else if (TYPE_PTR_P (expr_type) 
+          /* If expr is the address of an overloaded function, we
+             will get the unknown_type_node at this point.  */
+          || expr_type == unknown_type_node)
+    {
+      tree referent;
+
+      if (TREE_CODE (expr) != ADDR_EXPR)
+       {
+       bad_argument:
+         cp_error ("`%E' is not a valid template argument", expr);
+         error ("it must be %s%s with external linkage",
+                TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+                ? "a pointer to " : "",
+                TREE_CODE (TREE_TYPE (TREE_TYPE (expr))) == FUNCTION_TYPE
+                ? "a function" : "an object");
+         return NULL_TREE;
+       }
+
+      referent = TREE_OPERAND (expr, 0);
+      STRIP_NOPS (referent);
+      
+      if (TREE_CODE (referent) == STRING_CST)
+       {
+         cp_error ("string literal %E is not a valid template argument", 
+                   referent);
+         error ("because it is the address of an object with static linkage");
+         return NULL_TREE;
+       }
+
+      if (is_overloaded_fn (referent))
+       /* We'll check that it has external linkage later.  */
+       ;
+      else if (TREE_CODE (referent) != VAR_DECL)
+       goto bad_argument;
+      else if (!TREE_PUBLIC (referent))
+       {
+         cp_error ("address of non-extern `%E' cannot be used as template argument", referent); 
+         return error_mark_node;
+       }
+    }
+  else if (TREE_CODE (expr_type) == VAR_DECL)
+    {
+      if (!TREE_PUBLIC (expr))
+       goto bad_argument;
+    }
+  else if (is_overloaded_fn (expr))
+    /* OK for now.  We'll check that it has external linkage later.  */
+    ;
+  else 
+    {
+      cp_error ("object `%E' cannot be used as template argument", expr);
+      return NULL_TREE;
+    }
+
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+    case BOOLEAN_TYPE:
+    case ENUMERAL_TYPE:
+      /* For a non-type template-parameter of integral or enumeration
+         type, integral promotions (_conv.prom_) and integral
+         conversions (_conv.integral_) are applied. */
+      if (!INTEGRAL_TYPE_P (expr_type))
+       return error_mark_node;
+      
+      /* It's safe to call digest_init in this case; we know we're
+        just converting one integral constant expression to another.  */
+      return digest_init (type, expr, (tree*) 0);
+
+    case POINTER_TYPE:
+      {
+       tree type_pointed_to = TREE_TYPE (type);
+       if (TYPE_PTRMEM_P (type))
+         /* For a non-type template-parameter of type pointer to data
+            member, qualification conversions (_conv.qual_) are
+            applied.  */
+         return perform_qualification_conversions (type, expr);
+       else if (TREE_CODE (type_pointed_to) == FUNCTION_TYPE)
+         { 
+           /* For a non-type template-parameter of type pointer to
+              function, only the function-to-pointer conversion
+              (_conv.func_) is applied.  If the template-argument
+              represents a set of overloaded functions (or a pointer to
+              such), the matching function is selected from the set
+              (_over.over_).  */
+           tree fns;
+           tree fn;
+
+           if (TYPE_PTRFN_P (expr_type) ||
+               expr_type == unknown_type_node)
+             fns = TREE_OPERAND (expr, 0);
+           else
+             fns = expr;
+
+           fn = determine_overloaded_function (type_pointed_to, fns);
+
+           if (fn == error_mark_node)
+             return error_mark_node;
+
+           if (!TREE_PUBLIC (fn))
+             {
+               if (really_overloaded_fn (fns))
+                 return error_mark_node;
+               else
+                 goto bad_argument;
+             }
+
+           expr = build_unary_op (ADDR_EXPR, fn, 0);
+
+           my_friendly_assert (comptypes (type, TREE_TYPE (expr), 1), 
+                               0);
+           return expr;
+         }
+       else 
+         {
+           /* For a non-type template-parameter of type pointer to
+              object, qualification conversions (_conv.qual_) and the
+              array-to-pointer conversion (_conv.array_) are applied.
+              [Note: In particular, neither the null pointer conversion
+              (_conv.ptr_) nor the derived-to-base conversion
+              (_conv.ptr_) are applied.  Although 0 is a valid
+              template-argument for a non-type template-parameter of
+              integral type, it is not a valid template-argument for a
+              non-type template-parameter of pointer type.]  */
+           expr = perform_array_to_pointer_conversion (expr);
+
+           if (expr == error_mark_node)
+             return error_mark_node;
+           else
+             return perform_qualification_conversions (type, expr);
+         }
+      }
+      break;
+
+    case REFERENCE_TYPE:
+      {
+       tree type_referred_to = TREE_TYPE (type);
+
+       if (TREE_CODE (type_referred_to) == FUNCTION_TYPE)
+         {
+           /* For a non-type template-parameter of type reference to
+             function, no conversions apply.  If the
+             template-argument represents a set of overloaded
+             functions, the matching function is selected from the
+             set (_over.over_).  */
+           tree fns = expr;
+           tree fn;
+
+           fn = determine_overloaded_function (type_referred_to, fns);
+
+           if (!TREE_PUBLIC (fn))
+             {
+               if (really_overloaded_fn (fns))
+                 /* Don't issue an error here; we might get a different
+                    function if the overloading had worked out
+                    differently.  */
+                 return error_mark_node;
+               else
+                 goto bad_argument;
+             }
+
+           if (fn == error_mark_node)
+             return error_mark_node;
+
+           my_friendly_assert (comptypes (type, TREE_TYPE (fn), 1),
+                               0);
+
+           return fn;
+         }
+       else
+         {
+           /* For a non-type template-parameter of type reference to
+              object, no conversions apply.  The type referred to by the
+              reference may be more cv-qualified than the (otherwise
+              identical) type of the template-argument.  The
+              template-parameter is bound directly to the
+              template-argument, which must be an lvalue.  */
+           if (!comptypes (TYPE_MAIN_VARIANT (expr_type),
+                           TYPE_MAIN_VARIANT (type), 1)
+               || (TYPE_READONLY (expr_type) >
+                   TYPE_READONLY (type_referred_to))
+               || (TYPE_VOLATILE (expr_type) >
+                   TYPE_VOLATILE (type_referred_to))
+               || !real_lvalue_p (expr))
+             return error_mark_node;
+           else
+             return expr;
+         }
+      }
+      break;
+
+    case RECORD_TYPE:
+      {
+       tree fns;
+       tree fn;
+
+       my_friendly_assert (TYPE_PTRMEMFUNC_P (type), 0);
+
+       /* For a non-type template-parameter of type pointer to member
+          function, no conversions apply.  If the template-argument
+          represents a set of overloaded member functions, the
+          matching member function is selected from the set
+          (_over.over_).  */
+
+       if (!TYPE_PTRMEMFUNC_P (expr_type) && 
+           expr_type != unknown_type_node)
+         return error_mark_node;
+
+       if (TREE_CODE (expr) == CONSTRUCTOR)
+         {
+           /* A ptr-to-member constant.  */
+           if (!comptypes (type, expr_type, 1))
+             return error_mark_node;
+           else 
+             return expr;
+         }
+
+       if (TREE_CODE (expr) != ADDR_EXPR)
+         return error_mark_node;
+
+       fns = TREE_OPERAND (expr, 0);
+       
+       fn = determine_overloaded_function (TREE_TYPE (TREE_TYPE (type)), 
+                                           fns);
+       
+       if (fn == error_mark_node)
+         return error_mark_node;
+
+       expr = build_unary_op (ADDR_EXPR, fn, 0);
+       
+       my_friendly_assert (comptypes (type, TREE_TYPE (expr), 1), 
+                           0);
+       return expr;
+      }
+      break;
+
+    default:
+      /* All non-type parameters must have one of these types.  */
+      my_friendly_abort (0);
+      break;
+    }
+
+  return error_mark_node;
+}
+
 /* Convert all template arguments to their appropriate types, and return
    a vector containing the resulting values.  If any error occurs, return
-   error_mark_node.  */
+   error_mark_node, and, if COMPLAIN is non-zero, issue an error message.
+   Some error messages are issued even if COMPLAIN is zero; for
+   instance, if a template argument is composed from a local class. 
+
+   If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
+   provided in ARGLIST, or else trailing parameters must have default
+   values.  If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
+   deduction for any unspecified trailing arguments.  */
 
 static tree
-coerce_template_parms (parms, arglist, in_decl)
+coerce_template_parms (parms, arglist, in_decl,
+                      complain,
+                      require_all_arguments)
      tree parms, arglist;
      tree in_decl;
+     int complain;
+     int require_all_arguments;
 {
   int nparms, nargs, i, lost = 0;
-  tree vec;
+  tree vec = NULL_TREE;
 
   if (arglist == NULL_TREE)
     nargs = 0;
@@ -983,12 +1650,19 @@ coerce_template_parms (parms, arglist, in_decl)
 
   if (nargs > nparms
       || (nargs < nparms
+         && require_all_arguments
          && TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)) == NULL_TREE))
     {
-      error ("incorrect number of parameters (%d, should be %d)",
-            nargs, nparms);
-      if (in_decl)
-       cp_error_at ("in template expansion for decl `%D'", in_decl);
+      if (complain) 
+       {
+         error ("incorrect number of parameters (%d, should be %d)",
+                nargs, nparms);
+         
+         if (in_decl)
+           cp_error_at ("in template expansion for decl `%D'",
+                        in_decl);
+       }
+
       return error_mark_node;
     }
 
@@ -997,9 +1671,11 @@ coerce_template_parms (parms, arglist, in_decl)
   else
     {
       vec = make_tree_vec (nparms);
+
       for (i = 0; i < nparms; i++)
        {
          tree arg;
+         tree parm = TREE_VEC_ELT (parms, i);
 
          if (arglist)
            {
@@ -1011,13 +1687,15 @@ coerce_template_parms (parms, arglist, in_decl)
              else
                arg = TREE_VALUE (arg);
            }
-         else if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (parms, i)))
-                  == TYPE_DECL)
-           arg = tsubst (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
-                         vec, i, in_decl);
+         else if (TREE_PURPOSE (parm) == NULL_TREE)
+           {
+             my_friendly_assert (!require_all_arguments, 0);
+             break;
+           }
+         else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL)
+           arg = tsubst (TREE_PURPOSE (parm), vec, i, in_decl);
          else
-           arg = tsubst_expr (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
-                              vec, i, in_decl);
+           arg = tsubst_expr (TREE_PURPOSE (parm), vec, i, in_decl);
 
          TREE_VEC_ELT (vec, i) = arg;
        }
@@ -1029,6 +1707,20 @@ coerce_template_parms (parms, arglist, in_decl)
       tree val = 0;
       int is_type, requires_type;
 
+      if (arg == NULL_TREE)
+       /* We're out of arguments.  */
+       {
+         my_friendly_assert (!require_all_arguments, 0);
+         break;
+       }
+
+      if (arg == error_mark_node)
+       {
+         cp_error ("template argument %d is invalid", i + 1);
+         lost++;
+         continue;
+       }
+
       is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't';
       requires_type = TREE_CODE (parm) == TYPE_DECL;
 
@@ -1037,6 +1729,7 @@ coerce_template_parms (parms, arglist, in_decl)
        {
          cp_pedwarn ("to refer to a type member of a template parameter,");
          cp_pedwarn ("  use `typename %E'", arg);
+
          arg = make_typename_type (TREE_OPERAND (arg, 0),
                                    TREE_OPERAND (arg, 1));
          is_type = 1;
@@ -1045,13 +1738,16 @@ coerce_template_parms (parms, arglist, in_decl)
        {
          if (in_decl)
            {
-             cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
-                       i, in_decl);
-             if (is_type)
-               cp_error ("  expected a constant of type `%T', got `%T'",
-                         TREE_TYPE (parm), arg);
-             else
-               cp_error ("  expected a type, got `%E'", arg);
+             if (complain)
+               {
+                 cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
+                           i + 1, in_decl);
+                 if (is_type)
+                   cp_error ("  expected a constant of type `%T', got `%T'",
+                             TREE_TYPE (parm), arg);
+                 else
+                   cp_error ("  expected a type, got `%E'", arg);
+               }
            }
          lost++;
          TREE_VEC_ELT (vec, i) = error_mark_node;
@@ -1076,70 +1772,30 @@ coerce_template_parms (parms, arglist, in_decl)
        {
          tree t = tsubst (TREE_TYPE (parm), vec,
                           TREE_VEC_LENGTH (vec), in_decl);
+
          if (processing_template_decl)
-           val = maybe_fold_nontype_arg (arg);
+           arg = maybe_fold_nontype_arg (arg);
+
+         if (!uses_template_parms (arg) && !uses_template_parms (t))
+           /* We used to call digest_init here.  However, digest_init
+              will report errors, which we don't want when complain
+              is zero.  More importantly, digest_init will try too
+              hard to convert things: for example, `0' should not be
+              converted to pointer type at this point according to
+              the standard.  Accepting this is not merely an
+              extension, since deciding whether or not these
+              conversions can occur is part of determining which
+              function template to call, or whether a given epxlicit
+              argument specification is legal.  */
+           val = convert_nontype_parameter (t, arg);
          else
            val = arg;
 
-         if (!uses_template_parms (val) && !uses_template_parms (t))
-           val = digest_init (t, val, (tree *) 0);
-
-         if (val == error_mark_node 
-             || (processing_template_decl && uses_template_parms (val)))
-           ;
-
-         /* 14.2: Other template-arguments must be constant-expressions,
-            addresses of objects or functions with external linkage, or of
-            static class members.  */
-         else if (IS_AGGR_TYPE (TREE_TYPE (val)))
-           {
-             cp_error ("object `%E' cannot be used as template argument", arg);
-             val = error_mark_node;
-           }
-         else if (!TREE_CONSTANT (val))
-           {
-             cp_error ("non-constant `%E' cannot be used as template argument",
-                       arg);
-             val = error_mark_node;
-           }
-         else if (POINTER_TYPE_P (TREE_TYPE (val))
-                  && ! integer_zerop (val)
-                  && TREE_CODE (TREE_TYPE (TREE_TYPE (val))) != OFFSET_TYPE
-                  && TREE_CODE (TREE_TYPE (TREE_TYPE (val))) != METHOD_TYPE)
-           {
-             t = val;
-             STRIP_NOPS (t);
-             if (TREE_CODE (t) == ADDR_EXPR)
-               {
-                 tree a = TREE_OPERAND (t, 0);
-                 STRIP_NOPS (a);
-                 if (TREE_CODE (a) == STRING_CST)
-                   {
-                     cp_error ("string literal %E is not a valid template argument", a);
-                     error ("because it is the address of an object with static linkage");
-                     val = error_mark_node;
-                   }
-                 else if (TREE_CODE (a) != VAR_DECL
-                          && TREE_CODE (a) != FUNCTION_DECL)
-                   goto bad;
-                 else if (! TREE_PUBLIC (a))
-                   {
-                     cp_error ("address of non-extern `%E' cannot be used as template argument", a);
-                     val = error_mark_node;
-                   }
-               }
-             else
-               {
-               bad:
-                 cp_error ("`%E' is not a valid template argument", t);
-                 error ("it must be %s%s with external linkage",
-                        TREE_CODE (TREE_TYPE (val)) == POINTER_TYPE
-                        ? "a pointer to " : "",
-                        TREE_CODE (TREE_TYPE (TREE_TYPE (val))) == FUNCTION_TYPE
-                        ? "a function" : "an object");
-                 val = error_mark_node;
-               }
-           }
+         if (val == NULL_TREE)
+           val = error_mark_node;
+         else if (val == error_mark_node && complain)
+           cp_error ("could not convert template argument `%E' to `%T'", 
+                     arg, t);
        }
 
       if (val == error_mark_node)
@@ -1192,9 +1848,10 @@ comp_template_args (oldargs, newargs)
    for the instantiation.  */
 
 static char *
-mangle_class_name_for_template (name, parms, arglist)
+mangle_class_name_for_template (name, parms, arglist, ctx)
      char *name;
      tree parms, arglist;
+     tree ctx;
 {
   static struct obstack scratch_obstack;
   static char *scratch_firstobj;
@@ -1219,6 +1876,12 @@ mangle_class_name_for_template (name, parms, arglist)
 #define cat(s) obstack_grow (&scratch_obstack, (s), strlen (s))
 #endif
 
+  if (ctx)
+    {
+      char* s = fndecl_as_string(ctx, 0);
+      cat (s);
+      cat ("::");
+    }
   cat (name);
   ccat ('<');
   nparms = TREE_VEC_LENGTH (parms);
@@ -1284,7 +1947,9 @@ classtype_mangled_name (t)
       char *mangled_name = mangle_class_name_for_template
        (IDENTIFIER_POINTER (name),
         DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (t)),
-        CLASSTYPE_TI_ARGS (t));
+        CLASSTYPE_TI_ARGS (t), 
+        (DECL_CONTEXT (t) && TREE_CODE (t) == FUNCTION_DECL) ? 
+        DECL_CONTEXT (t) : NULL_TREE);
       tree id = get_identifier (mangled_name);
       IDENTIFIER_TEMPLATE (id) = name;
       return id;
@@ -1346,12 +2011,17 @@ lookup_template_function (fns, arglist)
    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.  */
+   instantiate.  
+
+   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)
+lookup_template_class (d1, arglist, in_decl, function_context)
      tree d1, arglist;
      tree in_decl;
+     tree function_context;
 {
   tree template, parmlist;
   char *mangled_name;
@@ -1394,7 +2064,8 @@ lookup_template_class (d1, arglist, in_decl)
     {
       parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
 
-      arglist = coerce_template_parms (parmlist, arglist, template);
+      arglist = coerce_template_parms (parmlist, arglist, template,
+                                      1, 1);
       if (arglist == error_mark_node)
        return error_mark_node;
       if (uses_template_parms (arglist))
@@ -1425,18 +2096,35 @@ lookup_template_class (d1, arglist, in_decl)
        }
 
       mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
-                                                    parmlist, arglist);
+                                                    parmlist,
+                                                    arglist,
+                                                    function_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 (function_context != NULL_TREE)
+       {
+         /* 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) = function_context;
+         DECL_CONTEXT (type_decl) = function_context;
+         DECL_ASSEMBLER_NAME (type_decl) = DECL_NAME (type_decl);
+         DECL_ASSEMBLER_NAME (type_decl) = 
+           get_identifier (build_overload_name (t, 1, 1));
+       }
+
       pop_from_top_level ();
     }
   else
     {
       tree ctx = lookup_template_class (TYPE_CONTEXT (TREE_TYPE (template)),
-                                       arglist, in_decl);
+                                       arglist, in_decl, NULL_TREE);
       id = d1;
       arglist = CLASSTYPE_TI_ARGS (ctx);
 
@@ -2114,7 +2802,15 @@ tsubst (t, args, nargs, in_decl)
       if (uses_template_parms (t))
        {
          tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, nargs, in_decl);
-         tree r = lookup_template_class (t, argvec, in_decl);
+         tree context;
+         tree r;
+
+         context = (TYPE_CONTEXT (t) 
+                    && TREE_CODE (TYPE_CONTEXT (t)) == FUNCTION_DECL)
+           ? tsubst (TYPE_CONTEXT (t), args, nargs, in_decl) : NULL_TREE;
+
+         r = lookup_template_class (t, argvec, in_decl, context);
+
          return cp_build_type_variant (r, TYPE_READONLY (t),
                                        TYPE_VOLATILE (t));
        }
@@ -2230,12 +2926,9 @@ tsubst (t, args, nargs, in_decl)
        int i;
 
        /* We might already have an instance of this template. */
-       tree instances = DECL_TEMPLATE_INSTANTIATIONS (t);
-       tree ctx = tsubst (DECL_CLASS_CONTEXT (t), args, nargs, in_decl); 
-         
-       for (; instances; instances = TREE_CHAIN (instances))
-         if (DECL_CLASS_CONTEXT (TREE_VALUE (instances)) == ctx)
-           return TREE_VALUE (instances);
+       spec = retrieve_specialization (t, args);
+       if (spec != NULL_TREE)
+         return spec;
 
        /* Make a new template decl.  It will be similar to the
           original, but will record the current template arguments. 
@@ -2265,12 +2958,64 @@ tsubst (t, args, nargs, in_decl)
             parms = TREE_CHAIN (parms))
          TREE_CHAIN (parms) = copy_node (TREE_CHAIN (parms));
 
-       /* Record this partial instantiation. */
-       DECL_TEMPLATE_INSTANTIATIONS (t)
-         = perm_tree_cons (NULL_TREE, tmpl,
-                           DECL_TEMPLATE_INSTANTIATIONS (t));
-
+       /* 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))
+         {
+           /* It helps to consider example here.  Consider:
+
+              template <class T>
+              struct S {
+                template <class U>
+                void f(U u);
+
+                template <>
+                void f(T* t) {}
+              };
+              
+              Now, for example, we are instantiating S<int>::f(U u).  
+              We want to make a template:
+
+              template <class U>
+              void S<int>::f(U);
+
+              It will have a specialization, for the case U = int*, of
+              the form:
+
+              template <>
+              void S<int>::f<int*>(int*);
+
+              This specialization will be an instantiation of
+              the specialization given in the declaration of S, with
+              argument list int*.  */
+
+           tree fn = TREE_VALUE (spec);
+           tree spec_args;
+           tree new_fn;
+
+           if (!DECL_TEMPLATE_SPECIALIZATION (fn))
+             /* Instantiations are on the same list, but they're of
+                no concern to us.  */
+             continue;
+
+           spec_args = tsubst (DECL_TI_ARGS (fn), args, nargs,
+                               in_decl); 
+           new_fn = tsubst (DECL_RESULT (fn), args, nargs,
+                            in_decl); 
+           DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = 
+             perm_tree_cons (spec_args, new_fn, 
+                             DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+         }
+
+       /* Record this partial instantiation.  */
+       register_specialization (tmpl, t, args);
+
        return tmpl;
       }
 
@@ -2302,13 +3047,10 @@ tsubst (t, args, nargs, in_decl)
        if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
          {
            tree tmpl = DECL_TI_TEMPLATE (t);
-           tree decls = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
+           tree spec = retrieve_specialization (tmpl, args);
 
-           for (; decls; decls = TREE_CHAIN (decls))
-             if (TREE_TYPE (TREE_VALUE (decls)) == type
-                 && DECL_CLASS_CONTEXT (TREE_VALUE (decls)) == ctx
-                 && comp_template_args (TREE_PURPOSE (decls), args))
-               return TREE_VALUE (decls);
+           if (spec)
+             return spec;
          }
 
        /* We do NOT check for matching decls pushed separately at this
@@ -2390,16 +3132,46 @@ tsubst (t, args, nargs, in_decl)
                   we re-use the parms from the original template, which
                   have level 2.  When this is fixed we can remove the
                   add_to_template_args from instantiate_template.  */
-               tree tparms = DECL_TEMPLATE_PARMS (tmpl);
-
-               while (tparms && TREE_CHAIN (tparms) != NULL_TREE)
-                 tparms = TREE_CHAIN (tparms);
-
+               tree tparms;
+               tree targs;
+
+               if (!DECL_TEMPLATE_SPECIALIZATION (tmpl)) 
+                 {
+                   tparms = DECL_TEMPLATE_PARMS (tmpl);
+
+                   while (tparms && TREE_CHAIN (tparms) != NULL_TREE)
+                     tparms = TREE_CHAIN (tparms);
+                   
+                   targs = 
+                     (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC 
+                      ? TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1)
+                      : args); 
+                 }
+               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 
@@ -2410,11 +3182,7 @@ tsubst (t, args, nargs, in_decl)
                  = build_template_decl_overload 
                  (DECL_NAME (r), arg_types, 
                   TREE_TYPE (TREE_TYPE (tmpl)),
-                  tparms,
-                  TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC 
-                  ? TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1) :
-                  args, 
-                  member);
+                  tparms, targs, member);
              }
          }
        DECL_RTL (r) = 0;
@@ -2426,7 +3194,7 @@ tsubst (t, args, nargs, in_decl)
        DECL_INITIAL (r) = NULL_TREE;
 
        TREE_STATIC (r) = 0;
-       TREE_PUBLIC (r) = 1;
+       TREE_PUBLIC (r) = TREE_PUBLIC (t);
        DECL_EXTERNAL (r) = 1;
        DECL_INTERFACE_KNOWN (r) = 0;
        DECL_DEFER_OUTPUT (r) = 0;
@@ -2471,22 +3239,32 @@ tsubst (t, args, nargs, in_decl)
        if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
          {
            tree tmpl = DECL_TI_TEMPLATE (t);
-           tree *declsp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
            tree argvec = tsubst (DECL_TI_ARGS (t), args, nargs, in_decl);
 
            if (DECL_TEMPLATE_INFO (tmpl) && DECL_TI_ARGS (tmpl))
-             argvec = add_to_template_args (DECL_TI_ARGS (tmpl), argvec);
+             {
+               if (!DECL_TEMPLATE_SPECIALIZATION (tmpl))
+                 argvec = add_to_template_args (DECL_TI_ARGS (tmpl), argvec);
+               else
+                 /* In this case, we are instantiating a
+                    specialization.  The innermost template args are
+                    already given by the specialization.  */
+                 argvec = add_to_template_args (argvec, DECL_TI_ARGS (tmpl));
+             }
 
            DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
-           *declsp = perm_tree_cons (argvec, r, *declsp);
 
            /* If we have a preexisting version of this function, don't expand
               the template version, use the other instead.  */
-           if (TREE_STATIC (r) || DECL_TEMPLATE_SPECIALIZATION (r))
+           if (TREE_STATIC (r) || 
+               (DECL_TEMPLATE_SPECIALIZATION (r) &&
+                /* FIXME: Explain this condition.  */
+                !DECL_TEMPLATE_SPECIALIZATION (tmpl)))
              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
@@ -3469,14 +4247,11 @@ instantiate_template (tmpl, targ_ptr)
 
   if (DECL_FUNCTION_TEMPLATE_P (tmpl))
     {
-      tree specs;
+      /* Check to see if we already have this specialization.  */
+      tree spec = retrieve_specialization (tmpl, targ_ptr);
       
-      /* Check to see if there is a matching specialization. */
-      for (specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
-          specs != NULL_TREE;
-          specs = TREE_CHAIN (specs))
-       if (comp_template_args (TREE_PURPOSE (specs), targ_ptr))
-         return TREE_VALUE (specs);
+      if (spec != NULL_TREE)
+       return spec;
     }
 
   push_obstacks (&permanent_obstack, &permanent_obstack);
@@ -3605,22 +4380,38 @@ type_unification (tparms, targs, parms, args, targs_in, nsubsts,
      int *nsubsts, strict, allow_incomplete;
 {
   int ntparms = TREE_VEC_LENGTH (tparms);
-  tree t;
+  tree arg;
+  tree parm;
   int i;
   int r;
 
   bzero ((char *) targs, sizeof (tree) * ntparms);
 
-  /* Insert any explicit template arguments.  They are encoded as the
-     operands of NOP_EXPRs so that unify can tell that they are
-     explicit arguments.  */
-  for (i = 0, t = targs_in; t != NULL_TREE; t = TREE_CHAIN (t), ++i)
-    targs[i] = build1 (NOP_EXPR, NULL_TREE, TREE_VALUE (t));
+  if (targs_in != NULL_TREE)
+    {
+      tree arg_vec;
+      arg_vec = coerce_template_parms (tparms, targs_in, NULL_TREE, 0,
+                                      0);
+
+      if (arg_vec == error_mark_node)
+       return 1;
 
+      for (i = 0; 
+          i < TREE_VEC_LENGTH (arg_vec) 
+            && TREE_VEC_ELT (arg_vec, i) != NULL_TREE; 
+          ++i)
+       /* Insert the template argument.  It is encoded as the operands
+          of NOP_EXPRs so that unify can tell that it is an explicit
+          arguments.  */
+       targs[i] = build1 (NOP_EXPR, NULL_TREE, TREE_VEC_ELT (arg_vec, i));
+    }
+  
   r = type_unification_real (tparms, targs, parms, args, nsubsts, 0,
                             strict, allow_incomplete); 
 
-  for (i = 0, t = targs_in; t != NULL_TREE; t = TREE_CHAIN (t), ++i)
+  for (i = 0, arg = targs_in; 
+       arg != NULL_TREE; 
+       arg = TREE_CHAIN (arg), ++i)
     if (TREE_CODE (targs[i]) == NOP_EXPR)
       targs[i] = TREE_OPERAND (targs[i], 0);
 
@@ -4032,7 +4823,11 @@ mark_decl_instantiated (result, extern_p)
 {
   if (DECL_TEMPLATE_INSTANTIATION (result))
     SET_DECL_EXPLICIT_INSTANTIATION (result);
-  TREE_PUBLIC (result) = 1;
+
+  if (TREE_CODE (result) != FUNCTION_DECL)
+    /* The TREE_PUBLIC flag for function declarations will have been
+       set correctly by tsubst.  */
+    TREE_PUBLIC (result) = 1;
 
   if (! extern_p)
     {
@@ -4041,7 +4836,7 @@ mark_decl_instantiated (result, extern_p)
 
       /* For WIN32 we also want to put explicit instantiations in
         linkonce sections.  */
-      if (supports_one_only () && ! SUPPORTS_WEAK)
+      if (supports_one_only () && ! SUPPORTS_WEAK && TREE_PUBLIC (result))
        make_decl_one_only (result);
     }
   else if (TREE_CODE (result) == FUNCTION_DECL)
@@ -4290,11 +5085,12 @@ do_decl_instantiation (declspecs, declarator, storage)
     }
   else if (DECL_FUNCTION_MEMBER_P (decl))
     {
-      if (DECL_TEMPLATE_INSTANTIATION (decl))
+      if (DECL_TEMPLATE_INSTANTIATION (decl) && DECL_RTL (decl))
        result = decl;
       else if (name = DECL_ASSEMBLER_NAME (decl),
               fn = IDENTIFIER_GLOBAL_VALUE (name),
-              fn && DECL_TEMPLATE_INSTANTIATION (fn))
+              fn && DECL_TEMPLATE_INSTANTIATION (fn)
+              && DECL_RTL (fn))
        result = fn;
       else 
        {
@@ -4517,14 +5313,11 @@ instantiate_decl (d)
 
   if (TREE_CODE (d) == FUNCTION_DECL) 
     {
-      tree specs;
-
-      /* Check to see if there is a matching specialization. */
-      for (specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
-          specs != NULL_TREE;
-          specs = TREE_CHAIN (specs))
-       if (comp_template_args (TREE_PURPOSE (specs), args))
-         return TREE_VALUE (specs);
+      tree spec = retrieve_specialization (tmpl, args);
+      
+      if (spec != NULL_TREE 
+         && DECL_TEMPLATE_SPECIALIZATION (spec))
+       return spec;
     }
 
   /* This needs to happen before any tsubsting.  */
@@ -4727,6 +5520,24 @@ add_tree (t)
   last_tree = TREE_CHAIN (last_tree) = t;
 }
 
+
+void
+begin_tree ()
+{
+  saved_trees = tree_cons (NULL_TREE, last_tree, saved_trees);
+  last_tree = NULL_TREE;
+}
+
+
+void 
+end_tree ()
+{
+  my_friendly_assert (saved_trees != NULL_TREE, 0);
+
+  last_tree = TREE_VALUE (saved_trees);
+  saved_trees = TREE_CHAIN (saved_trees);
+}
+
 /* D is an undefined function declaration in the presence of templates with
    the same name, listed in FNS.  If one of them can produce D as an
    instantiation, remember this so we can instantiate it at EOF if D has
index 6b8c54e88dcdcdbfd8438b0e2e6e0755733addc3..365ee4d8d2dabfa9b2f2fdc43fa09954d4dde598 100644 (file)
@@ -1464,7 +1464,11 @@ mapcar (t, func)
     case VAR_DECL:
     case FUNCTION_DECL:
     case CONST_DECL:
-      break;
+      /* Rather than aborting, return error_mark_node.  This allows us
+        to report a sensible error message on code like this:
+
+        void g() { int i; f<i>(7); } */
+      return error_mark_node;
 
     case PARM_DECL:
       {
index 993835556623783be03d895c7fc227ba2dcec3fe..e3c426d9a325bbdc11380aa9565372db7c0f13a4 100644 (file)
@@ -4481,9 +4481,11 @@ build_unary_op (code, xarg, noconvert)
          /* We don't require a match here; it's possible that the
             context (like a cast to a particular type) will resolve
             the particular choice of template.  */
-         fn = determine_explicit_specialization (arg, NULL_TREE,
-                                                 &targs,
-                                                 0, 0);
+         fn = determine_specialization (arg,
+                                        NULL_TREE,
+                                        &targs, 
+                                        0, 
+                                        0);
 
          if (fn)
            {
index e867e447fb3f8688b3f182db0e5bb8735bc674da..92cbcc34aa8e0139793d931131185d0463e1c116 100644 (file)
@@ -247,6 +247,10 @@ incomplete_type_error (value, type)
          error ("invalid use of member type (did you forget the `&' ?)");
          return;
 
+       case TEMPLATE_TYPE_PARM:
+         error ("invalid use of template type parameter");
+         return;
+
        default:
          my_friendly_abort (108);
        }
This page took 0.16372 seconds and 5 git commands to generate.