Commit 2b110bfc by Jason Merrill Committed by Jason Merrill

Use hash tables for template specialization lookup.

	* pt.c (struct spec_entry): New type.
	(decl_specializations, type_specializations): New hash tables.
	(register_specialization, retrieve_specialization): Use them.
	(reregister_specialization, lookup_template_class): Use them.
	(eq_specializations, hash_tmpl_and_args, hash_specialization): New.
	(iterative_hash_template_arg): New.
	(init_template_processing): New
	(process_partial_specialization): Don't look to see if we already
	have this partial specialization.
	(maybe_process_partial_specialization): Handle reassigning
	full specializations when we get an explicit specialization
	of the partial instantiation.
	(tsubst_friend_function): Adjust specialization reassignment code.
	(instantiate_template): Only do one lookup.
	(instantiate_decl): Don't do any lookup.
	* cp-tree.h: Declare init_template_processing.
	* decl.c (duplicate_decls): Pass args to reregister_specialization.

From-SVN: r149188
parent 74c9e852
2009-07-02 Jason Merrill <jason@redhat.com>
Use hash tables for template specialization lookup.
* pt.c (struct spec_entry): New type.
(decl_specializations, type_specializations): New hash tables.
(register_specialization, retrieve_specialization): Use them.
(reregister_specialization, lookup_template_class): Use them.
(eq_specializations, hash_tmpl_and_args, hash_specialization): New.
(iterative_hash_template_arg): New.
(init_template_processing): New
(process_partial_specialization): Don't look to see if we already
have this partial specialization.
(maybe_process_partial_specialization): Handle reassigning
full specializations when we get an explicit specialization
of the partial instantiation.
(tsubst_friend_function): Adjust specialization reassignment code.
(instantiate_template): Only do one lookup.
(instantiate_decl): Don't do any lookup.
* cp-tree.h: Declare init_template_processing.
* decl.c (duplicate_decls): Pass args to reregister_specialization.
2009-07-01 Jason Merrill <jason@redhat.com> 2009-07-01 Jason Merrill <jason@redhat.com>
* cp-tree.h (DECL_CLASS_TEMPLATE_P): Use DECL_IMPLICIT_TYPEDEF_P. * cp-tree.h (DECL_CLASS_TEMPLATE_P): Use DECL_IMPLICIT_TYPEDEF_P.
......
...@@ -3072,15 +3072,18 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -3072,15 +3072,18 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (NODE)) TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (NODE))
/* For function, method, class-data templates. */ /* For function, method, class-data templates. */
#define DECL_TEMPLATE_RESULT(NODE) DECL_RESULT_FLD (NODE) #define DECL_TEMPLATE_RESULT(NODE) DECL_RESULT_FLD (NODE)
/* For a static member variable template, the /* For a function template at namespace scope, DECL_TEMPLATE_INSTANTIATIONS
DECL_TEMPLATE_INSTANTIATIONS list contains the explicitly and lists all instantiations and specializations of the function so that
implicitly generated instantiations of the variable. There are no tsubst_friend_function can reassign them to another template if we find
partial instantiations of static member variables, so all of these that the namespace-scope template is really a partial instantiation of a
will be full instantiations. friend template.
For a class template the DECL_TEMPLATE_INSTANTIATIONS lists holds For a class template the DECL_TEMPLATE_INSTANTIATIONS lists holds
all instantiations and specializations of the class type, including all instantiations and specializations of the class type, including
partial instantiations and partial specializations. partial instantiations and partial specializations, so that if we
explicitly specialize a partial instantiation we can walk the list
in maybe_process_partial_specialization and reassign them or complain
as appropriate.
In both cases, the TREE_PURPOSE of each node contains the arguments In both cases, the TREE_PURPOSE of each node contains the arguments
used; the TREE_VALUE contains the generated variable. The template used; the TREE_VALUE contains the generated variable. The template
...@@ -3096,29 +3099,9 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -3096,29 +3099,9 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
DECL_TEMPLATE_INSTANTIATIONS list for `template <class T> template DECL_TEMPLATE_INSTANTIATIONS list for `template <class T> template
<class U> struct S1<T>::S2'. <class U> struct S1<T>::S2'.
This list is not used for function templates. */ This list is not used for other templates. */
#define DECL_TEMPLATE_INSTANTIATIONS(NODE) DECL_VINDEX (NODE) #define DECL_TEMPLATE_INSTANTIATIONS(NODE) DECL_VINDEX (NODE)
/* For a function template, the DECL_TEMPLATE_SPECIALIZATIONS lists /* For a class template, this list contains the partial
contains all instantiations and specializations of the function,
including partial instantiations. For a partial instantiation
which is a specialization, this list holds only full
specializations of the template that are instantiations of the
partial instantiation. For example, given:
template <class T> struct S {
template <class U> void f(U);
template <> void f(T);
};
the `S<int>::f<int>(int)' function will appear on the
DECL_TEMPLATE_SPECIALIZATIONS list for both `template <class T>
template <class U> void S<T>::f(U)' and `template <class T> void
S<int>::f(T)'. In the latter case, however, it will have only the
innermost set of arguments (T, in this case). The DECL_TI_TEMPLATE
for the function declaration will point at the specialization, not
the fully general template.
For a class template, this list contains the partial
specializations of this template. (Full specializations are not specializations of this template. (Full specializations are not
recorded on this list.) The TREE_PURPOSE holds the arguments used recorded on this list.) The TREE_PURPOSE holds the arguments used
in the partial specialization (e.g., for `template <class T> struct in the partial specialization (e.g., for `template <class T> struct
...@@ -3128,7 +3111,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -3128,7 +3111,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
example above.) The TREE_TYPE is the _TYPE node for the partial example above.) The TREE_TYPE is the _TYPE node for the partial
specialization. specialization.
This list is not used for static variable templates. */ This list is not used for other templates. */
#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE (NODE) #define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE (NODE)
/* Nonzero for a DECL which is actually a template parameter. Keep /* Nonzero for a DECL which is actually a template parameter. Keep
...@@ -4619,6 +4602,7 @@ extern tree fold_non_dependent_expr (tree); ...@@ -4619,6 +4602,7 @@ extern tree fold_non_dependent_expr (tree);
extern bool explicit_class_specialization_p (tree); extern bool explicit_class_specialization_p (tree);
extern struct tinst_level *outermost_tinst_level(void); extern struct tinst_level *outermost_tinst_level(void);
extern bool parameter_of_template_p (tree, tree); extern bool parameter_of_template_p (tree, tree);
extern void init_template_processing (void);
/* in repo.c */ /* in repo.c */
extern void init_repo (void); extern void init_repo (void);
......
...@@ -1109,7 +1109,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) ...@@ -1109,7 +1109,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
unsigned olddecl_uid = DECL_UID (olddecl); unsigned olddecl_uid = DECL_UID (olddecl);
int olddecl_friend = 0, types_match = 0, hidden_friend = 0; int olddecl_friend = 0, types_match = 0, hidden_friend = 0;
int new_defines_function = 0; int new_defines_function = 0;
tree new_template; tree new_template_info;
if (newdecl == olddecl) if (newdecl == olddecl)
return olddecl; return olddecl;
...@@ -1855,7 +1855,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) ...@@ -1855,7 +1855,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
if (! DECL_EXTERNAL (olddecl)) if (! DECL_EXTERNAL (olddecl))
DECL_EXTERNAL (newdecl) = 0; DECL_EXTERNAL (newdecl) = 0;
new_template = NULL_TREE; new_template_info = NULL_TREE;
if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl)) if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl))
{ {
bool new_redefines_gnu_inline = false; bool new_redefines_gnu_inline = false;
...@@ -1899,7 +1899,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) ...@@ -1899,7 +1899,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl); DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
DECL_REPO_AVAILABLE_P (newdecl) = DECL_REPO_AVAILABLE_P (olddecl); DECL_REPO_AVAILABLE_P (newdecl) = DECL_REPO_AVAILABLE_P (olddecl);
if (DECL_TEMPLATE_INFO (newdecl)) if (DECL_TEMPLATE_INFO (newdecl))
new_template = DECL_TI_TEMPLATE (newdecl); new_template_info = DECL_TEMPLATE_INFO (newdecl);
DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
DECL_INITIALIZED_IN_CLASS_P (newdecl) DECL_INITIALIZED_IN_CLASS_P (newdecl)
|= DECL_INITIALIZED_IN_CLASS_P (olddecl); |= DECL_INITIALIZED_IN_CLASS_P (olddecl);
...@@ -2097,7 +2097,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) ...@@ -2097,7 +2097,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
memcpy ((char *) olddecl + sizeof (struct tree_decl_common), memcpy ((char *) olddecl + sizeof (struct tree_decl_common),
(char *) newdecl + sizeof (struct tree_decl_common), (char *) newdecl + sizeof (struct tree_decl_common),
sizeof (struct tree_function_decl) - sizeof (struct tree_decl_common)); sizeof (struct tree_function_decl) - sizeof (struct tree_decl_common));
if (new_template) if (new_template_info)
/* If newdecl is a template instantiation, it is possible that /* If newdecl is a template instantiation, it is possible that
the following sequence of events has occurred: the following sequence of events has occurred:
...@@ -2120,7 +2120,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) ...@@ -2120,7 +2120,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
instantiations so that if we try to do the instantiation instantiations so that if we try to do the instantiation
again we won't get the clobbered declaration. */ again we won't get the clobbered declaration. */
reregister_specialization (newdecl, reregister_specialization (newdecl,
new_template, new_template_info,
olddecl); olddecl);
} }
else else
...@@ -3459,6 +3459,7 @@ cxx_init_decl_processing (void) ...@@ -3459,6 +3459,7 @@ cxx_init_decl_processing (void)
/* Perform other language dependent initializations. */ /* Perform other language dependent initializations. */
init_class_processing (); init_class_processing ();
init_rtti_processing (); init_rtti_processing ();
init_template_processing ();
if (flag_exceptions) if (flag_exceptions)
init_exception_processing (); init_exception_processing ();
......
...@@ -82,6 +82,19 @@ static tree cur_stmt_expr; ...@@ -82,6 +82,19 @@ static tree cur_stmt_expr;
local variables. */ local variables. */
static htab_t local_specializations; static htab_t local_specializations;
typedef struct GTY(()) spec_entry
{
tree tmpl;
tree args;
tree spec;
} spec_entry;
static GTY ((param_is (spec_entry)))
htab_t decl_specializations;
static GTY ((param_is (spec_entry)))
htab_t type_specializations;
/* Contains canonical template parameter types. The vector is indexed by /* Contains canonical template parameter types. The vector is indexed by
the TEMPLATE_TYPE_IDX of the template parameter. Each element is a the TEMPLATE_TYPE_IDX of the template parameter. Each element is a
TREE_LIST, whose TREE_VALUEs contain the canonical template TREE_LIST, whose TREE_VALUEs contain the canonical template
...@@ -133,6 +146,7 @@ static bool inline_needs_template_parms (tree); ...@@ -133,6 +146,7 @@ static bool inline_needs_template_parms (tree);
static void push_inline_template_parms_recursive (tree, int); static void push_inline_template_parms_recursive (tree, int);
static tree retrieve_local_specialization (tree); static tree retrieve_local_specialization (tree);
static void register_local_specialization (tree, tree); static void register_local_specialization (tree, tree);
static hashval_t hash_specialization (const void *p);
static tree reduce_template_parm_level (tree, tree, int, tree, tsubst_flags_t); static tree reduce_template_parm_level (tree, tree, int, tree, tsubst_flags_t);
static int mark_template_parm (tree, void *); static int mark_template_parm (tree, void *);
static int template_parm_this_level_p (tree, void *); static int template_parm_this_level_p (tree, void *);
...@@ -176,6 +190,7 @@ static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree); ...@@ -176,6 +190,7 @@ static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
static tree tsubst_decl (tree, tree, tsubst_flags_t); static tree tsubst_decl (tree, tree, tsubst_flags_t);
static void perform_typedefs_access_check (tree tmpl, tree targs); static void perform_typedefs_access_check (tree tmpl, tree targs);
static void append_type_to_template_for_access_check_1 (tree, tree, tree); static void append_type_to_template_for_access_check_1 (tree, tree, tree);
static hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
/* Make the current scope suitable for access checking when we are /* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function processing T. T can be FUNCTION_DECL for instantiated function
...@@ -811,13 +826,13 @@ maybe_process_partial_specialization (tree type) ...@@ -811,13 +826,13 @@ maybe_process_partial_specialization (tree type)
&& !COMPLETE_TYPE_P (type)) && !COMPLETE_TYPE_P (type))
{ {
tree t; tree t;
tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
if (current_namespace if (current_namespace
!= decl_namespace_context (CLASSTYPE_TI_TEMPLATE (type))) != decl_namespace_context (tmpl))
{ {
permerror (input_location, "specializing %q#T in different namespace", type); permerror (input_location, "specializing %q#T in different namespace", type);
permerror (input_location, " from definition of %q+#D", permerror (input_location, " from definition of %q+#D", tmpl);
CLASSTYPE_TI_TEMPLATE (type));
} }
/* Check for invalid specialization after instantiation: /* Check for invalid specialization after instantiation:
...@@ -825,13 +840,38 @@ maybe_process_partial_specialization (tree type) ...@@ -825,13 +840,38 @@ maybe_process_partial_specialization (tree type)
template <> template <> class C<int>::D<int>; template <> template <> class C<int>::D<int>;
template <> template <class U> class C<int>::D; */ template <> template <class U> class C<int>::D; */
for (t = DECL_TEMPLATE_INSTANTIATIONS for (t = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
(most_general_template (CLASSTYPE_TI_TEMPLATE (type)));
t; t = TREE_CHAIN (t)) t; t = TREE_CHAIN (t))
if (TREE_VALUE (t) != type {
&& TYPE_CONTEXT (TREE_VALUE (t)) == context) tree inst = TREE_VALUE (t);
error ("specialization %qT after instantiation %qT", if (CLASSTYPE_TEMPLATE_SPECIALIZATION (inst))
type, TREE_VALUE (t)); {
/* We already have a full specialization of this partial
instantiation. Reassign it to the new member
specialization template. */
spec_entry elt;
spec_entry **slot;
elt.tmpl = most_general_template (tmpl);
elt.args = CLASSTYPE_TI_ARGS (inst);
elt.spec = inst;
htab_remove_elt (type_specializations, &elt);
elt.tmpl = tmpl;
elt.args = INNERMOST_TEMPLATE_ARGS (elt.args);
slot = (spec_entry **)
htab_find_slot (type_specializations, &elt, INSERT);
*slot = GGC_NEW (spec_entry);
**slot = elt;
}
else if (COMPLETE_TYPE_P (inst) || TYPE_BEING_DEFINED (inst))
/* But if we've had an implicit instantiation, that's a
problem ([temp.expl.spec]/6). */
error ("specialization %qT after instantiation %qT",
type, inst);
}
/* Mark TYPE as a specialization. And as a result, we only /* Mark TYPE as a specialization. And as a result, we only
have one level of template argument for the innermost have one level of template argument for the innermost
...@@ -895,8 +935,7 @@ optimize_specialization_lookup_p (tree tmpl) ...@@ -895,8 +935,7 @@ optimize_specialization_lookup_p (tree tmpl)
parameter is ignored if TMPL is not a class template. */ parameter is ignored if TMPL is not a class template. */
static tree static tree
retrieve_specialization (tree tmpl, tree args, retrieve_specialization (tree tmpl, tree args, hashval_t hash)
bool class_specializations_p)
{ {
if (args == error_mark_node) if (args == error_mark_node)
return NULL_TREE; return NULL_TREE;
...@@ -921,8 +960,7 @@ retrieve_specialization (tree tmpl, tree args, ...@@ -921,8 +960,7 @@ retrieve_specialization (tree tmpl, tree args,
arguments. */ arguments. */
class_template = CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (tmpl)); class_template = CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (tmpl));
class_specialization class_specialization
= retrieve_specialization (class_template, args, = retrieve_specialization (class_template, args, 0);
/*class_specializations_p=*/false);
if (!class_specialization) if (!class_specialization)
return NULL_TREE; return NULL_TREE;
/* Now, find the appropriate entry in the CLASSTYPE_METHOD_VEC /* Now, find the appropriate entry in the CLASSTYPE_METHOD_VEC
...@@ -943,39 +981,24 @@ retrieve_specialization (tree tmpl, tree args, ...@@ -943,39 +981,24 @@ retrieve_specialization (tree tmpl, tree args,
} }
else else
{ {
tree *sp; spec_entry *found;
tree *head; spec_entry elt;
htab_t specializations;
/* Class templates store their instantiations on the
DECL_TEMPLATE_INSTANTIATIONS list; other templates use the elt.tmpl = tmpl;
DECL_TEMPLATE_SPECIALIZATIONS list. */ elt.args = args;
if (!class_specializations_p elt.spec = NULL_TREE;
&& TREE_CODE (DECL_TEMPLATE_RESULT (tmpl)) == TYPE_DECL
&& !is_typedef_decl (DECL_TEMPLATE_RESULT (tmpl)) if (DECL_CLASS_TEMPLATE_P (tmpl))
&& TAGGED_TYPE_P (TREE_TYPE (tmpl))) specializations = type_specializations;
sp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
else else
sp = &DECL_TEMPLATE_SPECIALIZATIONS (tmpl); specializations = decl_specializations;
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)) if (hash == 0)
{ hash = hash_specialization (&elt);
/* Use the move-to-front heuristic to speed up future found = (spec_entry *) htab_find_with_hash (specializations, &elt, hash);
searches. */ if (found)
if (spec != *head) return found->spec;
{
*sp = TREE_CHAIN (*sp);
TREE_CHAIN (spec) = *head;
*head = spec;
}
return TREE_VALUE (spec);
}
sp = &TREE_CHAIN (spec);
}
} }
return NULL_TREE; return NULL_TREE;
...@@ -1214,11 +1237,14 @@ is_specialization_of_friend (tree decl, tree friend_decl) ...@@ -1214,11 +1237,14 @@ is_specialization_of_friend (tree decl, tree friend_decl)
equivalent prior declaration, if available. */ equivalent prior declaration, if available. */
static tree static tree
register_specialization (tree spec, tree tmpl, tree args, bool is_friend) register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
hashval_t hash)
{ {
tree fn; tree fn;
spec_entry **slot = NULL;
spec_entry elt;
gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL); gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL && DECL_P (spec));
if (TREE_CODE (spec) == FUNCTION_DECL if (TREE_CODE (spec) == FUNCTION_DECL
&& uses_template_parms (DECL_TI_ARGS (spec))) && uses_template_parms (DECL_TI_ARGS (spec)))
...@@ -1235,8 +1261,27 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend) ...@@ -1235,8 +1261,27 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend)
instantiation unless and until it is actually needed. */ instantiation unless and until it is actually needed. */
return spec; return spec;
fn = retrieve_specialization (tmpl, args, if (optimize_specialization_lookup_p (tmpl))
/*class_specializations_p=*/false); /* We don't put these specializations in the hash table, but we might
want to give an error about a mismatch. */
fn = retrieve_specialization (tmpl, args, 0);
else
{
elt.tmpl = tmpl;
elt.args = args;
elt.spec = spec;
if (hash == 0)
hash = hash_specialization (&elt);
slot = (spec_entry **)
htab_find_slot_with_hash (decl_specializations, &elt, hash, INSERT);
if (*slot)
fn = (*slot)->spec;
else
fn = NULL_TREE;
}
/* We can sometimes try to re-register a specialization that we've /* We can sometimes try to re-register a specialization that we've
already got. In particular, regenerate_decl_from_template calls already got. In particular, regenerate_decl_from_template calls
duplicate_decls which will update the specialization list. But, duplicate_decls which will update the specialization list. But,
...@@ -1322,32 +1367,216 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend) ...@@ -1322,32 +1367,216 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend)
DECL_CONTEXT (spec) = DECL_CONTEXT (tmpl); DECL_CONTEXT (spec) = DECL_CONTEXT (tmpl);
if (!optimize_specialization_lookup_p (tmpl)) if (!optimize_specialization_lookup_p (tmpl))
DECL_TEMPLATE_SPECIALIZATIONS (tmpl) {
= tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl)); gcc_assert (tmpl && args && spec);
*slot = GGC_NEW (spec_entry);
**slot = elt;
if (TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec)
&& PRIMARY_TEMPLATE_P (tmpl)
&& DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE)
/* TMPL is a forward declaration of a template function; keep a list
of all specializations in case we need to reassign them to a friend
template later in tsubst_friend_function. */
DECL_TEMPLATE_INSTANTIATIONS (tmpl)
= tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
}
return spec; return spec;
} }
/* Returns true iff two spec_entry nodes are equivalent. Only compares the
TMPL and ARGS members, ignores SPEC. */
static int
eq_specializations (const void *p1, const void *p2)
{
const spec_entry *e1 = (const spec_entry *)p1;
const spec_entry *e2 = (const spec_entry *)p2;
return (e1->tmpl == e2->tmpl
&& comp_template_args (e1->args, e2->args));
}
/* Returns a hash for a template TMPL and template arguments ARGS. */
static hashval_t
hash_tmpl_and_args (tree tmpl, tree args)
{
hashval_t val = DECL_UID (tmpl);
return iterative_hash_template_arg (args, val);
}
/* Returns a hash for a spec_entry node based on the TMPL and ARGS members,
ignoring SPEC. */
static hashval_t
hash_specialization (const void *p)
{
const spec_entry *e = (const spec_entry *)p;
return hash_tmpl_and_args (e->tmpl, e->args);
}
/* Recursively calculate a hash value for a template argument ARG, for use
in the hash tables of template specializations. */
static hashval_t
iterative_hash_template_arg (tree arg, hashval_t val)
{
unsigned HOST_WIDE_INT i;
enum tree_code code;
char tclass;
if (arg == NULL_TREE)
return iterative_hash_object (arg, val);
if (!TYPE_P (arg))
STRIP_NOPS (arg);
code = TREE_CODE (arg);
tclass = TREE_CODE_CLASS (code);
val = iterative_hash_object (code, val);
switch (code)
{
case ERROR_MARK:
return val;
case IDENTIFIER_NODE:
return iterative_hash_object (IDENTIFIER_HASH_VALUE (arg), val);
case TREE_VEC:
{
int i, len = TREE_VEC_LENGTH (arg);
for (i = 0; i < len; ++i)
val = iterative_hash_template_arg (TREE_VEC_ELT (arg, i), val);
return val;
}
case TYPE_PACK_EXPANSION:
case EXPR_PACK_EXPANSION:
return iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), val);
case ARGUMENT_PACK_SELECT:
/* We can get one of these when re-hashing a previous entry in the middle
of substituting into a pack expansion. Just look through it... */
arg = ARGUMENT_PACK_SELECT_FROM_PACK (arg);
/* ...and fall through. */
case TYPE_ARGUMENT_PACK:
case NONTYPE_ARGUMENT_PACK:
return iterative_hash_template_arg (ARGUMENT_PACK_ARGS (arg), val);
case TREE_LIST:
for (; arg; arg = TREE_CHAIN (arg))
val = iterative_hash_template_arg (TREE_VALUE (arg), val);
return val;
case OVERLOAD:
for (; arg; arg = OVL_CHAIN (arg))
val = iterative_hash_template_arg (OVL_FUNCTION (arg), val);
return val;
case CONSTRUCTOR:
{
tree field, value;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg), i, field, value)
{
val = iterative_hash_template_arg (field, val);
val = iterative_hash_template_arg (value, val);
}
return val;
}
case PARM_DECL:
/* I tried hashing parm_index as well, but in some cases we get
called too soon for that to work, so just hash the type and let
lookup check that the index matches. */
return iterative_hash_template_arg (TREE_TYPE (arg), val);
case TARGET_EXPR:
return iterative_hash_template_arg (TARGET_EXPR_INITIAL (arg), val);
case PTRMEM_CST:
val = iterative_hash_template_arg (PTRMEM_CST_CLASS (arg), val);
return iterative_hash_template_arg (PTRMEM_CST_MEMBER (arg), val);
case TEMPLATE_PARM_INDEX:
val = iterative_hash_template_arg
(TREE_TYPE (TEMPLATE_PARM_DECL (arg)), val);
val = iterative_hash_object (TEMPLATE_PARM_LEVEL (arg), val);
return iterative_hash_object (TEMPLATE_PARM_IDX (arg), val);
case TRAIT_EXPR:
val = iterative_hash_object (TRAIT_EXPR_KIND (arg), val);
val = iterative_hash_template_arg (TRAIT_EXPR_TYPE1 (arg), val);
return iterative_hash_template_arg (TRAIT_EXPR_TYPE2 (arg), val);
case BASELINK:
val = iterative_hash_template_arg (BINFO_TYPE (BASELINK_BINFO (arg)),
val);
return iterative_hash_template_arg (DECL_NAME (get_first_fn (arg)),
val);
case MODOP_EXPR:
val = iterative_hash_template_arg (TREE_OPERAND (arg, 0), val);
code = TREE_CODE (TREE_OPERAND (arg, 1));
val = iterative_hash_object (code, val);
return iterative_hash_template_arg (TREE_OPERAND (arg, 2), val);
default:
switch (tclass)
{
case tcc_type:
if (TYPE_CANONICAL (arg))
return iterative_hash_object (TYPE_HASH (TYPE_CANONICAL (arg)),
val);
else if (TREE_CODE (arg) == DECLTYPE_TYPE)
return iterative_hash_template_arg (DECLTYPE_TYPE_EXPR (arg), val);
/* Otherwise just compare the types during lookup. */
return val;
case tcc_declaration:
case tcc_constant:
return iterative_hash_expr (arg, val);
default:
gcc_assert (IS_EXPR_CODE_CLASS (tclass));
{
unsigned n = TREE_OPERAND_LENGTH (arg);
for (i = 0; i < n; ++i)
val = iterative_hash_template_arg (TREE_OPERAND (arg, i), val);
return val;
}
}
}
gcc_unreachable ();
return 0;
}
/* Unregister the specialization SPEC as a specialization of TMPL. /* Unregister the specialization SPEC as a specialization of TMPL.
Replace it with NEW_SPEC, if NEW_SPEC is non-NULL. Returns true Replace it with NEW_SPEC, if NEW_SPEC is non-NULL. Returns true
if the SPEC was listed as a specialization of TMPL. */ if the SPEC was listed as a specialization of TMPL.
Note that SPEC has been ggc_freed, so we can't look inside it. */
bool bool
reregister_specialization (tree spec, tree tmpl, tree new_spec) reregister_specialization (tree spec, tree tinfo, tree new_spec)
{ {
tree* s; spec_entry **slot;
spec_entry elt;
for (s = &DECL_TEMPLATE_SPECIALIZATIONS (tmpl); elt.tmpl = most_general_template (TI_TEMPLATE (tinfo));
*s != NULL_TREE; elt.args = TI_ARGS (tinfo);
s = &TREE_CHAIN (*s)) elt.spec = NULL_TREE;
if (TREE_VALUE (*s) == spec)
{ slot = (spec_entry **) htab_find_slot (decl_specializations, &elt, INSERT);
if (!new_spec) if (*slot)
*s = TREE_CHAIN (*s); {
else gcc_assert ((*slot)->spec == spec || (*slot)->spec == new_spec);
TREE_VALUE (*s) = new_spec; gcc_assert (new_spec != NULL_TREE);
return 1; (*slot)->spec = new_spec;
} return 1;
}
return 0; return 0;
} }
...@@ -2241,7 +2470,7 @@ check_explicit_specialization (tree declarator, ...@@ -2241,7 +2470,7 @@ check_explicit_specialization (tree declarator,
DECL_CONTEXT (parm) = result; DECL_CONTEXT (parm) = result;
} }
return register_specialization (tmpl, gen_tmpl, targs, return register_specialization (tmpl, gen_tmpl, targs,
is_friend); is_friend, 0);
} }
/* Set up the DECL_TEMPLATE_INFO for DECL. */ /* Set up the DECL_TEMPLATE_INFO for DECL. */
...@@ -2319,7 +2548,7 @@ check_explicit_specialization (tree declarator, ...@@ -2319,7 +2548,7 @@ check_explicit_specialization (tree declarator,
/* Register this specialization so that we can find it /* Register this specialization so that we can find it
again. */ again. */
decl = register_specialization (decl, gen_tmpl, targs, is_friend); decl = register_specialization (decl, gen_tmpl, targs, is_friend, 0);
} }
} }
...@@ -3514,10 +3743,8 @@ process_partial_specialization (tree decl) ...@@ -3514,10 +3743,8 @@ process_partial_specialization (tree decl)
} }
} }
if (retrieve_specialization (maintmpl, specargs, /* We should only get here once. */
/*class_specializations_p=*/true)) gcc_assert (!COMPLETE_TYPE_P (type));
/* We've already got this specialization. */
return decl;
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)
= tree_cons (specargs, inner_parms, = tree_cons (specargs, inner_parms,
...@@ -3997,7 +4224,7 @@ push_template_decl_real (tree decl, bool is_friend) ...@@ -3997,7 +4224,7 @@ push_template_decl_real (tree decl, bool is_friend)
register_specialization (new_tmpl, register_specialization (new_tmpl,
most_general_template (tmpl), most_general_template (tmpl),
args, args,
is_friend); is_friend, 0);
return decl; return decl;
} }
...@@ -5617,6 +5844,10 @@ lookup_template_class (tree d1, ...@@ -5617,6 +5844,10 @@ lookup_template_class (tree d1,
{ {
tree templ = NULL_TREE, parmlist; tree templ = NULL_TREE, parmlist;
tree t; tree t;
spec_entry **slot;
spec_entry *entry;
spec_entry elt;
hashval_t hash;
timevar_push (TV_NAME_LOOKUP); timevar_push (TV_NAME_LOOKUP);
...@@ -5782,7 +6013,6 @@ lookup_template_class (tree d1, ...@@ -5782,7 +6013,6 @@ lookup_template_class (tree d1,
/* From here on, we're only interested in the most general /* From here on, we're only interested in the most general
template. */ template. */
templ = gen_tmpl;
/* Calculate the BOUND_ARGS. These will be the args that are /* Calculate the BOUND_ARGS. These will be the args that are
actually tsubst'd into the definition to create the actually tsubst'd into the definition to create the
...@@ -5796,12 +6026,12 @@ lookup_template_class (tree d1, ...@@ -5796,12 +6026,12 @@ lookup_template_class (tree d1,
tree bound_args = make_tree_vec (parm_depth); tree bound_args = make_tree_vec (parm_depth);
for (i = saved_depth, for (i = saved_depth,
t = DECL_TEMPLATE_PARMS (templ); t = DECL_TEMPLATE_PARMS (gen_tmpl);
i > 0 && t != NULL_TREE; i > 0 && t != NULL_TREE;
--i, t = TREE_CHAIN (t)) --i, t = TREE_CHAIN (t))
{ {
tree a = coerce_template_parms (TREE_VALUE (t), tree a = coerce_template_parms (TREE_VALUE (t),
arglist, templ, arglist, gen_tmpl,
complain, complain,
/*require_all_args=*/true, /*require_all_args=*/true,
/*use_default_args=*/true); /*use_default_args=*/true);
...@@ -5832,7 +6062,7 @@ lookup_template_class (tree d1, ...@@ -5832,7 +6062,7 @@ lookup_template_class (tree d1,
arglist arglist
= coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parmlist), = coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parmlist),
INNERMOST_TEMPLATE_ARGS (arglist), INNERMOST_TEMPLATE_ARGS (arglist),
templ, gen_tmpl,
complain, complain,
/*require_all_args=*/true, /*require_all_args=*/true,
/*use_default_args=*/true); /*use_default_args=*/true);
...@@ -5850,7 +6080,7 @@ lookup_template_class (tree d1, ...@@ -5850,7 +6080,7 @@ lookup_template_class (tree d1,
the `C<T>' is just the same as `C'. Outside of the the `C<T>' is just the same as `C'. Outside of the
class, however, such a reference is an instantiation. */ class, however, such a reference is an instantiation. */
if ((entering_scope if ((entering_scope
|| !PRIMARY_TEMPLATE_P (templ) || !PRIMARY_TEMPLATE_P (gen_tmpl)
|| currently_open_class (template_type)) || currently_open_class (template_type))
/* comp_template_args is expensive, check it last. */ /* comp_template_args is expensive, check it last. */
&& comp_template_args (TYPE_TI_ARGS (template_type), && comp_template_args (TYPE_TI_ARGS (template_type),
...@@ -5858,10 +6088,14 @@ lookup_template_class (tree d1, ...@@ -5858,10 +6088,14 @@ lookup_template_class (tree d1,
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, template_type); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, template_type);
/* If we already have this specialization, return it. */ /* If we already have this specialization, return it. */
found = retrieve_specialization (templ, arglist, elt.tmpl = gen_tmpl;
/*class_specializations_p=*/false); elt.args = arglist;
if (found) hash = hash_specialization (&elt);
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, found); entry = (spec_entry *) htab_find_with_hash (type_specializations,
&elt, hash);
if (entry)
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, entry->spec);
/* This type is a "partial instantiation" if any of the template /* This type is a "partial instantiation" if any of the template
arguments still involve template parameters. Note that we set arguments still involve template parameters. Note that we set
...@@ -5872,22 +6106,22 @@ lookup_template_class (tree d1, ...@@ -5872,22 +6106,22 @@ lookup_template_class (tree d1,
/* If the deduced arguments are invalid, then the binding /* If the deduced arguments are invalid, then the binding
failed. */ failed. */
if (!is_partial_instantiation if (!is_partial_instantiation
&& check_instantiated_args (templ, && check_instantiated_args (gen_tmpl,
INNERMOST_TEMPLATE_ARGS (arglist), INNERMOST_TEMPLATE_ARGS (arglist),
complain)) complain))
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
if (!is_partial_instantiation if (!is_partial_instantiation
&& !PRIMARY_TEMPLATE_P (templ) && !PRIMARY_TEMPLATE_P (gen_tmpl)
&& TREE_CODE (CP_DECL_CONTEXT (templ)) == NAMESPACE_DECL) && TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL)
{ {
found = xref_tag_from_type (TREE_TYPE (templ), found = xref_tag_from_type (TREE_TYPE (gen_tmpl),
DECL_NAME (templ), DECL_NAME (gen_tmpl),
/*tag_scope=*/ts_global); /*tag_scope=*/ts_global);
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, found); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, found);
} }
context = tsubst (DECL_CONTEXT (templ), arglist, context = tsubst (DECL_CONTEXT (gen_tmpl), arglist,
complain, in_decl); complain, in_decl);
if (!context) if (!context)
context = global_namespace; context = global_namespace;
...@@ -5923,7 +6157,7 @@ lookup_template_class (tree d1, ...@@ -5923,7 +6157,7 @@ lookup_template_class (tree d1,
/* A local class. Make sure the decl gets registered properly. */ /* A local class. Make sure the decl gets registered properly. */
if (context == current_function_decl) if (context == current_function_decl)
pushtag (DECL_NAME (templ), t, /*tag_scope=*/ts_current); pushtag (DECL_NAME (gen_tmpl), t, /*tag_scope=*/ts_current);
if (comp_template_args (CLASSTYPE_TI_ARGS (template_type), arglist)) if (comp_template_args (CLASSTYPE_TI_ARGS (template_type), arglist))
/* This instantiation is another name for the primary /* This instantiation is another name for the primary
...@@ -5943,7 +6177,7 @@ lookup_template_class (tree d1, ...@@ -5943,7 +6177,7 @@ lookup_template_class (tree d1,
{ {
TYPE_CONTEXT (t) = FROB_CONTEXT (context); TYPE_CONTEXT (t) = FROB_CONTEXT (context);
type_decl = create_implicit_typedef (DECL_NAME (templ), t); type_decl = create_implicit_typedef (DECL_NAME (gen_tmpl), t);
DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t); DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);
TYPE_STUB_DECL (t) = type_decl; TYPE_STUB_DECL (t) = type_decl;
DECL_SOURCE_LOCATION (type_decl) DECL_SOURCE_LOCATION (type_decl)
...@@ -5966,65 +6200,32 @@ lookup_template_class (tree d1, ...@@ -5966,65 +6200,32 @@ lookup_template_class (tree d1,
template is the immediate parent if this is a full template is the immediate parent if this is a full
instantiation. */ instantiation. */
if (parm_depth == 1 || is_partial_instantiation if (parm_depth == 1 || is_partial_instantiation
|| !PRIMARY_TEMPLATE_P (templ)) || !PRIMARY_TEMPLATE_P (gen_tmpl))
/* This case is easy; there are no member templates involved. */ /* This case is easy; there are no member templates involved. */
found = templ; found = gen_tmpl;
else else
{ {
/* This is a full instantiation of a member template. Look /* This is a full instantiation of a member template. Find
for a partial instantiation of which this is an instance. */ the partial instantiation of which this is an instance. */
for (found = DECL_TEMPLATE_INSTANTIATIONS (templ); /* Temporarily reduce by one the number of levels in the ARGLIST
found; found = TREE_CHAIN (found)) so as to avoid comparing the last set of arguments. */
{ TREE_VEC_LENGTH (arglist)--;
int success; found = tsubst (gen_tmpl, arglist, complain, NULL_TREE);
tree tmpl = CLASSTYPE_TI_TEMPLATE (TREE_VALUE (found)); TREE_VEC_LENGTH (arglist)++;
found = CLASSTYPE_TI_TEMPLATE (found);
/* We only want partial instantiations, here, not
specializations or full instantiations. */
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_VALUE (found))
|| !uses_template_parms (TREE_VALUE (found)))
continue;
/* Temporarily reduce by one the number of levels in the
ARGLIST and in FOUND so as to avoid comparing the
last set of arguments. */
TREE_VEC_LENGTH (arglist)--;
TREE_VEC_LENGTH (TREE_PURPOSE (found)) --;
/* See if the arguments match. If they do, then TMPL is
the partial instantiation we want. */
success = comp_template_args (TREE_PURPOSE (found), arglist);
/* Restore the argument vectors to their full size. */
TREE_VEC_LENGTH (arglist)++;
TREE_VEC_LENGTH (TREE_PURPOSE (found))++;
if (success)
{
found = tmpl;
break;
}
}
if (!found)
{
/* There was no partial instantiation. This happens
where C<T> is a member template of A<T> and it's used
in something like
template <typename T> struct B { A<T>::C<int> m; };
B<float>;
Create the partial instantiation.
*/
TREE_VEC_LENGTH (arglist)--;
found = tsubst (templ, arglist, complain, NULL_TREE);
TREE_VEC_LENGTH (arglist)++;
}
} }
SET_TYPE_TEMPLATE_INFO (t, tree_cons (found, arglist, NULL_TREE)); SET_TYPE_TEMPLATE_INFO (t, tree_cons (found, arglist, NULL_TREE));
elt.spec = t;
slot = (spec_entry **) htab_find_slot_with_hash (type_specializations,
&elt, hash, INSERT);
*slot = GGC_NEW (spec_entry);
**slot = elt;
/* Note this use of the partial instantiation so we can check it
later in maybe_process_partial_specialization. */
DECL_TEMPLATE_INSTANTIATIONS (templ) DECL_TEMPLATE_INSTANTIATIONS (templ)
= tree_cons (arglist, t, = tree_cons (arglist, t,
DECL_TEMPLATE_INSTANTIATIONS (templ)); DECL_TEMPLATE_INSTANTIATIONS (templ));
...@@ -6632,46 +6833,58 @@ tsubst_friend_function (tree decl, tree args) ...@@ -6632,46 +6833,58 @@ tsubst_friend_function (tree decl, tree args)
; ;
else else
{ {
tree new_template = TI_TEMPLATE (new_friend_template_info);
tree new_args = TI_ARGS (new_friend_template_info);
/* Overwrite whatever template info was there before, if /* Overwrite whatever template info was there before, if
any, with the new template information pertaining to any, with the new template information pertaining to
the declaration. */ the declaration. */
DECL_TEMPLATE_INFO (old_decl) = new_friend_template_info; DECL_TEMPLATE_INFO (old_decl) = new_friend_template_info;
if (TREE_CODE (old_decl) != TEMPLATE_DECL) if (TREE_CODE (old_decl) != TEMPLATE_DECL)
reregister_specialization (new_friend, /* We should have called reregister_specialization in
most_general_template (old_decl), duplicate_decls. */
old_decl); gcc_assert (retrieve_specialization (new_template,
new_args, 0)
== old_decl);
else else
{ {
tree t; tree t;
tree new_friend_args;
/* Indicate that the old function template is a partial
instantiation. */
DECL_TEMPLATE_INFO (DECL_TEMPLATE_RESULT (old_decl)) DECL_TEMPLATE_INFO (DECL_TEMPLATE_RESULT (old_decl))
= new_friend_result_template_info; = new_friend_result_template_info;
new_friend_args = TI_ARGS (new_friend_template_info); gcc_assert (new_template
for (t = DECL_TEMPLATE_SPECIALIZATIONS (old_decl); == most_general_template (new_template));
gcc_assert (new_template != old_decl);
/* Reassign any specializations already in the hash table
to the new more general template, and add the
additional template args. */
for (t = DECL_TEMPLATE_INSTANTIATIONS (old_decl);
t != NULL_TREE; t != NULL_TREE;
t = TREE_CHAIN (t)) t = TREE_CHAIN (t))
{ {
tree spec = TREE_VALUE (t); tree spec = TREE_VALUE (t);
spec_entry elt;
elt.tmpl = old_decl;
elt.args = DECL_TI_ARGS (spec);
elt.spec = NULL_TREE;
htab_remove_elt (decl_specializations, &elt);
DECL_TI_ARGS (spec) DECL_TI_ARGS (spec)
= add_outermost_template_args (new_friend_args, = add_outermost_template_args (new_args,
DECL_TI_ARGS (spec)); DECL_TI_ARGS (spec));
}
/* Now, since specializations are always supposed to register_specialization
hang off of the most general template, we must move (spec, new_template, DECL_TI_ARGS (spec), true, 0);
them. */
t = most_general_template (old_decl);
if (t != old_decl)
{
DECL_TEMPLATE_SPECIALIZATIONS (t)
= chainon (DECL_TEMPLATE_SPECIALIZATIONS (t),
DECL_TEMPLATE_SPECIALIZATIONS (old_decl));
DECL_TEMPLATE_SPECIALIZATIONS (old_decl) = NULL_TREE;
} }
DECL_TEMPLATE_INSTANTIATIONS (old_decl) = NULL_TREE;
} }
} }
...@@ -8090,6 +8303,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -8090,6 +8303,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
location_t saved_loc; location_t saved_loc;
tree r = NULL_TREE; tree r = NULL_TREE;
tree in_decl = t; tree in_decl = t;
hashval_t hash = 0;
/* Set the filename and linenumber to improve error-reporting. */ /* Set the filename and linenumber to improve error-reporting. */
saved_loc = input_location; saved_loc = input_location;
...@@ -8150,8 +8364,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -8150,8 +8364,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
changed. */ changed. */
gcc_assert (full_args != tmpl_args); gcc_assert (full_args != tmpl_args);
spec = retrieve_specialization (t, full_args, hash = hash_tmpl_and_args (t, full_args);
/*class_specializations_p=*/true); spec = retrieve_specialization (t, full_args, hash);
if (spec != NULL_TREE) if (spec != NULL_TREE)
{ {
r = spec; r = spec;
...@@ -8218,7 +8432,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -8218,7 +8432,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
/* Record this non-type partial instantiation. */ /* Record this non-type partial instantiation. */
register_specialization (r, t, register_specialization (r, t,
DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)), DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
false); false, hash);
} }
break; break;
...@@ -8260,8 +8474,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -8260,8 +8474,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
args, complain, in_decl); args, complain, in_decl);
/* Check to see if we already have this specialization. */ /* Check to see if we already have this specialization. */
spec = retrieve_specialization (gen_tmpl, argvec, hash = hash_tmpl_and_args (gen_tmpl, argvec);
/*class_specializations_p=*/false); spec = retrieve_specialization (gen_tmpl, argvec, hash);
if (spec) if (spec)
{ {
...@@ -8396,7 +8610,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -8396,7 +8610,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
DECL_TEMPLATE_INFO (r) DECL_TEMPLATE_INFO (r)
= tree_cons (gen_tmpl, argvec, NULL_TREE); = tree_cons (gen_tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r); SET_DECL_IMPLICIT_INSTANTIATION (r);
register_specialization (r, gen_tmpl, argvec, false); register_specialization (r, gen_tmpl, argvec, false, hash);
/* We're not supposed to instantiate default arguments /* We're not supposed to instantiate default arguments
until they are called, for a template. But, for a until they are called, for a template. But, for a
...@@ -8686,9 +8900,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -8686,9 +8900,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
tmpl = DECL_TI_TEMPLATE (t); tmpl = DECL_TI_TEMPLATE (t);
gen_tmpl = most_general_template (tmpl); gen_tmpl = most_general_template (tmpl);
argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl); argvec = tsubst (DECL_TI_ARGS (t), args, complain, in_decl);
spec = (retrieve_specialization hash = hash_tmpl_and_args (gen_tmpl, argvec);
(gen_tmpl, argvec, spec = retrieve_specialization (gen_tmpl, argvec, hash);
/*class_specializations_p=*/false));
} }
} }
else else
...@@ -8800,7 +9013,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -8800,7 +9013,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
processing here. */ processing here. */
DECL_EXTERNAL (r) = 1; DECL_EXTERNAL (r) = 1;
register_specialization (r, gen_tmpl, argvec, false); register_specialization (r, gen_tmpl, argvec, false, hash);
DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE); DECL_TEMPLATE_INFO (r) = tree_cons (tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r); SET_DECL_IMPLICIT_INSTANTIATION (r);
} }
...@@ -9130,7 +9343,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -9130,7 +9343,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{ {
tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl)); tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl); tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
r = retrieve_specialization (tmpl, gen_args, false); r = retrieve_specialization (tmpl, gen_args, 0);
} }
else if (DECL_FUNCTION_SCOPE_P (decl) else if (DECL_FUNCTION_SCOPE_P (decl)
&& DECL_TEMPLATE_INFO (DECL_CONTEXT (decl)) && DECL_TEMPLATE_INFO (DECL_CONTEXT (decl))
...@@ -12098,8 +12311,9 @@ check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain) ...@@ -12098,8 +12311,9 @@ check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain)
the template arguments in TARG_PTR. */ the template arguments in TARG_PTR. */
tree tree
instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain) instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
{ {
tree targ_ptr = orig_args;
tree fndecl; tree fndecl;
tree gen_tmpl; tree gen_tmpl;
tree spec; tree spec;
...@@ -12131,26 +12345,25 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain) ...@@ -12131,26 +12345,25 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
} }
/* Check to see if we already have this specialization. */ /* Check to see if we already have this specialization. */
spec = retrieve_specialization (tmpl, targ_ptr,
/*class_specializations_p=*/false);
if (spec != NULL_TREE)
return spec;
gen_tmpl = most_general_template (tmpl); gen_tmpl = most_general_template (tmpl);
if (tmpl != gen_tmpl) if (tmpl != gen_tmpl)
{ /* The TMPL is a partial instantiation. To get a full set of
/* The TMPL is a partial instantiation. To get a full set of arguments we must add the arguments used to perform the
arguments we must add the arguments used to perform the partial instantiation. */
partial instantiation. */ targ_ptr = add_outermost_template_args (DECL_TI_ARGS (tmpl),
targ_ptr = add_outermost_template_args (DECL_TI_ARGS (tmpl), targ_ptr);
targ_ptr);
/* Check to see if we already have this specialization. */ /* It would be nice to avoid hashing here and then again in tsubst_decl,
spec = retrieve_specialization (gen_tmpl, targ_ptr, but it doesn't seem to be on the hot path. */
/*class_specializations_p=*/false); spec = retrieve_specialization (gen_tmpl, targ_ptr, 0);
if (spec != NULL_TREE)
return spec; gcc_assert (tmpl == gen_tmpl
} || ((fndecl = retrieve_specialization (tmpl, orig_args, 0))
== spec)
|| fndecl == NULL_TREE);
if (spec != NULL_TREE)
return spec;
if (check_instantiated_args (gen_tmpl, INNERMOST_TEMPLATE_ARGS (targ_ptr), if (check_instantiated_args (gen_tmpl, INNERMOST_TEMPLATE_ARGS (targ_ptr),
complain)) complain))
...@@ -15495,25 +15708,28 @@ instantiate_decl (tree d, int defer_ok, ...@@ -15495,25 +15708,28 @@ instantiate_decl (tree d, int defer_ok,
if (TREE_CODE (d) == FUNCTION_DECL && DECL_CLONED_FUNCTION_P (d)) if (TREE_CODE (d) == FUNCTION_DECL && DECL_CLONED_FUNCTION_P (d))
d = DECL_CLONED_FUNCTION (d); d = DECL_CLONED_FUNCTION (d);
if (DECL_TEMPLATE_INSTANTIATED (d)) if (DECL_TEMPLATE_INSTANTIATED (d)
/* D has already been instantiated. It might seem reasonable to || DECL_TEMPLATE_SPECIALIZATION (d))
check whether or not D is an explicit instantiation, and, if so, /* D has already been instantiated or explicitly specialized, so
stop here. But when an explicit instantiation is deferred there's nothing for us to do here.
until the end of the compilation, DECL_EXPLICIT_INSTANTIATION
is set, even though we still need to do the instantiation. */ It might seem reasonable to check whether or not D is an explicit
instantiation, and, if so, stop here. But when an explicit
instantiation is deferred until the end of the compilation,
DECL_EXPLICIT_INSTANTIATION is set, even though we still need to do
the instantiation. */
return d; return d;
/* If we already have a specialization of this declaration, then
there's no reason to instantiate it. Note that
retrieve_specialization gives us both instantiations and
specializations, so we must explicitly check
DECL_TEMPLATE_SPECIALIZATION. */
gen_tmpl = most_general_template (tmpl); gen_tmpl = most_general_template (tmpl);
gen_args = DECL_TI_ARGS (d); gen_args = DECL_TI_ARGS (d);
spec = retrieve_specialization (gen_tmpl, gen_args,
/*class_specializations_p=*/false); if (tmpl != gen_tmpl)
if (spec != NULL_TREE && DECL_TEMPLATE_SPECIALIZATION (spec)) /* We should already have the extra args. */
return spec; gcc_assert (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (gen_tmpl))
== TMPL_ARGS_DEPTH (gen_args));
/* And what's in the hash table should match D. */
gcc_assert ((spec = retrieve_specialization (gen_tmpl, gen_args, 0)) == d
|| spec == NULL_TREE);
/* This needs to happen before any tsubsting. */ /* This needs to happen before any tsubsting. */
if (! push_tinst_level (d)) if (! push_tinst_level (d))
...@@ -17406,4 +17622,19 @@ append_type_to_template_for_access_check (tree templ, ...@@ -17406,4 +17622,19 @@ append_type_to_template_for_access_check (tree templ,
append_type_to_template_for_access_check_1 (templ, type_decl, scope); append_type_to_template_for_access_check_1 (templ, type_decl, scope);
} }
/* Set up the hash tables for template instantiations. */
void
init_template_processing (void)
{
decl_specializations = htab_create_ggc (37,
hash_specialization,
eq_specializations,
ggc_free);
type_specializations = htab_create_ggc (37,
hash_specialization,
eq_specializations,
ggc_free);
}
#include "gt-cp-pt.h" #include "gt-cp-pt.h"
2009-07-02 Jason Merrill <jason@redhat.com>
* g++.dg/template/spec8.C: Fix.
2009-07-02 Michael Matz <matz@suse.de> 2009-07-02 Michael Matz <matz@suse.de>
PR fortran/32131 PR fortran/32131
......
...@@ -5,7 +5,12 @@ ...@@ -5,7 +5,12 @@
template<class T1> struct A template<class T1> struct A
{ {
template<class T2> struct B {}; template<class T2> struct B {};
template<class T2> struct C {};
}; };
template <> template <> struct A<int>::B<int> {}; template <> template <> struct A<int>::B<int>;
template <> template <class U> struct A<int>::B {}; // { dg-error "specialization" } template <> template <class U> struct A<int>::B {};
A<int>::B<int> ab; // { dg-error "incomplete" }
A<int>::C<char> ac;
template <> template <class U> struct A<int>::C {}; // { dg-error "specialization" }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment