X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=blobdiff_plain;f=gcc%2Fcp%2Fpt.c;fp=gcc%2Fcp%2Fpt.c;h=84820c9d3d143920cd7b96ef3f00b09d449574ff;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=a2fed22b77455b484976a25c5df9426ba60c1304;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a2fed22b..84820c9d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1,25 +1,25 @@ /* Handle parameterized types (templates) for GNU C++. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + Free Software Foundation, Inc. Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing. Rewritten by Jason Merrill (jason@cygnus.com). -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify +GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) +the Free Software Foundation; either version 3, or (at your option) any later version. -GNU CC is distributed in the hope that it will be useful, +GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* Known bugs or deficiencies include: @@ -28,53 +28,65 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "obstack.h" #include "tree.h" +#include "pointer-set.h" #include "flags.h" +#include "c-common.h" #include "cp-tree.h" +#include "cp-objcp-common.h" #include "tree-inline.h" #include "decl.h" -#include "parse.h" -#include "lex.h" #include "output.h" #include "except.h" #include "toplev.h" #include "rtl.h" -#include "ggc.h" #include "timevar.h" +#include "tree-iterator.h" +#include "vecprim.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ -typedef int (*tree_fn_t) PARAMS ((tree, void*)); - -extern struct obstack permanent_obstack; +typedef int (*tree_fn_t) (tree, void*); /* The PENDING_TEMPLATES is a TREE_LIST of templates whose instantiations have been deferred, either because their definitions - were not yet available, or because we were putting off doing the - work. The TREE_PURPOSE of each entry is a SRCLOC indicating where - the instantiate request occurred; the TREE_VALUE is a either a DECL - (for a function or static data member), or a TYPE (for a class) - indicating what we are hoping to instantiate. */ -static tree pending_templates; -static tree last_pending_template; + were not yet available, or because we were putting off doing the work. */ +struct pending_template GTY (()) { + struct pending_template *next; + struct tinst_level *tinst; +}; + +static GTY(()) struct pending_template *pending_templates; +static GTY(()) struct pending_template *last_pending_template; int processing_template_parmlist; static int template_header_count; -static tree saved_trees; -static varray_type inline_parm_levels; -static size_t inline_parm_levels_used; +static GTY(()) tree saved_trees; +static VEC(int,heap) *inline_parm_levels; + +static GTY(()) struct tinst_level *current_tinst_level; -static tree current_tinst_level; +static GTY(()) tree saved_access_scope; + +/* Live only within one (recursive) call to tsubst_expr. We use + this to pass the statement expression node from the STMT_EXPR + to the EXPR_STMT that is its result. */ +static tree cur_stmt_expr; /* A map from local variable declarations in the body of the template presently being instantiated to the corresponding instantiated local variables. */ static htab_t local_specializations; -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free +/* Contains canonical template parameter types. The vector is indexed by + the TEMPLATE_TYPE_IDX of the template parameter. Each element is a + TREE_LIST, whose TREE_VALUEs contain the canonical template + parameters of various types and levels. */ +static GTY(()) VEC(tree,gc) *canonical_template_parms; #define UNIFY_ALLOW_NONE 0 #define UNIFY_ALLOW_MORE_CV_QUAL 1 @@ -84,132 +96,164 @@ static htab_t local_specializations; #define UNIFY_ALLOW_OUTER_LEVEL 16 #define UNIFY_ALLOW_OUTER_MORE_CV_QUAL 32 #define UNIFY_ALLOW_OUTER_LESS_CV_QUAL 64 -#define UNIFY_ALLOW_MAX_CORRECTION 128 - -#define GTB_VIA_VIRTUAL 1 /* The base class we are examining is - virtual, or a base class of a virtual - base. */ -#define GTB_IGNORE_TYPE 2 /* We don't need to try to unify the current - type with the desired type. */ - -static int resolve_overloaded_unification PARAMS ((tree, tree, tree, tree, - unification_kind_t, int)); -static int try_one_overload PARAMS ((tree, tree, tree, tree, tree, - unification_kind_t, int)); -static int unify PARAMS ((tree, tree, tree, tree, int)); -static void add_pending_template PARAMS ((tree)); -static void reopen_tinst_level PARAMS ((tree)); -static tree classtype_mangled_name PARAMS ((tree)); -static char *mangle_class_name_for_template PARAMS ((const char *, - tree, tree)); -static tree tsubst_initializer_list PARAMS ((tree, tree)); -static int list_eq PARAMS ((tree, tree)); -static tree get_class_bindings PARAMS ((tree, tree, tree)); -static tree coerce_template_parms PARAMS ((tree, tree, tree, - tsubst_flags_t, int)); -static void tsubst_enum PARAMS ((tree, tree, tree)); -static tree add_to_template_args PARAMS ((tree, tree)); -static tree add_outermost_template_args PARAMS ((tree, tree)); -static int maybe_adjust_types_for_deduction PARAMS ((unification_kind_t, tree*, - tree*)); -static int type_unification_real PARAMS ((tree, tree, tree, tree, - int, unification_kind_t, int, int)); -static void note_template_header PARAMS ((int)); -static tree maybe_fold_nontype_arg PARAMS ((tree)); -static tree convert_nontype_argument PARAMS ((tree, tree)); -static tree convert_template_argument PARAMS ((tree, tree, tree, - tsubst_flags_t, int, tree)); -static tree get_bindings_overload PARAMS ((tree, tree, tree)); -static int for_each_template_parm PARAMS ((tree, tree_fn_t, void*)); -static tree build_template_parm_index PARAMS ((int, int, int, tree, tree)); -static int inline_needs_template_parms PARAMS ((tree)); -static void push_inline_template_parms_recursive PARAMS ((tree, int)); -static tree retrieve_specialization PARAMS ((tree, tree)); -static tree retrieve_local_specialization PARAMS ((tree)); -static tree register_specialization PARAMS ((tree, tree, tree)); -static void register_local_specialization PARAMS ((tree, tree)); -static int unregister_specialization PARAMS ((tree, tree)); -static tree reduce_template_parm_level PARAMS ((tree, tree, int)); -static tree build_template_decl PARAMS ((tree, tree)); -static int mark_template_parm PARAMS ((tree, void *)); -static tree tsubst_friend_function PARAMS ((tree, tree)); -static tree tsubst_friend_class PARAMS ((tree, tree)); -static int can_complete_type_without_circularity PARAMS ((tree)); -static tree get_bindings_real PARAMS ((tree, tree, tree, int, int, int)); -static int template_decl_level PARAMS ((tree)); -static tree maybe_get_template_decl_from_type_decl PARAMS ((tree)); -static int check_cv_quals_for_unify PARAMS ((int, tree, tree)); -static tree tsubst_template_arg_vector PARAMS ((tree, tree, tsubst_flags_t)); -static tree tsubst_template_parms PARAMS ((tree, tree, tsubst_flags_t)); -static void regenerate_decl_from_template PARAMS ((tree, tree)); -static tree most_specialized PARAMS ((tree, tree, tree)); -static tree most_specialized_class PARAMS ((tree, tree)); -static int template_class_depth_real PARAMS ((tree, int)); -static tree tsubst_aggr_type PARAMS ((tree, tree, tsubst_flags_t, tree, int)); -static tree tsubst_decl PARAMS ((tree, tree, tree, tsubst_flags_t)); -static tree tsubst_arg_types PARAMS ((tree, tree, tsubst_flags_t, tree)); -static tree tsubst_function_type PARAMS ((tree, tree, tsubst_flags_t, tree)); -static void check_specialization_scope PARAMS ((void)); -static tree process_partial_specialization PARAMS ((tree)); -static void set_current_access_from_decl PARAMS ((tree)); -static void check_default_tmpl_args PARAMS ((tree, tree, int, int)); -static tree tsubst_call_declarator_parms PARAMS ((tree, tree, - tsubst_flags_t, tree)); -static tree get_template_base_recursive PARAMS ((tree, tree, - tree, tree, tree, int)); -static tree get_template_base PARAMS ((tree, tree, tree, tree)); -static int verify_class_unification PARAMS ((tree, tree, tree)); -static tree try_class_unification PARAMS ((tree, tree, tree, tree)); -static int coerce_template_template_parms PARAMS ((tree, tree, tsubst_flags_t, - tree, tree)); -static tree determine_specialization PARAMS ((tree, tree, tree *, int)); -static int template_args_equal PARAMS ((tree, tree)); -static void tsubst_default_arguments PARAMS ((tree)); -static tree for_each_template_parm_r PARAMS ((tree *, int *, void *)); -static tree copy_default_args_to_explicit_spec_1 PARAMS ((tree, tree)); -static void copy_default_args_to_explicit_spec PARAMS ((tree)); -static int invalid_nontype_parm_type_p PARAMS ((tree, tsubst_flags_t)); - -/* Called once to initialize pt.c. */ -void -init_pt () +static void push_access_scope (tree); +static void pop_access_scope (tree); +static bool resolve_overloaded_unification (tree, tree, tree, tree, + unification_kind_t, int); +static int try_one_overload (tree, tree, tree, tree, tree, + unification_kind_t, int, bool); +static int unify (tree, tree, tree, tree, int); +static void add_pending_template (tree); +static int push_tinst_level (tree); +static void pop_tinst_level (void); +static tree reopen_tinst_level (struct tinst_level *); +static tree tsubst_initializer_list (tree, tree); +static tree get_class_bindings (tree, tree, tree); +static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t, + bool, bool); +static void tsubst_enum (tree, tree, tree); +static tree add_to_template_args (tree, tree); +static tree add_outermost_template_args (tree, tree); +static bool check_instantiated_args (tree, tree, tsubst_flags_t); +static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*, + tree); +static int type_unification_real (tree, tree, tree, tree, + int, unification_kind_t, int); +static void note_template_header (int); +static tree convert_nontype_argument_function (tree, tree); +static tree convert_nontype_argument (tree, tree); +static tree convert_template_argument (tree, tree, tree, + tsubst_flags_t, int, tree); +static int for_each_template_parm (tree, tree_fn_t, void*, + struct pointer_set_t*, bool); +static tree expand_template_argument_pack (tree); +static tree build_template_parm_index (int, int, int, tree, tree); +static bool inline_needs_template_parms (tree); +static void push_inline_template_parms_recursive (tree, int); +static tree retrieve_local_specialization (tree); +static void register_local_specialization (tree, tree); +static tree reduce_template_parm_level (tree, tree, int, tree, tsubst_flags_t); +static int mark_template_parm (tree, void *); +static int template_parm_this_level_p (tree, void *); +static tree tsubst_friend_function (tree, tree); +static tree tsubst_friend_class (tree, tree); +static int can_complete_type_without_circularity (tree); +static tree get_bindings (tree, tree, tree, bool); +static int template_decl_level (tree); +static int check_cv_quals_for_unify (int, tree, tree); +static void template_parm_level_and_index (tree, int*, int*); +static int unify_pack_expansion (tree, tree, tree, tree, int, bool, bool); +static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree); +static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree); +static tree tsubst_template_parms (tree, tree, tsubst_flags_t); +static void regenerate_decl_from_template (tree, tree); +static tree most_specialized_class (tree, tree); +static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int); +static tree tsubst_arg_types (tree, tree, tsubst_flags_t, tree); +static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree); +static bool check_specialization_scope (void); +static tree process_partial_specialization (tree); +static void set_current_access_from_decl (tree); +static tree get_template_base (tree, tree, tree, tree); +static tree try_class_unification (tree, tree, tree, tree); +static int coerce_template_template_parms (tree, tree, tsubst_flags_t, + tree, tree); +static bool template_template_parm_bindings_ok_p (tree, tree); +static int template_args_equal (tree, tree); +static void tsubst_default_arguments (tree); +static tree for_each_template_parm_r (tree *, int *, void *); +static tree copy_default_args_to_explicit_spec_1 (tree, tree); +static void copy_default_args_to_explicit_spec (tree); +static int invalid_nontype_parm_type_p (tree, tsubst_flags_t); +static int eq_local_specializations (const void *, const void *); +static bool dependent_template_arg_p (tree); +static bool any_template_arguments_need_structural_equality_p (tree); +static bool dependent_type_p_r (tree); +static tree tsubst (tree, tree, tsubst_flags_t, tree); +static tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool); +static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); +static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree); +static tree tsubst_decl (tree, tree, tsubst_flags_t); +static tree listify (tree); +static tree listify_autos (tree, tree); + +/* Make the current scope suitable for access checking when we are + processing T. T can be FUNCTION_DECL for instantiated function + template, or VAR_DECL for static member variable (need by + instantiate_decl). */ + +static void +push_access_scope (tree t) +{ + gcc_assert (TREE_CODE (t) == FUNCTION_DECL + || TREE_CODE (t) == VAR_DECL); + + if (DECL_FRIEND_CONTEXT (t)) + push_nested_class (DECL_FRIEND_CONTEXT (t)); + else if (DECL_CLASS_SCOPE_P (t)) + push_nested_class (DECL_CONTEXT (t)); + else + push_to_top_level (); + + if (TREE_CODE (t) == FUNCTION_DECL) + { + saved_access_scope = tree_cons + (NULL_TREE, current_function_decl, saved_access_scope); + current_function_decl = t; + } +} + +/* Restore the scope set up by push_access_scope. T is the node we + are processing. */ + +static void +pop_access_scope (tree t) { - ggc_add_tree_root (&pending_templates, 1); - ggc_add_tree_root (&saved_trees, 1); - ggc_add_tree_root (¤t_tinst_level, 1); + if (TREE_CODE (t) == FUNCTION_DECL) + { + current_function_decl = TREE_VALUE (saved_access_scope); + saved_access_scope = TREE_CHAIN (saved_access_scope); + } + + if (DECL_FRIEND_CONTEXT (t) || DECL_CLASS_SCOPE_P (t)) + pop_nested_class (); + else + pop_from_top_level (); } -/* Do any processing required when DECL (a member template declaration - using TEMPLATE_PARAMETERS as its innermost parameter list) is - finished. Returns the TEMPLATE_DECL corresponding to DECL, unless - it is a specialization, in which case the DECL itself is returned. */ +/* Do any processing required when DECL (a member template + declaration) is finished. Returns the TEMPLATE_DECL corresponding + to DECL, unless it is a specialization, in which case the DECL + itself is returned. */ tree -finish_member_template_decl (decl) - tree decl; +finish_member_template_decl (tree decl) { - if (decl == NULL_TREE || decl == void_type_node) - return NULL_TREE; - else if (decl == error_mark_node) - /* By returning NULL_TREE, the parser will just ignore this - declaration. We have already issued the error. */ - return NULL_TREE; - else if (TREE_CODE (decl) == TREE_LIST) + if (decl == error_mark_node) + return error_mark_node; + + gcc_assert (DECL_P (decl)); + + if (TREE_CODE (decl) == TYPE_DECL) { - /* Assume that the class is the only declspec. */ - decl = TREE_VALUE (decl); - if (IS_AGGR_TYPE (decl) && CLASSTYPE_TEMPLATE_INFO (decl) - && ! CLASSTYPE_TEMPLATE_SPECIALIZATION (decl)) + tree type; + + type = TREE_TYPE (decl); + if (type == error_mark_node) + return error_mark_node; + if (MAYBE_CLASS_TYPE_P (type) + && CLASSTYPE_TEMPLATE_INFO (type) + && !CLASSTYPE_TEMPLATE_SPECIALIZATION (type)) { - tree tmpl = CLASSTYPE_TI_TEMPLATE (decl); + tree tmpl = CLASSTYPE_TI_TEMPLATE (type); check_member_template (tmpl); return tmpl; } return NULL_TREE; } else if (TREE_CODE (decl) == FIELD_DECL) - error ("data member `%D' cannot be a member template", decl); + error ("data member %qD cannot be a member template", decl); else if (DECL_TEMPLATE_INFO (decl)) { if (!DECL_TEMPLATE_SPECIALIZATION (decl)) @@ -219,15 +263,34 @@ finish_member_template_decl (decl) } else return decl; - } + } else - error ("invalid member template declaration `%D'", decl); + error ("invalid member template declaration %qD", decl); return error_mark_node; } +/* Return the template info node corresponding to T, whatever T is. */ + +tree +get_template_info (tree t) +{ + tree tinfo = NULL_TREE; + + if (DECL_P (t) && DECL_LANG_SPECIFIC (t)) + tinfo = DECL_TEMPLATE_INFO (t); + + if (!tinfo && TREE_CODE (t) == TYPE_DECL) + t = TREE_TYPE (t); + + if (TAGGED_TYPE_P (t)) + tinfo = TYPE_TEMPLATE_INFO (t); + + return tinfo; +} + /* Returns the template nesting level of the indicated class TYPE. - + For example, in: template struct A @@ -236,70 +299,42 @@ finish_member_template_decl (decl) struct B {}; }; - A::B has depth two, while A has depth one. + A::B has depth two, while A has depth one. Both A::B and A::B have depth one, if - COUNT_SPECIALIZATIONS is 0 or if they are instantiations, not - specializations. + they are instantiations, not specializations. This function is guaranteed to return 0 if passed NULL_TREE so that, for example, `template_class_depth (current_class_type)' is always safe. */ -static int -template_class_depth_real (type, count_specializations) - tree type; - int count_specializations; +int +template_class_depth (tree type) { int depth; - for (depth = 0; + for (depth = 0; type && TREE_CODE (type) != NAMESPACE_DECL; - type = (TREE_CODE (type) == FUNCTION_DECL) + type = (TREE_CODE (type) == FUNCTION_DECL) ? CP_DECL_CONTEXT (type) : TYPE_CONTEXT (type)) { - if (TREE_CODE (type) != FUNCTION_DECL) - { - if (CLASSTYPE_TEMPLATE_INFO (type) - && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)) - && ((count_specializations - && CLASSTYPE_TEMPLATE_SPECIALIZATION (type)) - || uses_template_parms (CLASSTYPE_TI_ARGS (type)))) - ++depth; - } - else - { - if (DECL_TEMPLATE_INFO (type) - && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (type)) - && ((count_specializations - && DECL_TEMPLATE_SPECIALIZATION (type)) - || uses_template_parms (DECL_TI_ARGS (type)))) - ++depth; - } + tree tinfo = get_template_info (type); + + if (tinfo && PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)) + && uses_template_parms (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)))) + ++depth; } return depth; } -/* Returns the template nesting level of the indicated class TYPE. - Like template_class_depth_real, but instantiations do not count in - the depth. */ - -int -template_class_depth (type) - tree type; -{ - return template_class_depth_real (type, /*count_specializations=*/0); -} - -/* Returns 1 if processing DECL as part of do_pending_inlines - needs us to push template parms. */ +/* Subroutine of maybe_begin_member_template_processing. + Returns true if processing DECL needs us to push template parms. */ -static int -inline_needs_template_parms (decl) - tree decl; +static bool +inline_needs_template_parms (tree decl) { if (! DECL_TEMPLATE_INFO (decl)) - return 0; + return false; return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (most_general_template (decl))) > (processing_template_decl + DECL_TEMPLATE_SPECIALIZATION (decl))); @@ -311,9 +346,7 @@ inline_needs_template_parms (decl) innermost first. */ static void -push_inline_template_parms_recursive (parmlist, levels) - tree parmlist; - int levels; +push_inline_template_parms_recursive (tree parmlist, int levels) { tree parms = TREE_VALUE (parmlist); int i; @@ -327,11 +360,16 @@ push_inline_template_parms_recursive (parmlist, levels) parms, current_template_parms); TEMPLATE_PARMS_FOR_INLINE (current_template_parms) = 1; - pushlevel (0); - for (i = 0; i < TREE_VEC_LENGTH (parms); ++i) + begin_scope (TREE_VEC_LENGTH (parms) ? sk_template_parms : sk_template_spec, + NULL); + for (i = 0; i < TREE_VEC_LENGTH (parms); ++i) { tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i)); - my_friendly_assert (DECL_P (parm), 0); + + if (parm == error_mark_node) + continue; + + gcc_assert (DECL_P (parm)); switch (TREE_CODE (parm)) { @@ -349,6 +387,8 @@ push_inline_template_parms_recursive (parmlist, levels) tree decl = build_decl (CONST_DECL, DECL_NAME (parm), TREE_TYPE (parm)); DECL_ARTIFICIAL (decl) = 1; + TREE_CONSTANT (decl) = 1; + TREE_READONLY (decl) = 1; DECL_INITIAL (decl) = DECL_INITIAL (parm); SET_DECL_TEMPLATE_PARM_P (decl); pushdecl (decl); @@ -356,7 +396,7 @@ push_inline_template_parms_recursive (parmlist, levels) break; default: - abort (); + gcc_unreachable (); } } } @@ -365,8 +405,7 @@ push_inline_template_parms_recursive (parmlist, levels) a friend template defined in a class definition. */ void -maybe_begin_member_template_processing (decl) - tree decl; +maybe_begin_member_template_processing (tree decl) { tree parms; int levels = 0; @@ -387,28 +426,22 @@ maybe_begin_member_template_processing (decl) /* Remember how many levels of template parameters we pushed so that we can pop them later. */ - if (!inline_parm_levels) - VARRAY_INT_INIT (inline_parm_levels, 4, "inline_parm_levels"); - if (inline_parm_levels_used == inline_parm_levels->num_elements) - VARRAY_GROW (inline_parm_levels, 2 * inline_parm_levels_used); - VARRAY_INT (inline_parm_levels, inline_parm_levels_used) = levels; - ++inline_parm_levels_used; + VEC_safe_push (int, heap, inline_parm_levels, levels); } -/* Undo the effects of begin_member_template_processing. */ +/* Undo the effects of maybe_begin_member_template_processing. */ -void -maybe_end_member_template_processing () +void +maybe_end_member_template_processing (void) { int i; + int last; - if (!inline_parm_levels_used) + if (VEC_length (int, inline_parm_levels) == 0) return; - --inline_parm_levels_used; - for (i = 0; - i < VARRAY_INT (inline_parm_levels, inline_parm_levels_used); - ++i) + last = VEC_pop (int, inline_parm_levels); + for (i = 0; i < last; ++i) { --processing_template_decl; current_template_parms = TREE_CHAIN (current_template_parms); @@ -416,76 +449,11 @@ maybe_end_member_template_processing () } } -/* Returns non-zero iff T is a member template function. We must be - careful as in - - template 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 C { template void f(U); } - - then neither C::f nor C::f is considered - to be a member template. But, `template void - C::f(U)' is considered a member template. */ - -int -is_member_template (t) - tree t; -{ - if (!DECL_FUNCTION_TEMPLATE_P (t)) - /* Anything that isn't a function or a template function is - certainly not a member template. */ - return 0; - - /* A local class can't have member templates. */ - if (decl_function_context (t)) - return 0; - - return (DECL_FUNCTION_MEMBER_P (DECL_TEMPLATE_RESULT (t)) - /* If there are more levels of template parameters than - there are template classes surrounding the declaration, - then we have a member template. */ - && (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (t)) > - template_class_depth (DECL_CONTEXT (t)))); -} - -#if 0 /* UNUSED */ -/* Returns non-zero iff T is a member template class. See - is_member_template for a description of what precisely constitutes - a member template. */ - -int -is_member_template_class (t) - tree t; -{ - if (!DECL_CLASS_TEMPLATE_P (t)) - /* Anything that isn't a class template, is certainly not a member - template. */ - return 0; - - if (!DECL_CLASS_SCOPE_P (t)) - /* Anything whose context isn't a class type is surely not a - member template. */ - return 0; - - /* If there are more levels of template parameters than there are - template classes surrounding the declaration, then we have a - member template. */ - return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (t)) > - template_class_depth (DECL_CONTEXT (t))); -} -#endif - /* Return a new template argument vector which contains all of ARGS, but has as its innermost set of arguments the EXTRA_ARGS. */ static tree -add_to_template_args (args, extra_args) - tree args; - tree extra_args; +add_to_template_args (tree args, tree extra_args) { tree new_args; int extra_depth; @@ -500,7 +468,7 @@ add_to_template_args (args, extra_args) for (j = 1; j <= extra_depth; ++j, ++i) SET_TMPL_ARGS_LEVEL (new_args, i, TMPL_ARGS_LEVEL (extra_args, j)); - + return new_args; } @@ -512,16 +480,13 @@ add_to_template_args (args, extra_args) partial instantiation. */ static tree -add_outermost_template_args (args, extra_args) - tree args; - tree extra_args; +add_outermost_template_args (tree args, tree extra_args) { tree new_args; /* If there are more levels of EXTRA_ARGS than there are ARGS, something very fishy is going on. */ - my_friendly_assert (TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (extra_args), - 0); + gcc_assert (TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (extra_args)); /* If *all* the new arguments will be the EXTRA_ARGS, just return them. */ @@ -530,7 +495,7 @@ add_outermost_template_args (args, extra_args) /* For the moment, we make ARGS look like it contains fewer levels. */ TREE_VEC_LENGTH (args) -= TMPL_ARGS_DEPTH (extra_args); - + new_args = add_to_template_args (args, extra_args); /* Now, we restore ARGS to its full dimensions. */ @@ -542,41 +507,70 @@ add_outermost_template_args (args, extra_args) /* Return the N levels of innermost template arguments from the ARGS. */ tree -get_innermost_template_args (args, n) - tree args; - int n; +get_innermost_template_args (tree args, int n) { tree new_args; int extra_levels; int i; - my_friendly_assert (n >= 0, 20000603); + gcc_assert (n >= 0); /* If N is 1, just return the innermost set of template arguments. */ if (n == 1) return TMPL_ARGS_LEVEL (args, TMPL_ARGS_DEPTH (args)); - + /* If we're not removing anything, just return the arguments we were given. */ extra_levels = TMPL_ARGS_DEPTH (args) - n; - my_friendly_assert (extra_levels >= 0, 20000603); + gcc_assert (extra_levels >= 0); if (extra_levels == 0) return args; /* Make a new set of arguments, not containing the outer arguments. */ new_args = make_tree_vec (n); for (i = 1; i <= n; ++i) - SET_TMPL_ARGS_LEVEL (new_args, i, + SET_TMPL_ARGS_LEVEL (new_args, i, TMPL_ARGS_LEVEL (args, i + extra_levels)); return new_args; } +/* The inverse of get_innermost_template_args: Return all but the innermost + EXTRA_LEVELS levels of template arguments from the ARGS. */ + +static tree +strip_innermost_template_args (tree args, int extra_levels) +{ + tree new_args; + int n = TMPL_ARGS_DEPTH (args) - extra_levels; + int i; + + gcc_assert (n >= 0); + + /* If N is 1, just return the outermost set of template arguments. */ + if (n == 1) + return TMPL_ARGS_LEVEL (args, 1); + + /* If we're not removing anything, just return the arguments we were + given. */ + gcc_assert (extra_levels >= 0); + if (extra_levels == 0) + return args; + + /* Make a new set of arguments, not containing the inner arguments. */ + new_args = make_tree_vec (n); + for (i = 1; i <= n; ++i) + SET_TMPL_ARGS_LEVEL (new_args, i, + TMPL_ARGS_LEVEL (args, i)); + + return new_args; +} + /* We've got a template header coming up; push to a new level for storing the parms. */ void -begin_template_parm_list () +begin_template_parm_list (void) { /* We use a non-tag-transparent scope here, which causes pushtag to put tags in this scope, rather than in the enclosing class or @@ -587,27 +581,28 @@ begin_template_parm_list () e.g.: template struct S1 { - template struct S2 {}; + template struct S2 {}; }; pushtag contains special code to call pushdecl_with_scope on the TEMPLATE_DECL for S2. */ - begin_scope (sk_template_parms); + begin_scope (sk_template_parms, NULL); ++processing_template_decl; ++processing_template_parmlist; note_template_header (0); } /* This routine is called when a specialization is declared. If it is - illegal to declare a specialization here, an error is reported. */ + invalid to declare a specialization here, an error is reported and + false is returned, otherwise this routine will return true. */ -static void -check_specialization_scope () +static bool +check_specialization_scope (void) { tree scope = current_scope (); - /* [temp.expl.spec] - + /* [temp.expl.spec] + An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class @@ -616,10 +611,12 @@ check_specialization_scope () shall be declared in the namespace of which the class template is a member. */ if (scope && TREE_CODE (scope) != NAMESPACE_DECL) - error ("explicit specialization in non-namespace scope `%D'", - scope); + { + error ("explicit specialization in non-namespace scope %qD", scope); + return false; + } - /* [temp.expl.spec] + /* [temp.expl.spec] In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, @@ -627,46 +624,50 @@ check_specialization_scope () remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. */ - if (current_template_parms) - error ("enclosing class templates are not explicitly specialized"); + if (current_template_parms) + { + error ("enclosing class templates are not explicitly specialized"); + return false; + } + + return true; } -/* We've just seen template <>. */ +/* We've just seen template <>. */ -void -begin_specialization () +bool +begin_specialization (void) { - begin_scope (sk_template_spec); + begin_scope (sk_template_spec, NULL); note_template_header (1); - check_specialization_scope (); + return check_specialization_scope (); } /* Called at then end of processing a declaration preceded by template<>. */ -void -end_specialization () +void +end_specialization (void) { finish_scope (); reset_specialization (); } /* Any template <>'s that we have seen thus far are not referring to a - function specialization. */ + function specialization. */ void -reset_specialization () +reset_specialization (void) { processing_specialization = 0; template_header_count = 0; } -/* We've just seen a template header. If SPECIALIZATION is non-zero, +/* We've just seen a template header. If SPECIALIZATION is nonzero, it was of the form template <>. */ -static void -note_template_header (specialization) - int specialization; +static void +note_template_header (int specialization) { processing_specialization = specialization; template_header_count++; @@ -675,28 +676,86 @@ note_template_header (specialization) /* We're beginning an explicit instantiation. */ void -begin_explicit_instantiation () +begin_explicit_instantiation (void) { - ++processing_explicit_instantiation; + gcc_assert (!processing_explicit_instantiation); + processing_explicit_instantiation = true; } void -end_explicit_instantiation () +end_explicit_instantiation (void) +{ + gcc_assert (processing_explicit_instantiation); + processing_explicit_instantiation = false; +} + +/* An explicit specialization or partial specialization TMPL is being + declared. Check that the namespace in which the specialization is + occurring is permissible. Returns false iff it is invalid to + specialize TMPL in the current namespace. */ + +static bool +check_specialization_namespace (tree tmpl) { - my_friendly_assert(processing_explicit_instantiation > 0, 0); - --processing_explicit_instantiation; + tree tpl_ns = decl_namespace_context (tmpl); + + /* [tmpl.expl.spec] + + An explicit specialization shall be declared in the namespace of + which the template is a member, or, for member templates, in the + namespace of which the enclosing class or enclosing class + template is a member. An explicit specialization of a member + function, member class or static data member of a class template + shall be declared in the namespace of which the class template is + a member. */ + if (is_associated_namespace (current_namespace, tpl_ns)) + /* Same or super-using namespace. */ + return true; + else + { + permerror (input_location, "specialization of %qD in different namespace", tmpl); + permerror (input_location, " from definition of %q+#D", tmpl); + return false; + } +} + +/* SPEC is an explicit instantiation. Check that it is valid to + perform this explicit instantiation in the current namespace. */ + +static void +check_explicit_instantiation_namespace (tree spec) +{ + tree ns; + + /* DR 275: An explicit instantiation shall appear in an enclosing + namespace of its template. */ + ns = decl_namespace_context (spec); + if (!is_ancestor (current_namespace, ns)) + permerror (input_location, "explicit instantiation of %qD in namespace %qD " + "(which does not enclose namespace %qD)", + spec, current_namespace, ns); } /* The TYPE is being declared. If it is a template type, that means it is a partial specialization. Do appropriate error-checking. */ -void -maybe_process_partial_specialization (type) - tree type; +tree +maybe_process_partial_specialization (tree type) { - /* TYPE maybe an ERROR_MARK_NODE. */ - tree context = TYPE_P (type) ? TYPE_CONTEXT (type) : NULL_TREE; + tree context; + + if (type == error_mark_node) + return error_mark_node; + + if (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM) + { + error ("name of class shadows template template parameter %qD", + TYPE_NAME (type)); + return error_mark_node; + } + + context = TYPE_CONTEXT (type); if (CLASS_TYPE_P (type) && CLASSTYPE_USE_TEMPLATE (type)) { @@ -714,19 +773,17 @@ maybe_process_partial_specialization (type) if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type)) { - if (current_namespace - != decl_namespace_context (CLASSTYPE_TI_TEMPLATE (type))) - { - pedwarn ("specializing `%#T' in different namespace", type); - cp_pedwarn_at (" from definition of `%#D'", - CLASSTYPE_TI_TEMPLATE (type)); - } + check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type)); SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type); if (processing_template_decl) - push_template_decl (TYPE_MAIN_DECL (type)); + { + if (push_template_decl (TYPE_MAIN_DECL (type)) + == error_mark_node) + return error_mark_node; + } } else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)) - error ("specialization of `%T' after instantiation", type); + error ("specialization of %qT after instantiation", type); } else if (CLASS_TYPE_P (type) && !CLASSTYPE_USE_TEMPLATE (type) @@ -758,9 +815,9 @@ maybe_process_partial_specialization (type) if (current_namespace != decl_namespace_context (CLASSTYPE_TI_TEMPLATE (type))) { - pedwarn ("specializing `%#T' in different namespace", type); - cp_pedwarn_at (" from definition of `%#D'", - CLASSTYPE_TI_TEMPLATE (type)); + permerror (input_location, "specializing %q#T in different namespace", type); + permerror (input_location, " from definition of %q+#D", + CLASSTYPE_TI_TEMPLATE (type)); } /* Check for invalid specialization after instantiation: @@ -773,7 +830,7 @@ maybe_process_partial_specialization (type) t; t = TREE_CHAIN (t)) if (TREE_VALUE (t) != type && TYPE_CONTEXT (TREE_VALUE (t)) == context) - error ("specialization `%T' after instantiation `%T'", + error ("specialization %qT after instantiation %qT", type, TREE_VALUE (t)); /* Mark TYPE as a specialization. And as a result, we only @@ -785,7 +842,45 @@ maybe_process_partial_specialization (type) } } else if (processing_specialization) - error ("explicit specialization of non-template `%T'", type); + { + error ("explicit specialization of non-template %qT", type); + return error_mark_node; + } + + return type; +} + +/* Returns nonzero if we can optimize the retrieval of specializations + for TMPL, a TEMPLATE_DECL. In particular, for such a template, we + do not use DECL_TEMPLATE_SPECIALIZATIONS at all. */ + +static inline bool +optimize_specialization_lookup_p (tree tmpl) +{ + return (DECL_FUNCTION_TEMPLATE_P (tmpl) + && DECL_CLASS_SCOPE_P (tmpl) + /* DECL_CLASS_SCOPE_P holds of T::f even if T is a template + parameter. */ + && CLASS_TYPE_P (DECL_CONTEXT (tmpl)) + /* The optimized lookup depends on the fact that the + template arguments for the member function template apply + purely to the containing class, which is not true if the + containing class is an explicit or partial + specialization. */ + && !CLASSTYPE_TEMPLATE_SPECIALIZATION (DECL_CONTEXT (tmpl)) + && !DECL_MEMBER_TEMPLATE_P (tmpl) + && !DECL_CONV_FN_P (tmpl) + /* It is possible to have a template that is not a member + template and is not a member of a template class: + + template + struct S { friend A::f(); }; + + Here, the friend function is a template, but the context does + not have template information. The optimized lookup relies + on having ARGS be the template arguments for both the class + and the function template. */ + && !DECL_FRIEND_P (DECL_TEMPLATE_RESULT (tmpl))); } /* Retrieve the specialization (in the sense of [temp.spec] - a @@ -793,28 +888,94 @@ maybe_process_partial_specialization (type) 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. */ - + templates with more than one level of parameters. + + If TMPL is a type template and CLASS_SPECIALIZATIONS_P is true, + then we search for a partial specialization matching ARGS. This + parameter is ignored if TMPL is not a class template. */ + static tree -retrieve_specialization (tmpl, args) - tree tmpl; - tree args; +retrieve_specialization (tree tmpl, tree args, + bool class_specializations_p) { - tree s; + if (args == error_mark_node) + return NULL_TREE; - my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0); + gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL); /* There should be as many levels of arguments as there are levels of parameters. */ - my_friendly_assert (TMPL_ARGS_DEPTH (args) - == TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)), - 0); - - for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); - s != NULL_TREE; - s = TREE_CHAIN (s)) - if (comp_template_args (TREE_PURPOSE (s), args)) - return TREE_VALUE (s); + gcc_assert (TMPL_ARGS_DEPTH (args) + == TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))); + + if (optimize_specialization_lookup_p (tmpl)) + { + tree class_template; + tree class_specialization; + VEC(tree,gc) *methods; + tree fns; + int idx; + + /* The template arguments actually apply to the containing + class. Find the class specialization with those + arguments. */ + class_template = CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (tmpl)); + class_specialization + = retrieve_specialization (class_template, args, + /*class_specializations_p=*/false); + if (!class_specialization) + return NULL_TREE; + /* Now, find the appropriate entry in the CLASSTYPE_METHOD_VEC + for the specialization. */ + idx = class_method_index_for_fn (class_specialization, tmpl); + if (idx == -1) + return NULL_TREE; + /* Iterate through the methods with the indicated name, looking + for the one that has an instance of TMPL. */ + methods = CLASSTYPE_METHOD_VEC (class_specialization); + for (fns = VEC_index (tree, methods, idx); fns; fns = OVL_NEXT (fns)) + { + tree fn = OVL_CURRENT (fns); + if (DECL_TEMPLATE_INFO (fn) && DECL_TI_TEMPLATE (fn) == tmpl) + return fn; + } + return NULL_TREE; + } + else + { + tree *sp; + tree *head; + + /* Class templates store their instantiations on the + DECL_TEMPLATE_INSTANTIATIONS list; other templates use the + DECL_TEMPLATE_SPECIALIZATIONS list. */ + if (!class_specializations_p + && TREE_CODE (DECL_TEMPLATE_RESULT (tmpl)) == TYPE_DECL + && TAGGED_TYPE_P (TREE_TYPE (tmpl))) + sp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl); + else + sp = &DECL_TEMPLATE_SPECIALIZATIONS (tmpl); + head = sp; + /* Iterate through the list until we find a matching template. */ + while (*sp != NULL_TREE) + { + tree spec = *sp; + + if (comp_template_args (TREE_PURPOSE (spec), args)) + { + /* Use the move-to-front heuristic to speed up future + searches. */ + if (spec != *head) + { + *sp = TREE_CHAIN (*sp); + TREE_CHAIN (spec) = *head; + *head = spec; + } + return TREE_VALUE (spec); + } + sp = &TREE_CHAIN (spec); + } + } return NULL_TREE; } @@ -822,32 +983,36 @@ retrieve_specialization (tmpl, args) /* Like retrieve_specialization, but for local declarations. */ static tree -retrieve_local_specialization (tmpl) - tree tmpl; +retrieve_local_specialization (tree tmpl) { - return (tree) htab_find (local_specializations, tmpl); + tree spec; + + if (local_specializations == NULL) + return NULL_TREE; + + spec = (tree) htab_find_with_hash (local_specializations, tmpl, + htab_hash_pointer (tmpl)); + return spec ? TREE_PURPOSE (spec) : NULL_TREE; } -/* Returns non-zero iff DECL is a specialization of TMPL. */ +/* Returns nonzero iff DECL is a specialization of TMPL. */ int -is_specialization_of (decl, tmpl) - tree decl; - tree tmpl; +is_specialization_of (tree decl, tree tmpl) { tree t; if (TREE_CODE (decl) == FUNCTION_DECL) { - for (t = decl; + for (t = decl; t != NULL_TREE; t = DECL_TEMPLATE_INFO (t) ? DECL_TI_TEMPLATE (t) : NULL_TREE) if (t == tmpl) return 1; } - else + else { - my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 0); + gcc_assert (TREE_CODE (decl) == TYPE_DECL); for (t = TREE_TYPE (decl); t != NULL_TREE; @@ -855,26 +1020,206 @@ is_specialization_of (decl, tmpl) ? TREE_TYPE (CLASSTYPE_TI_TEMPLATE (t)) : NULL_TREE) if (same_type_ignoring_top_level_qualifiers_p (t, TREE_TYPE (tmpl))) return 1; - } + } return 0; } +/* Returns nonzero iff DECL is a specialization of friend declaration + FRIEND_DECL according to [temp.friend]. */ + +bool +is_specialization_of_friend (tree decl, tree friend_decl) +{ + bool need_template = true; + int template_depth; + + gcc_assert (TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == TYPE_DECL); + + /* For [temp.friend/6] when FRIEND_DECL is an ordinary member function + of a template class, we want to check if DECL is a specialization + if this. */ + if (TREE_CODE (friend_decl) == FUNCTION_DECL + && DECL_TEMPLATE_INFO (friend_decl) + && !DECL_USE_TEMPLATE (friend_decl)) + { + /* We want a TEMPLATE_DECL for `is_specialization_of'. */ + friend_decl = DECL_TI_TEMPLATE (friend_decl); + need_template = false; + } + else if (TREE_CODE (friend_decl) == TEMPLATE_DECL + && !PRIMARY_TEMPLATE_P (friend_decl)) + need_template = false; + + /* There is nothing to do if this is not a template friend. */ + if (TREE_CODE (friend_decl) != TEMPLATE_DECL) + return false; + + if (is_specialization_of (decl, friend_decl)) + return true; + + /* [temp.friend/6] + A member of a class template may be declared to be a friend of a + non-template class. In this case, the corresponding member of + every specialization of the class template is a friend of the + class granting friendship. + + For example, given a template friend declaration + + template friend void A::f(); + + the member function below is considered a friend + + template <> struct A { + void f(); + }; + + For this type of template friend, TEMPLATE_DEPTH below will be + nonzero. To determine if DECL is a friend of FRIEND, we first + check if the enclosing class is a specialization of another. */ + + template_depth = template_class_depth (DECL_CONTEXT (friend_decl)); + if (template_depth + && DECL_CLASS_SCOPE_P (decl) + && is_specialization_of (TYPE_NAME (DECL_CONTEXT (decl)), + CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (friend_decl)))) + { + /* Next, we check the members themselves. In order to handle + a few tricky cases, such as when FRIEND_DECL's are + + template friend void A::g(T t); + template template friend void A::h(); + + and DECL's are + + void A::g(int); + template void A::h(); + + we need to figure out ARGS, the template arguments from + the context of DECL. This is required for template substitution + of `T' in the function parameter of `g' and template parameter + of `h' in the above examples. Here ARGS corresponds to `int'. */ + + tree context = DECL_CONTEXT (decl); + tree args = NULL_TREE; + int current_depth = 0; + + while (current_depth < template_depth) + { + if (CLASSTYPE_TEMPLATE_INFO (context)) + { + if (current_depth == 0) + args = TYPE_TI_ARGS (context); + else + args = add_to_template_args (TYPE_TI_ARGS (context), args); + current_depth++; + } + context = TYPE_CONTEXT (context); + } + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + bool is_template; + tree friend_type; + tree decl_type; + tree friend_args_type; + tree decl_args_type; + + /* Make sure that both DECL and FRIEND_DECL are templates or + non-templates. */ + is_template = DECL_TEMPLATE_INFO (decl) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)); + if (need_template ^ is_template) + return false; + else if (is_template) + { + /* If both are templates, check template parameter list. */ + tree friend_parms + = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_decl), + args, tf_none); + if (!comp_template_parms + (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl)), + friend_parms)) + return false; + + decl_type = TREE_TYPE (DECL_TI_TEMPLATE (decl)); + } + else + decl_type = TREE_TYPE (decl); + + friend_type = tsubst_function_type (TREE_TYPE (friend_decl), args, + tf_none, NULL_TREE); + if (friend_type == error_mark_node) + return false; + + /* Check if return types match. */ + if (!same_type_p (TREE_TYPE (decl_type), TREE_TYPE (friend_type))) + return false; + + /* Check if function parameter types match, ignoring the + `this' parameter. */ + friend_args_type = TYPE_ARG_TYPES (friend_type); + decl_args_type = TYPE_ARG_TYPES (decl_type); + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (friend_decl)) + friend_args_type = TREE_CHAIN (friend_args_type); + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + decl_args_type = TREE_CHAIN (decl_args_type); + + return compparms (decl_args_type, friend_args_type); + } + else + { + /* DECL is a TYPE_DECL */ + bool is_template; + tree decl_type = TREE_TYPE (decl); + + /* Make sure that both DECL and FRIEND_DECL are templates or + non-templates. */ + is_template + = CLASSTYPE_TEMPLATE_INFO (decl_type) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (decl_type)); + + if (need_template ^ is_template) + return false; + else if (is_template) + { + tree friend_parms; + /* If both are templates, check the name of the two + TEMPLATE_DECL's first because is_friend didn't. */ + if (DECL_NAME (CLASSTYPE_TI_TEMPLATE (decl_type)) + != DECL_NAME (friend_decl)) + return false; + + /* Now check template parameter list. */ + friend_parms + = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_decl), + args, tf_none); + return comp_template_parms + (DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (decl_type)), + friend_parms); + } + else + return (DECL_NAME (decl) + == DECL_NAME (friend_decl)); + } + } + return false; +} + /* Register the specialization SPEC as a specialization of TMPL with - the indicated ARGS. Returns SPEC, or an equivalent prior - declaration, if available. */ + the indicated ARGS. IS_FRIEND indicates whether the specialization + is actually just a friend declaration. Returns SPEC, or an + equivalent prior declaration, if available. */ static tree -register_specialization (spec, tmpl, args) - tree spec; - tree tmpl; - tree args; +register_specialization (tree spec, tree tmpl, tree args, bool is_friend) { - tree s; + tree fn; - my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0); + gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL); - if (TREE_CODE (spec) == FUNCTION_DECL + if (TREE_CODE (spec) == FUNCTION_DECL && uses_template_parms (DECL_TI_ARGS (spec))) /* This is the FUNCTION_DECL for a partial instantiation. Don't register it; we want the corresponding TEMPLATE_DECL instead. @@ -883,99 +1228,113 @@ register_specialization (spec, tmpl, args) with default function arguments. In particular, given something like this: - template void f(T t1, T t = T()) + template void f(T t1, T t = T()) the default argument expression is not substituted for in an instantiation unless and until it is actually needed. */ return spec; - - /* There should be as many levels of arguments as there are - levels of parameters. */ - my_friendly_assert (TMPL_ARGS_DEPTH (args) - == TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)), - 0); - - for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); - s != NULL_TREE; - s = TREE_CHAIN (s)) - { - tree fn = TREE_VALUE (s); - - /* We can sometimes try to re-register a specialization that we've - already got. In particular, regenerate_decl_from_template - calls duplicate_decls which will update the specialization - list. But, we'll still get called again here anyhow. It's - more convenient to simply allow this than to try to prevent it. */ - if (fn == spec) - return spec; - else if (comp_template_args (TREE_PURPOSE (s), args)) + + fn = retrieve_specialization (tmpl, args, + /*class_specializations_p=*/false); + /* We can sometimes try to re-register a specialization that we've + already got. In particular, regenerate_decl_from_template calls + duplicate_decls which will update the specialization list. But, + we'll still get called again here anyhow. It's more convenient + to simply allow this than to try to prevent it. */ + if (fn == spec) + return spec; + else if (fn && DECL_TEMPLATE_SPECIALIZATION (spec)) + { + if (DECL_TEMPLATE_INSTANTIATION (fn)) { - if (DECL_TEMPLATE_SPECIALIZATION (spec)) + if (TREE_USED (fn) + || DECL_EXPLICIT_INSTANTIATION (fn)) { - if (DECL_TEMPLATE_INSTANTIATION (fn)) + error ("specialization of %qD after instantiation", + fn); + return error_mark_node; + } + else + { + tree clone; + /* 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 and then specialized + it later. + + We can also wind up here if a friend declaration that + looked like an instantiation turns out to be a + specialization: + + template void foo(T); + class S { friend void foo<>(int) }; + template <> void foo(int); + + We transform the existing DECL in place so that any + pointers to it become pointers to the updated + declaration. + + If there was a definition for the template, but not + for the specialization, we want this to look as if + there were no definition, and vice versa. */ + DECL_INITIAL (fn) = NULL_TREE; + duplicate_decls (spec, fn, is_friend); + /* The call to duplicate_decls will have applied + [temp.expl.spec]: + + An explicit specialization of a function template + is inline only if it is explicitly declared to be, + and independently of whether its function template + is. + + to the primary function; now copy the inline bits to + the various clones. */ + FOR_EACH_CLONE (clone, fn) { - if (TREE_USED (fn) - || DECL_EXPLICIT_INSTANTIATION (fn)) - { - error ("specialization of %D after instantiation", - fn); - return spec; - } - 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 and - then specialized it later. - - We can also wind up here if a friend - declaration that looked like an instantiation - turns out to be a specialization: - - template void foo(T); - class S { friend void foo<>(int) }; - template <> void foo(int); - - We transform the existing DECL in place so that - any pointers to it become pointers to the - updated declaration. - - If there was a definition for the template, but - not for the specialization, we want this to - look as if there is no definition, and vice - versa. */ - DECL_INITIAL (fn) = NULL_TREE; - duplicate_decls (spec, fn); - - return fn; - } - } - else if (DECL_TEMPLATE_SPECIALIZATION (fn)) - { - duplicate_decls (spec, fn); - return fn; + DECL_DECLARED_INLINE_P (clone) + = DECL_DECLARED_INLINE_P (fn); + DECL_SOURCE_LOCATION (clone) + = DECL_SOURCE_LOCATION (fn); } + check_specialization_namespace (fn); + + return fn; } } - } + else if (DECL_TEMPLATE_SPECIALIZATION (fn)) + { + if (!duplicate_decls (spec, fn, is_friend) && DECL_INITIAL (spec)) + /* Dup decl failed, but this is a new definition. Set the + line number so any errors match this new + definition. */ + DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (spec); + + return fn; + } + } + + /* A specialization must be declared in the same namespace as the + template it is specializing. */ + if (DECL_TEMPLATE_SPECIALIZATION (spec) + && !check_specialization_namespace (tmpl)) + DECL_CONTEXT (spec) = FROB_CONTEXT (decl_namespace_context (tmpl)); - DECL_TEMPLATE_SPECIALIZATIONS (tmpl) - = tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl)); + if (!optimize_specialization_lookup_p (tmpl)) + DECL_TEMPLATE_SPECIALIZATIONS (tmpl) + = tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl)); return spec; } /* Unregister the specialization SPEC as a specialization of TMPL. - Returns nonzero if the SPEC was listed as a specialization of - TMPL. */ + Replace it with NEW_SPEC, if NEW_SPEC is non-NULL. Returns true + if the SPEC was listed as a specialization of TMPL. */ -static int -unregister_specialization (spec, tmpl) - tree spec; - tree tmpl; +bool +reregister_specialization (tree spec, tree tmpl, tree new_spec) { tree* s; @@ -984,32 +1343,62 @@ unregister_specialization (spec, tmpl) s = &TREE_CHAIN (*s)) if (TREE_VALUE (*s) == spec) { - *s = TREE_CHAIN (*s); + if (!new_spec) + *s = TREE_CHAIN (*s); + else + TREE_VALUE (*s) = new_spec; return 1; } return 0; } +/* Compare an entry in the local specializations hash table P1 (which + is really a pointer to a TREE_LIST) with P2 (which is really a + DECL). */ + +static int +eq_local_specializations (const void *p1, const void *p2) +{ + return TREE_VALUE ((const_tree) p1) == (const_tree) p2; +} + +/* Hash P1, an entry in the local specializations table. */ + +static hashval_t +hash_local_specialization (const void* p1) +{ + return htab_hash_pointer (TREE_VALUE ((const_tree) p1)); +} + /* Like register_specialization, but for local declarations. We are registering SPEC, an instantiation of TMPL. */ static void -register_local_specialization (spec, tmpl) - tree spec; - tree tmpl; +register_local_specialization (tree spec, tree tmpl) { void **slot; - slot = htab_find_slot (local_specializations, tmpl, INSERT); - *slot = spec; + slot = htab_find_slot_with_hash (local_specializations, tmpl, + htab_hash_pointer (tmpl), INSERT); + *slot = build_tree_list (spec, tmpl); +} + +/* TYPE is a class type. Returns true if TYPE is an explicitly + specialized class. */ + +bool +explicit_class_specialization_p (tree type) +{ + if (!CLASSTYPE_TEMPLATE_SPECIALIZATION (type)) + return false; + return !uses_template_parms (CLASSTYPE_TI_ARGS (type)); } /* Print the list of candidate FNS in an error message. */ void -print_candidates (fns) - tree fns; +print_candidates (tree fns) { tree fn; @@ -1020,7 +1409,7 @@ print_candidates (fns) tree f; for (f = TREE_VALUE (fn); f; f = OVL_NEXT (f)) - cp_error_at ("%s %+#D", str, OVL_CURRENT (f)); + error ("%s %+#D", str, OVL_CURRENT (f)); str = " "; } } @@ -1031,9 +1420,18 @@ print_candidates (fns) NULL_TREE if none is available. In that case, the functions in TEMPLATE_ID are non-members. - If NEED_MEMBER_TEMPLATE is non-zero the function is known to be a + If NEED_MEMBER_TEMPLATE is nonzero 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. See + check_explicit_specialization for a more accurate description. + + TSK indicates what kind of template declaration (if any) is being + declared. TSK_TEMPLATE indicates that the declaration given by + DECL, though a FUNCTION_DECL, has template parameters, and is + therefore a template function. + The template args (those explicitly specified and those deduced) are output in a newly created vector *TARGS_OUT. @@ -1041,22 +1439,29 @@ print_candidates (fns) issued. The error_mark_node is returned to indicate failure. */ static tree -determine_specialization (template_id, decl, targs_out, - need_member_template) - tree template_id; - tree decl; - tree* targs_out; - int need_member_template; +determine_specialization (tree template_id, + tree decl, + tree* targs_out, + int need_member_template, + int template_count, + tmpl_spec_kind tsk) { tree fns; tree targs; tree explicit_targs; tree candidates = NULL_TREE; + /* A TREE_LIST of templates of which DECL may be a specialization. + The TREE_VALUE of each node is a TEMPLATE_DECL. The + corresponding TREE_PURPOSE is the set of template arguments that, + when used to instantiate the template, would produce a function + with the signature of DECL. */ tree templates = NULL_TREE; + int header_count; + struct cp_binding_level *b; *targs_out = NULL_TREE; - if (template_id == error_mark_node) + if (template_id == error_mark_node || decl == error_mark_node) return error_mark_node; fns = TREE_OPERAND (template_id, 0); @@ -1065,40 +1470,140 @@ determine_specialization (template_id, decl, targs_out, if (fns == error_mark_node) return error_mark_node; - /* Check for baselinks. */ + /* Check for baselinks. */ if (BASELINK_P (fns)) - fns = TREE_VALUE (fns); + fns = BASELINK_FUNCTIONS (fns); if (!is_overloaded_fn (fns)) { - error ("`%D' is not a function template", fns); + error ("%qD is not a function template", fns); return error_mark_node; } + /* Count the number of template headers specified for this + specialization. */ + header_count = 0; + for (b = current_binding_level; + b->kind == sk_template_parms; + b = b->level_chain) + ++header_count; + for (; fns; fns = OVL_NEXT (fns)) { - tree tmpl; - tree fn = OVL_CURRENT (fns); if (TREE_CODE (fn) == TEMPLATE_DECL) - /* DECL might be a specialization of FN. */ - tmpl = fn; + { + tree decl_arg_types; + tree fn_arg_types; + + /* In case of explicit specialization, we need to check if + the number of template headers appearing in the specialization + is correct. This is usually done in check_explicit_specialization, + but the check done there cannot be exhaustive when specializing + member functions. Consider the following code: + + template <> void A::f(int); + template <> template <> void A::f(int); + + Assuming that A is not itself an explicit specialization + already, the first line specializes "f" which is a non-template + member function, whilst the second line specializes "f" which + is a template member function. So both lines are syntactically + correct, and check_explicit_specialization does not reject + them. + + Here, we can do better, as we are matching the specialization + against the declarations. We count the number of template + headers, and we check if they match TEMPLATE_COUNT + 1 + (TEMPLATE_COUNT is the number of qualifying template classes, + plus there must be another header for the member template + itself). + + Notice that if header_count is zero, this is not a + specialization but rather a template instantiation, so there + is no check we can perform here. */ + if (header_count && header_count != template_count + 1) + continue; + + /* Check that the number of template arguments at the + innermost level for DECL is the same as for FN. */ + if (current_binding_level->kind == sk_template_parms + && !current_binding_level->explicit_spec_p + && (TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (fn)) + != TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS + (current_template_parms)))) + continue; + + /* DECL might be a specialization of FN. */ + decl_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); + fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); + + /* For a non-static member function, we need to make sure + that the const qualification is the same. Since + get_bindings does not try to merge the "this" parameter, + we must do the comparison explicitly. */ + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && !same_type_p (TREE_VALUE (fn_arg_types), + TREE_VALUE (decl_arg_types))) + continue; + + /* Skip the "this" parameter and, for constructors of + classes with virtual bases, the VTT parameter. A + full specialization of a constructor will have a VTT + parameter, but a template never will. */ + decl_arg_types + = skip_artificial_parms_for (decl, decl_arg_types); + fn_arg_types + = skip_artificial_parms_for (fn, fn_arg_types); + + /* Check that the number of function parameters matches. + For example, + template void f(int i = 0); + template <> void f(); + The specialization f is invalid but is not caught + by get_bindings below. */ + if (list_length (fn_arg_types) != list_length (decl_arg_types)) + continue; + + /* Function templates cannot be specializations; there are + no partial specializations of functions. Therefore, if + the type of DECL does not match FN, there is no + match. */ + if (tsk == tsk_template) + { + if (compparms (fn_arg_types, decl_arg_types)) + candidates = tree_cons (NULL_TREE, fn, candidates); + continue; + } + + /* See whether this function might be a specialization of this + template. */ + targs = get_bindings (fn, decl, explicit_targs, /*check_ret=*/true); + + if (!targs) + /* We cannot deduce template arguments that when used to + specialize TMPL will produce DECL. */ + continue; + + /* Save this template, and the arguments deduced. */ + templates = tree_cons (targs, fn, templates); + } else if (need_member_template) /* FN is an ordinary member function, and we need a specialization of a member template. */ - continue; + ; else if (TREE_CODE (fn) != FUNCTION_DECL) /* We can get IDENTIFIER_NODEs here in certain erroneous cases. */ - continue; + ; else if (!DECL_FUNCTION_MEMBER_P (fn)) /* This is just an ordinary non-member function. Nothing can be a specialization of that. */ - continue; + ; else if (DECL_ARTIFICIAL (fn)) /* Cannot specialize functions that are created implicitly. */ - continue; + ; else { tree decl_arg_types; @@ -1106,7 +1611,7 @@ determine_specialization (template_id, decl, targs_out, /* This is an ordinary member function. However, since we're here, we can assume it's enclosing class is a template class. For example, - + template struct S { void f(); }; template <> void S::f() {} @@ -1126,35 +1631,21 @@ determine_specialization (template_id, decl, targs_out, /* Adjust the type of DECL in case FN is a static member. */ decl_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); - if (DECL_STATIC_FUNCTION_P (fn) + if (DECL_STATIC_FUNCTION_P (fn) && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) decl_arg_types = TREE_CHAIN (decl_arg_types); - if (compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), + if (compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), decl_arg_types)) /* They match! */ candidates = tree_cons (NULL_TREE, fn, candidates); - - continue; } - - /* See whether this function might be a specialization of this - template. */ - targs = get_bindings (tmpl, decl, explicit_targs); - - if (!targs) - /* We cannot deduce template arguments that when used to - specialize TMPL will produce DECL. */ - continue; - - /* Save this template, and the arguments deduced. */ - templates = tree_cons (targs, tmpl, templates); } if (templates && TREE_CHAIN (templates)) { /* We have: - + [temp.expl.spec] It is possible for a specialization with a given function @@ -1172,50 +1663,54 @@ determine_specialization (template_id, decl, targs_out, Partial ordering of overloaded function template declarations is used in the following contexts to select the function template to which a function template - specialization refers: + specialization refers: - -- when an explicit specialization refers to a function - template. + -- when an explicit specialization refers to a function + template. So, we do use the partial ordering rules, at least for now. - This extension can only serve to make illegal programs legal, + This extension can only serve to make invalid programs valid, so it's safe. And, there is strong anecdotal evidence that the committee intended the partial ordering rules to apply; - the EDG front-end has that behavior, and John Spicer claims + the EDG front end has that behavior, and John Spicer claims that the committee simply forgot to delete the wording in [temp.expl.spec]. */ - tree tmpl = most_specialized (templates, decl, explicit_targs); - if (tmpl && tmpl != error_mark_node) - { - targs = get_bindings (tmpl, decl, explicit_targs); - templates = tree_cons (targs, tmpl, NULL_TREE); - } + tree tmpl = most_specialized_instantiation (templates); + if (tmpl != error_mark_node) + { + templates = tmpl; + TREE_CHAIN (templates) = NULL_TREE; + } } if (templates == NULL_TREE && candidates == NULL_TREE) { - cp_error_at ("template-id `%D' for `%+D' does not match any template declaration", - template_id, decl); + error ("template-id %qD for %q+D does not match any template " + "declaration", template_id, decl); return error_mark_node; } else if ((templates && TREE_CHAIN (templates)) || (candidates && TREE_CHAIN (candidates)) || (templates && candidates)) { - cp_error_at ("ambiguous template specialization `%D' for `%+D'", - template_id, decl); + error ("ambiguous template specialization %qD for %q+D", + template_id, decl); chainon (candidates, templates); print_candidates (candidates); return error_mark_node; } - /* We have one, and exactly one, match. */ + /* We have one, and exactly one, match. */ if (candidates) { + tree fn = TREE_VALUE (candidates); + /* DECL is a re-declaration of a template function. */ + if (TREE_CODE (fn) == TEMPLATE_DECL) + return fn; /* It was a specialization of an ordinary member function in a template class. */ - *targs_out = copy_node (DECL_TI_ARGS (TREE_VALUE (candidates))); - return DECL_TI_TEMPLATE (TREE_VALUE (candidates)); + *targs_out = copy_node (DECL_TI_ARGS (fn)); + return DECL_TI_TEMPLATE (fn); } /* It was a specialization of a template. */ @@ -1223,7 +1718,7 @@ determine_specialization (template_id, decl, targs_out, if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (targs)) { *targs_out = copy_node (targs); - SET_TMPL_ARGS_LEVEL (*targs_out, + SET_TMPL_ARGS_LEVEL (*targs_out, TMPL_ARGS_DEPTH (*targs_out), TREE_PURPOSE (templates)); } @@ -1235,12 +1730,10 @@ determine_specialization (template_id, decl, targs_out, /* Returns a chain of parameter types, exactly like the SPEC_TYPES, but with the default argument values filled in from those in the TMPL_TYPES. */ - + static tree -copy_default_args_to_explicit_spec_1 (spec_types, - tmpl_types) - tree spec_types; - tree tmpl_types; +copy_default_args_to_explicit_spec_1 (tree spec_types, + tree tmpl_types) { tree new_spec_types; @@ -1254,7 +1747,7 @@ copy_default_args_to_explicit_spec_1 (spec_types, new_spec_types = copy_default_args_to_explicit_spec_1 (TREE_CHAIN (spec_types), TREE_CHAIN (tmpl_types)); - + /* Add the default argument for this parameter. */ return hash_tree_cons (TREE_PURPOSE (tmpl_types), TREE_VALUE (spec_types), @@ -1266,15 +1759,14 @@ copy_default_args_to_explicit_spec_1 (spec_types, template void f(T = 3); template <> void f(double); - void g () { f (); } + void g () { f (); } works, as required.) An alternative approach would be to look up the correct default arguments at the call-site, but this approach is consistent with how implicit instantiations are handled. */ static void -copy_default_args_to_explicit_spec (decl) - tree decl; +copy_default_args_to_explicit_spec (tree decl) { tree tmpl; tree spec_types; @@ -1298,20 +1790,20 @@ copy_default_args_to_explicit_spec (decl) old_type = TREE_TYPE (decl); spec_types = TYPE_ARG_TYPES (old_type); - + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) { /* Remove the this pointer, but remember the object's type for - CV quals. */ + CV quals. */ object_type = TREE_TYPE (TREE_VALUE (spec_types)); spec_types = TREE_CHAIN (spec_types); tmpl_types = TREE_CHAIN (tmpl_types); - + if (DECL_HAS_IN_CHARGE_PARM_P (decl)) - { - /* DECL may contain more parameters than TMPL due to the extra - in-charge parameter in constructors and destructors. */ - in_charge = spec_types; + { + /* DECL may contain more parameters than TMPL due to the extra + in-charge parameter in constructors and destructors. */ + in_charge = spec_types; spec_types = TREE_CHAIN (spec_types); } if (DECL_HAS_VTT_PARM_P (decl)) @@ -1322,32 +1814,32 @@ copy_default_args_to_explicit_spec (decl) } /* Compute the merged default arguments. */ - new_spec_types = + new_spec_types = copy_default_args_to_explicit_spec_1 (spec_types, tmpl_types); /* Compute the new FUNCTION_TYPE. */ if (object_type) { if (vtt) - new_spec_types = hash_tree_cons (TREE_PURPOSE (vtt), - TREE_VALUE (vtt), - new_spec_types); + new_spec_types = hash_tree_cons (TREE_PURPOSE (vtt), + TREE_VALUE (vtt), + new_spec_types); if (in_charge) - /* Put the in-charge parameter back. */ - new_spec_types = hash_tree_cons (TREE_PURPOSE (in_charge), - TREE_VALUE (in_charge), - new_spec_types); - - new_type = build_cplus_method_type (object_type, - TREE_TYPE (old_type), - new_spec_types); + /* Put the in-charge parameter back. */ + new_spec_types = hash_tree_cons (TREE_PURPOSE (in_charge), + TREE_VALUE (in_charge), + new_spec_types); + + new_type = build_method_type_directly (object_type, + TREE_TYPE (old_type), + new_spec_types); } else new_type = build_function_type (TREE_TYPE (old_type), new_spec_types); - new_type = build_type_attribute_variant (new_type, - TYPE_ATTRIBUTES (old_type)); + new_type = cp_build_type_attribute_variant (new_type, + TYPE_ATTRIBUTES (old_type)); new_type = build_exception_variant (new_type, TYPE_RAISES_EXCEPTIONS (old_type)); TREE_TYPE (decl) = new_type; @@ -1362,8 +1854,8 @@ copy_default_args_to_explicit_spec (decl) instead if all goes well. Issues an error message if something is amiss. Returns error_mark_node if the error is not easily recoverable. - - FLAGS is a bitmask consisting of the following flags: + + FLAGS is a bitmask consisting of the following flags: 2: The function has a definition. 4: The function is a friend. @@ -1374,7 +1866,7 @@ copy_default_args_to_explicit_spec (decl) template struct S { void f(); }; void S::f(); - + the TEMPLATE_COUNT would be 1. However, explicitly specialized classes are not counted in the TEMPLATE_COUNT, so that in @@ -1383,19 +1875,18 @@ copy_default_args_to_explicit_spec (decl) template <> void S::f(); the TEMPLATE_COUNT would be 0. (Note that this declaration is - illegal; there should be no template <>.) + invalid; 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 + is set up correctly, and it is added to the list of specializations for that template. */ tree -check_explicit_specialization (declarator, decl, template_count, flags) - tree declarator; - tree decl; - int template_count; - int flags; +check_explicit_specialization (tree declarator, + tree decl, + int template_count, + int flags) { int have_def = flags & 2; int is_friend = flags & 4; @@ -1406,12 +1897,20 @@ check_explicit_specialization (declarator, decl, template_count, flags) tree dname = DECL_NAME (decl); tmpl_spec_kind tsk; - tsk = current_tmpl_spec_kind (template_count); + if (is_friend) + { + if (!processing_specialization) + tsk = tsk_none; + else + tsk = tsk_excessive_parms; + } + else + tsk = current_tmpl_spec_kind (template_count); switch (tsk) { case tsk_none: - if (processing_specialization) + if (processing_specialization) { specialization = 1; SET_DECL_TEMPLATE_SPECIALIZATION (decl); @@ -1429,8 +1928,8 @@ check_explicit_specialization (declarator, decl, template_count, flags) /* This case handles bogus declarations like template <> template void f(); */ - error ("template-id `%D' in declaration of primary template", - declarator); + error ("template-id %qD in declaration of primary template", + declarator); return decl; } } @@ -1449,14 +1948,20 @@ check_explicit_specialization (declarator, decl, template_count, flags) case tsk_expl_inst: if (have_def) error ("definition provided for explicit instantiation"); - + explicit_instantiation = 1; break; case tsk_excessive_parms: - error ("too many template parameter lists in declaration of `%D'", - decl); - return error_mark_node; + case tsk_insufficient_parms: + if (tsk == tsk_excessive_parms) + error ("too many template parameter lists in declaration of %qD", + decl); + else if (template_header_count) + error("too few template parameter lists in declaration of %qD", decl); + else + error("explicit specialization of %qD must be introduced by " + "%