re PR c++/25342 (internal compiler error: in lookup_member, at cp/search.c:1209)

PR c++/25342
	* cp-tree.h (DECL_TEMPLATE_SPECIALIZATIONS): Revise
	documentation.
	* pt.c (determine_specialization): Use INNERMOST_TEMPLATE_PARMS,
	not TREE_VALUE.
	(instantiate_class_template): Simplify.
	(verify_class_unification): Remove.
	(unify): Document parameters.  Use INNERMOST_TEMPLATE_ARGS to
	permit multiple levels of template arguments.
	(more_specialized_class): Simplify.
	(get_class_bindings): Pass full arguments to unify.  Fold
	verify_class_unification into this function.  Return full
	arguments.
	(most_specialized_class): Adjust for changes to
	get_class_bindings.  Issue errors here for ambiguity.  Return the
	fully deduced arguments for the most specialized class, in
	addition to the partial specialization.
	PR c++/25342
	* g++.gd/template/partial4.C: New test.

From-SVN: r110466
This commit is contained in:
Mark Mitchell 2006-02-01 02:51:13 +00:00 committed by Mark Mitchell
parent f51a281b45
commit 916b63c371
5 changed files with 195 additions and 122 deletions

View file

@ -1,3 +1,23 @@
2006-01-31 Mark Mitchell <mark@codesourcery.com>
PR c++/25342
* cp-tree.h (DECL_TEMPLATE_SPECIALIZATIONS): Revise
documentation.
* pt.c (determine_specialization): Use INNERMOST_TEMPLATE_PARMS,
not TREE_VALUE.
(instantiate_class_template): Simplify.
(verify_class_unification): Remove.
(unify): Document parameters. Use INNERMOST_TEMPLATE_ARGS to
permit multiple levels of template arguments.
(more_specialized_class): Simplify.
(get_class_bindings): Pass full arguments to unify. Fold
verify_class_unification into this function. Return full
arguments.
(most_specialized_class): Adjust for changes to
get_class_bindings. Issue errors here for ambiguity. Return the
fully deduced arguments for the most specialized class, in
addition to the partial specialization.
2006-01-31 Ben Elliston <bje@au.ibm.com> 2006-01-31 Ben Elliston <bje@au.ibm.com>
* mangle.c: Comment fix. * mangle.c: Comment fix.

View file

@ -2729,12 +2729,13 @@ extern void decl_shadowed_for_var_insert (tree, tree);
For a class template, this list contains the partial 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 innermost recorded on this list.) The TREE_PURPOSE holds the arguments used
arguments used in the partial specialization (e.g., for `template in the partial specialization (e.g., for `template <class T> struct
<class T> struct S<T*, int>' this will be `T*'.) The TREE_VALUE S<T*, int>' this will be `T*'.) The arguments will also include
holds the innermost template parameters for the specialization any outer template arguments. The TREE_VALUE holds the innermost
(e.g., `T' in the example above.) The TREE_TYPE is the _TYPE node template parameters for the specialization (e.g., `T' in the
for the partial specialization. example above.) The TREE_TYPE is the _TYPE node for the partial
specialization.
This list is not used for static variable templates. */ This list is not used for static variable templates. */
#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE (NODE) #define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE (NODE)

View file

