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>
* 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
specializations of this template. (Full specializations are not
recorded on this list.) The TREE_PURPOSE holds the innermost
arguments used in the partial specialization (e.g., for `template
<class T> struct S<T*, int>' this will be `T*'.) The TREE_VALUE
holds the innermost template parameters for the specialization
(e.g., `T' in the example above.) The TREE_TYPE is the _TYPE node
for the partial specialization.
recorded on this list.) The TREE_PURPOSE holds the arguments used
in the partial specialization (e.g., for `template <class T> struct
S<T*, int>' this will be `T*'.) The arguments will also include
any outer template arguments. The TREE_VALUE holds the innermost
template parameters for the specialization (e.g., `T' in the
example above.) The TREE_TYPE is the _TYPE node for the partial
specialization.
This list is not used for static variable templates. */
#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE (NODE)

View File

@ -144,7 +144,6 @@ static tree process_partial_specialization (tree);
static void set_current_access_from_decl (tree);
static void check_default_tmpl_args (tree, tree, int, int);
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 int coerce_template_template_parms (tree, tree, tsubst_flags_t,
tree, tree);
@ -1450,7 +1449,8 @@ determine_specialization (tree template_id,
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 (TREE_VALUE (current_template_parms))))
!= TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
(current_template_parms))))
continue;
/* See whether this function might be a specialization of this
@ -2756,7 +2756,7 @@ process_partial_specialization (tree decl)
return decl;
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)
= tree_cons (inner_args, inner_parms,
= tree_cons (specargs, inner_parms,
DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
return decl;
@ -5493,34 +5493,34 @@ instantiate_class_template (tree type)
template = most_general_template (CLASSTYPE_TI_TEMPLATE (type));
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
instantiate. */
t = most_specialized_class (template, args);
t = most_specialized_class (type, template);
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;
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)
pattern = TREE_TYPE (t);
and supposing that we are instantiating S<int*>, ARGS will
presently be {int*} -- but we need {int}. */
pattern = TREE_TYPE (t);
args = TREE_PURPOSE (t);
}
else
pattern = TREE_TYPE (template);
{
pattern = TREE_TYPE (template);
args = CLASSTYPE_TI_ARGS (type);
}
/* If the template we're instantiating is incomplete, then clearly
there's nothing we can do. */
@ -5541,34 +5541,6 @@ instantiate_class_template (tree type)
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 the input location to the template definition. This is needed
@ -9734,34 +9706,6 @@ try_one_overload (tree tparms,
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
parameters). ARG is a fully instantiated type. If ARG can be
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;
}
/* Takes parameters as for type_unification. Returns 0 if the
type deduction succeeds, 1 otherwise. The parameter STRICT is a
bitwise or of the following flags:
/* Deduce the value of template parameters. TPARMS is the (innermost)
set of template parameters to a template. TARGS is the bindings
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:
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)
&& same_type_p (parm, arg)) ? 0 : 1;
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));
/* Check for mixed types and values. */
@ -10132,7 +10085,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
return 1;
}
TREE_VEC_ELT (targs, idx) = arg;
TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return 0;
case TEMPLATE_PARM_INDEX:
@ -10146,7 +10099,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
&& cp_tree_equal (parm, arg));
idx = TEMPLATE_PARM_IDX (parm);
targ = TREE_VEC_ELT (targs, idx);
targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
if (targ)
return !cp_tree_equal (targ, arg);
@ -10180,7 +10133,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
else
return 1;
TREE_VEC_ELT (targs, idx) = arg;
TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return 0;
case PTRMEM_CST:
@ -10705,33 +10658,44 @@ more_specialized_fn (tree pat1, tree pat2, int len)
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].
-1 if PAT2 is more specialized than PAT1.
0 if neither is more specialized.
PAT1 is a TREE_LIST whose TREE_TYPE is the _TYPE node corresponding
to the first partial specialization. The TREE_VALUE is the
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
partial ordering. */
Return 1 if the first partial specialization is more specialized;
-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
more_specialized_class (tree pat1, tree pat2, tree full_args)
more_specialized_class (tree pat1, tree pat2)
{
tree targs;
tree tmpl1, tmpl2;
int winner = 0;
tmpl1 = TREE_TYPE (pat1);
tmpl2 = TREE_TYPE (pat2);
/* Just like what happens for functions, if we are ordering between
different class template specializations, we may encounter dependent
types in the arguments, and we need our dependency check functions
to behave correctly. */
++processing_template_decl;
targs = get_class_bindings (TREE_VALUE (pat1), TREE_PURPOSE (pat1),
add_outermost_template_args (full_args, TREE_PURPOSE (pat2)));
targs = get_class_bindings (TREE_VALUE (pat1),
CLASSTYPE_TI_ARGS (tmpl1),
CLASSTYPE_TI_ARGS (tmpl2));
if (targs)
--winner;
targs = get_class_bindings (TREE_VALUE (pat2), TREE_PURPOSE (pat2),
add_outermost_template_args (full_args, TREE_PURPOSE (pat1)));
targs = get_class_bindings (TREE_VALUE (pat2),
CLASSTYPE_TI_ARGS (tmpl2),
CLASSTYPE_TI_ARGS (tmpl1));
if (targs)
++winner;
--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> {};
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'
is bound to `double'. */
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);
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))
return NULL_TREE;
for (i = 0; i < ntparms; ++i)
if (! TREE_VEC_ELT (vec, i))
if (! TREE_VEC_ELT (innermost_deduced_args, i))
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 vec;
return deduced_args;
}
/* TEMPLATES is a TREE_LIST. Each TREE_VALUE is a TEMPLATE_DECL.
@ -10957,26 +10952,42 @@ most_general_template (tree decl)
return decl;
}
/* Return the most specialized of the class template specializations
of TMPL which can produce an instantiation matching ARGS, or
error_mark_node if the choice is ambiguous. */
/* Return the most specialized of the class template partial
specializations of TMPL which can produce TYPE, a specialization of
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
most_specialized_class (tree tmpl, tree args)
most_specialized_class (tree type, tree tmpl)
{
tree list = NULL_TREE;
tree t;
tree champ;
int fate;
bool ambiguous_p;
tree args;
tmpl = most_general_template (tmpl);
args = CLASSTYPE_TI_ARGS (type);
for (t = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); t; t = TREE_CHAIN (t))
{
tree spec_args
= get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t), args);
tree partial_spec_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)
{
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);
}
}
@ -10984,12 +10995,13 @@ most_specialized_class (tree tmpl, tree args)
if (! list)
return NULL_TREE;
ambiguous_p = false;
t = list;
champ = 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)
;
else
@ -10998,17 +11010,36 @@ most_specialized_class (tree tmpl, tree args)
{
t = TREE_CHAIN (t);
if (! t)
return error_mark_node;
{
ambiguous_p = true;
break;
}
}
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);
if (fate != 1)
return error_mark_node;
const char *str = "candidates are:";
error ("ambiguous class template instantiation for %q#T", type);
for (t = list; t; t = TREE_CHAIN (t))
{
error ("%s %+#T", str, TREE_TYPE (t));
str = " ";
}
return error_mark_node;
}
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>
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;
};