@ -144,7 +144,6 @@ static tree process_partial_specialization (tree);
static void set_current_access_from_decl (tree); static void set_current_access_from_decl (tree);
static void check_default_tmpl_args (tree, tree, int, int); static void check_default_tmpl_args (tree, tree, int, int);
static tree get_template_base (tree, tree, tree, tree); static tree get_template_base (tree, tree, tree, tree);
static int verify_class_unification (tree, tree, tree);
static tree try_class_unification (tree, tree, tree, tree); static tree try_class_unification (tree, tree, tree, tree);
static int coerce_template_template_parms (tree, tree, tsubst_flags_t, static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
tree, tree); tree, tree);
@ -1450,7 +1449,8 @@ determine_specialization (tree template_id,
if (current_binding_level->kind == sk_template_parms if (current_binding_level->kind == sk_template_parms
&& !current_binding_level->explicit_spec_p && !current_binding_level->explicit_spec_p
&& (TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (fn)) && (TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (fn))
!= TREE_VEC_LENGTH (TREE_VALUE (current_template_parms)))) != TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
(current_template_parms))))
continue; continue;
/* See whether this function might be a specialization of this /* See whether this function might be a specialization of this
@ -2756,7 +2756,7 @@ process_partial_specialization (tree decl)
return decl; return decl;
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)
= tree_cons (inner_args, inner_parms, = tree_cons (specargs, inner_parms,
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)); DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type; TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
return decl; return decl;
@ -5493,34 +5493,34 @@ instantiate_class_template (tree type)
template = most_general_template (CLASSTYPE_TI_TEMPLATE (type)); template = most_general_template (CLASSTYPE_TI_TEMPLATE (type));
gcc_assert (TREE_CODE (template) == TEMPLATE_DECL); gcc_assert (TREE_CODE (template) == TEMPLATE_DECL);
/* Figure out which arguments are being used to do the
instantiation. */
args = CLASSTYPE_TI_ARGS (type);
/* Determine what specialization of the original template to /* Determine what specialization of the original template to
instantiate. */ instantiate. */
t = most_specialized_class (template, args); t = most_specialized_class (type, template);
if (t == error_mark_node) if (t == error_mark_node)
{ {
const char *str = "candidates are:";
error ("ambiguous class template instantiation for %q#T", type);
for (t = DECL_TEMPLATE_SPECIALIZATIONS (template); t;
t = TREE_CHAIN (t))
{
if (get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t), args))
{
error ("%s %+#T", str, TREE_TYPE (t));
str = " ";
}
}
TYPE_BEING_DEFINED (type) = 1; TYPE_BEING_DEFINED (type) = 1;
return error_mark_node; return error_mark_node;
} }
else if (t)
{
/* This TYPE is actually an instantiation of a partial
specialization. We replace the innermost set of ARGS with
the arguments appropriate for substitution. For example,
given:
template <class T> struct S {};
template <class T> struct S<T*> {};
if (t) and supposing that we are instantiating S<int*>, ARGS will
pattern = TREE_TYPE (t); presently be {int*} -- but we need {int}. */
pattern = TREE_TYPE (t);
args = TREE_PURPOSE (t);
}
else else
pattern = TREE_TYPE (template); {
pattern = TREE_TYPE (template);
args = CLASSTYPE_TI_ARGS (type);
}
/* If the template we're instantiating is incomplete, then clearly /* If the template we're instantiating is incomplete, then clearly
there's nothing we can do. */ there's nothing we can do. */
@ -5541,34 +5541,6 @@ instantiate_class_template (tree type)
push_to_top_level (); push_to_top_level ();
if (t)
{
/* This TYPE is actually an instantiation of a partial
specialization. We replace the innermost set of ARGS with
the arguments appropriate for substitution. For example,
given:
template <class T> struct S {};
template <class T> struct S<T*> {};
and supposing that we are instantiating S<int*>, ARGS will
present be {int*} but we need {int}. */
tree inner_args
= get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t),
args);
/* If there were multiple levels in ARGS, replacing the
innermost level would alter CLASSTYPE_TI_ARGS, which we don't
want, so we make a copy first. */
if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
{
args = copy_node (args);
SET_TMPL_ARGS_LEVEL (args, TMPL_ARGS_DEPTH (args), inner_args);
}
else
args = inner_args;
}
SET_CLASSTYPE_INTERFACE_UNKNOWN (type); SET_CLASSTYPE_INTERFACE_UNKNOWN (type);
/* Set the input location to the template definition. This is needed /* Set the input location to the template definition. This is needed
@ -9734,34 +9706,6 @@ try_one_overload (tree tparms,
return 1; return 1;
} }
/* Verify that nondeduce template argument agrees with the type
obtained from argument deduction. Return nonzero if the
verification fails.
For example:
struct A { typedef int X; };
template <class T, class U> struct C {};
template <class T> struct C<T, typename T::X> {};
Then with the instantiation `C<A, int>', we can deduce that
`T' is `A' but unify () does not check whether `typename T::X'
is `int'. This function ensure that they agree.
TARGS, PARMS are the same as the arguments of unify.
ARGS contains template arguments from all levels. */
static int
verify_class_unification (tree targs, tree parms, tree args)
{
parms = tsubst (parms, add_outermost_template_args (args, targs),
tf_none, NULL_TREE);
if (parms == error_mark_node)
return 1;
return !comp_template_args (parms, INNERMOST_TEMPLATE_ARGS (args));
}
/* PARM is a template class (perhaps with unbound template /* PARM is a template class (perhaps with unbound template
parameters). ARG is a fully instantiated type. If ARG can be parameters). ARG is a fully instantiated type. If ARG can be
bound to PARM, return ARG, otherwise return NULL_TREE. TPARMS and bound to PARM, return ARG, otherwise return NULL_TREE. TPARMS and
@ -9924,9 +9868,18 @@ check_cv_quals_for_unify (int strict, tree arg, tree parm)
return 1; return 1;
} }
/* Takes parameters as for type_unification. Returns 0 if the /* Deduce the value of template parameters. TPARMS is the (innermost)
type deduction succeeds, 1 otherwise. The parameter STRICT is a set of template parameters to a template. TARGS is the bindings
bitwise or of the following flags: for those template parameters, as determined thus far; TARGS may
include template arguments for outer levels of template parameters
as well. PARM is a parameter to a template function, or a
subcomponent of that parameter; ARG is the corresponding argument.
This function attempts to match PARM with ARG in a manner
consistent with the existing assignments in TARGS. If more values
are deduced, then TARGS is updated.
Returns 0 if the type deduction succeeds, 1 otherwise. The
parameter STRICT is a bitwise or of the following flags:
UNIFY_ALLOW_NONE: UNIFY_ALLOW_NONE:
Require an exact match between PARM and ARG. Require an exact match between PARM and ARG.
@ -10031,7 +9984,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
return (TREE_CODE (arg) == TREE_CODE (parm) return (TREE_CODE (arg) == TREE_CODE (parm)
&& same_type_p (parm, arg)) ? 0 : 1; && same_type_p (parm, arg)) ? 0 : 1;
idx = TEMPLATE_TYPE_IDX (parm); idx = TEMPLATE_TYPE_IDX (parm);
targ = TREE_VEC_ELT (targs, idx); targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx)); tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx));
/* Check for mixed types and values. */ /* Check for mixed types and values. */
@ -10132,7 +10085,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
return 1; return 1;
} }
TREE_VEC_ELT (targs, idx) = arg; TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return 0; return 0;
case TEMPLATE_PARM_INDEX: case TEMPLATE_PARM_INDEX:
@ -10146,7 +10099,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
&& cp_tree_equal (parm, arg)); && cp_tree_equal (parm, arg));
idx = TEMPLATE_PARM_IDX (parm); idx = TEMPLATE_PARM_IDX (parm);
targ = TREE_VEC_ELT (targs, idx); targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
if (targ) if (targ)
return !cp_tree_equal (targ, arg); return !cp_tree_equal (targ, arg);
@ -10180,7 +10133,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
else else
return 1; return 1;
TREE_VEC_ELT (targs, idx) = arg; TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return 0; return 0;
case PTRMEM_CST: case PTRMEM_CST:
@ -10705,33 +10658,44 @@ more_specialized_fn (tree pat1, tree pat2, int len)
return (better1 > 0) - (better2 > 0); return (better1 > 0) - (better2 > 0);
} }
/* Given two class template specialization list nodes PAT1 and PAT2, return: /* Determine which of two partial specializations is more specialized.
1 if PAT1 is more specialized than PAT2 as described in [temp.class.order]. PAT1 is a TREE_LIST whose TREE_TYPE is the _TYPE node corresponding
-1 if PAT2 is more specialized than PAT1. to the first partial specialization. The TREE_VALUE is the
0 if neither is more specialized. innermost set of template parameters for the partial
specialization. PAT2 is similar, but for the second template.
FULL_ARGS is the full set of template arguments that triggers this Return 1 if the first partial specialization is more specialized;
partial ordering. */ -1 if the second is more specialized; 0 if neither is more
specialized.
See [temp.class.order] for information about determining which of
two templates is more specialized. */
static int static int
more_specialized_class (tree pat1, tree pat2, tree full_args) more_specialized_class (tree pat1, tree pat2)
{ {
tree targs; tree targs;
tree tmpl1, tmpl2;
int winner = 0; int winner = 0;
tmpl1 = TREE_TYPE (pat1);
tmpl2 = TREE_TYPE (pat2);
/* Just like what happens for functions, if we are ordering between /* Just like what happens for functions, if we are ordering between
different class template specializations, we may encounter dependent different class template specializations, we may encounter dependent
types in the arguments, and we need our dependency check functions types in the arguments, and we need our dependency check functions
to behave correctly. */ to behave correctly. */
++processing_template_decl; ++processing_template_decl;
targs = get_class_bindings (TREE_VALUE (pat1), TREE_PURPOSE (pat1), targs = get_class_bindings (TREE_VALUE (pat1),
add_outermost_template_args (full_args, TREE_PURPOSE (pat2))); CLASSTYPE_TI_ARGS (tmpl1),
CLASSTYPE_TI_ARGS (tmpl2));
if (targs) if (targs)
--winner; --winner;
targs = get_class_bindings (TREE_VALUE (pat2), TREE_PURPOSE (pat2), targs = get_class_bindings (TREE_VALUE (pat2),
add_outermost_template_args (full_args, TREE_PURPOSE (pat1))); CLASSTYPE_TI_ARGS (tmpl2),
CLASSTYPE_TI_ARGS (tmpl1));
if (targs) if (targs)
++winner; ++winner;
--processing_template_decl; --processing_template_decl;
@ -10806,28 +10770,59 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
template <class T> struct S<T*, int> {}; template <class T> struct S<T*, int> {};
Then, suppose we want to get `S<double*, int>'. The TPARMS will be Then, suppose we want to get `S<double*, int>'. The TPARMS will be
{T}, the PARMS will be {T*, int} and the ARGS will be {double*, {T}, the SPEC_ARGS will be {T*, int} and the ARGS will be {double*,
int}. The resulting vector will be {double}, indicating that `T' int}. The resulting vector will be {double}, indicating that `T'
is bound to `double'. */ is bound to `double'. */
static tree static tree
get_class_bindings (tree tparms, tree parms, tree args) get_class_bindings (tree tparms, tree spec_args, tree args)
{ {
int i, ntparms = TREE_VEC_LENGTH (tparms); int i, ntparms = TREE_VEC_LENGTH (tparms);
tree vec = make_tree_vec (ntparms); tree deduced_args;
tree innermost_deduced_args;
if (unify (tparms, vec, parms, INNERMOST_TEMPLATE_ARGS (args), innermost_deduced_args = make_tree_vec (ntparms);
if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
{
deduced_args = copy_node (args);
SET_TMPL_ARGS_LEVEL (deduced_args,
TMPL_ARGS_DEPTH (deduced_args),
innermost_deduced_args);
}
else
deduced_args = innermost_deduced_args;
if (unify (tparms, deduced_args,
INNERMOST_TEMPLATE_ARGS (spec_args),
INNERMOST_TEMPLATE_ARGS (args),
UNIFY_ALLOW_NONE)) UNIFY_ALLOW_NONE))
return NULL_TREE; return NULL_TREE;
for (i = 0; i < ntparms; ++i) for (i = 0; i < ntparms; ++i)
if (! TREE_VEC_ELT (vec, i)) if (! TREE_VEC_ELT (innermost_deduced_args, i))
return NULL_TREE; return NULL_TREE;
if (verify_class_unification (vec, parms, args)) /* Verify that nondeduced template arguments agree with the type
obtained from argument deduction.
For example:
struct A { typedef int X; };
template <class T, class U> struct C {};
template <class T> struct C<T, typename T::X> {};
Then with the instantiation `C<A, int>', we can deduce that
`T' is `A' but unify () does not check whether `typename T::X'
is `int'. */
spec_args = tsubst (spec_args, deduced_args, tf_none, NULL_TREE);
if (spec_args == error_mark_node
/* We only need to check the innermost arguments; the other
arguments will always agree. */
|| !comp_template_args (INNERMOST_TEMPLATE_ARGS (spec_args),
INNERMOST_TEMPLATE_ARGS (args)))
return NULL_TREE; return NULL_TREE;
return vec; return deduced_args;
} }
/* TEMPLATES is a TREE_LIST. Each TREE_VALUE is a TEMPLATE_DECL. /* TEMPLATES is a TREE_LIST. Each TREE_VALUE is a TEMPLATE_DECL.
@ -10957,26 +10952,42 @@ most_general_template (tree decl)
return decl; return decl;
} }
/* Return the most specialized of the class template specializations /* Return the most specialized of the class template partial
of TMPL which can produce an instantiation matching ARGS, or specializations of TMPL which can produce TYPE, a specialization of
error_mark_node if the choice is ambiguous. */ TMPL. The value returned is actually a TREE_LIST; the TREE_TYPE is
a _TYPE node corresponding to the partial specialization, while the
TREE_PURPOSE is the set of template arguments that must be
substituted into the TREE_TYPE in order to generate TYPE.
If the choice of partial specialization is ambiguous, a diagnostic
is issued, and the error_mark_node is returned. If there are no
partial specializations of TMPL matching TYPE, then NULL_TREE is
returned. */
static tree static tree
most_specialized_class (tree tmpl, tree args) most_specialized_class (tree type, tree tmpl)
{ {
tree list = NULL_TREE; tree list = NULL_TREE;
tree t; tree t;
tree champ; tree champ;
int fate; int fate;
bool ambiguous_p;
tree args;
tmpl = most_general_template (tmpl); tmpl = most_general_template (tmpl);
args = CLASSTYPE_TI_ARGS (type);
for (t = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); t; t = TREE_CHAIN (t)) for (t = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); t; t = TREE_CHAIN (t))
{ {
tree spec_args tree partial_spec_args;
= get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t), args); tree spec_args;
partial_spec_args = CLASSTYPE_TI_ARGS (TREE_TYPE (t));
spec_args = get_class_bindings (TREE_VALUE (t),
partial_spec_args,
args);
if (spec_args) if (spec_args)
{ {
list = tree_cons (TREE_PURPOSE (t), TREE_VALUE (t), list); list = tree_cons (spec_args, TREE_VALUE (t), list);
TREE_TYPE (list) = TREE_TYPE (t); TREE_TYPE (list) = TREE_TYPE (t);
} }
} }
@ -10984,12 +10995,13 @@ most_specialized_class (tree tmpl, tree args)
if (! list) if (! list)
return NULL_TREE; return NULL_TREE;
ambiguous_p = false;
t = list; t = list;
champ = t; champ = t;
t = TREE_CHAIN (t); t = TREE_CHAIN (t);
for (; t; t = TREE_CHAIN (t)) for (; t; t = TREE_CHAIN (t))
{ {
fate = more_specialized_class (champ, t, args); fate = more_specialized_class (champ, t);
if (fate == 1) if (fate == 1)
; ;
else else
@ -10998,17 +11010,36 @@ most_specialized_class (tree tmpl, tree args)
{ {
t = TREE_CHAIN (t); t = TREE_CHAIN (t);
if (! t) if (! t)
return error_mark_node; {
ambiguous_p = true;
break;
}
} }
champ = t; champ = t;
} }
} }
for (t = list; t && t != champ; t = TREE_CHAIN (t)) if (!ambiguous_p)
for (t = list; t && t != champ; t = TREE_CHAIN (t))
{
fate = more_specialized_class (champ, t);
if (fate != 1)
{
ambiguous_p = true;
break;
}
}
if (ambiguous_p)
{ {
fate = more_specialized_class (champ, t, args); const char *str = "candidates are:";
if (fate != 1) error ("ambiguous class template instantiation for %q#T", type);
return error_mark_node; for (t = list; t; t = TREE_CHAIN (t))
{
error ("%s %+#T", str, TREE_TYPE (t));
str = " ";
}
return error_mark_node;
} }
return champ; return champ;

View file

@ -1,3 +1,8 @@
2006-01-31 Mark Mitchell <mark@codesourcery.com>
PR c++/25342
* g++.gd/template/partial4.C: New test.
2006-01-31 Andrew Pinski <pinskia@physics.uc.edu> 2006-01-31 Andrew Pinski <pinskia@physics.uc.edu>
PR middle-end/26001 PR middle-end/26001

View file

@ -0,0 +1,16 @@
// PR c++/25342
template < typename eval >
struct tpl_seq_search {
typedef typename eval::enum_type Enum;
template < Enum first, Enum last >
struct range {
};
template < Enum val >
struct range<val,val> {
};
};
struct xxx {
typedef int enum_type;
tpl_seq_search<xxx>::range<0, 1> a;
};