Thanks for the background; I will keep the principle in mind. IMHO, in
a case like this where we're logically printing one diagnostic (one
error and then some number of explanatory notes) keeping all the logic
for the diagnostic centralized makes more sense.
I understand, but that means we have to create a whole data structure to
try and preserve information about the failure, and either having to
duplicate every possible error or give less informative messages. I
feel even more strongly about this after looking more closely at your patch.
+ case ur_invalid:
+ inform (loc,
+ " template argument deduction attempted with invalid input");
+ break;
In ur_invalid cases, we should have had an earlier error message
already, so giving an extra message here seems kind of redundant.
+ " types %qT and %qT differ in their qualifiers",
Let's say "...have incompatible cv-qualifiers", since some differences
are OK.
+ inform (loc, " variable-sized array type %qT is not permitted",
"...is not a valid template argument"
+ inform (loc, " %qT is not derived from %qT",
This could be misleading, since we can also fail when the deduction is
ambiguous.
+ inform (loc, " %qE is not a valid pointer-to-member of type %qT",
This needs to say "pointer-to-member constant", not just
"pointer-to-member".
+ case ur_parameter_deduction_failure:
+ inform (loc, " couldn't deduce template argument %qD", ui->u.parm);
+ break;
It seems like you're using this both for cases where unification
succeeded but just didn't produce template arguments for all parameters,
and for cases where unification failed for some reason; this message
should only apply to the first case.
if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)))
{
tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
tree arg = TREE_PURPOSE (TREE_VEC_ELT (tparms, i));
arg = tsubst_template_arg (arg, targs, tf_none, NULL_TREE);
arg = convert_template_argument (parm, arg, targs, tf_none,
i, NULL_TREE, ui);
if (arg == error_mark_node)
return unify_parameter_deduction_failure (ui, parm);
In this case, the problem is that we tried to use the default template
argument but it didn't work for some reason; we should say that, not
just say we didn't deduce something, or the users will say "but there's
a default argument!".
In this case, we should do the substitution again with
tf_warning_or_error so the user can see what the problem actually is,
not just say that there was some unspecified problem.
- return 2;
+ return unify_parameter_deduction_failure (ui, tparm);
This seems like the only place we actually want to use
unify_parameter_deduction_failure.
/* Check for mixed types and values. */
if ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
&& TREE_CODE (tparm) != TYPE_DECL)
|| (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
&& TREE_CODE (tparm) != TEMPLATE_DECL))
return unify_parameter_deduction_failure (ui, parm);
This is a type/template mismatch issue that deserves a more helpful
diagnostic.
/* ARG must be constructed from a template class or a template
template parameter. */
if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
&& !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
return unify_parameter_deduction_failure (ui, parm);
This is saying that we can't deduce a template from a non-template type.
/* If the argument deduction results is a METHOD_TYPE,
then there is a problem.
METHOD_TYPE doesn't map to any real C++ type the result of
the deduction can not be of that type. */
if (TREE_CODE (arg) == METHOD_TYPE)
return unify_parameter_deduction_failure (ui, parm);
Like with the VLA case, the problem here is deducing something that
isn't a valid template type argument.
/* We haven't deduced the type of this parameter yet. Try again
later. */
return unify_success (ui);
else
return unify_parameter_deduction_failure (ui, parm);
Here the problem is a type mismatch between parm and arg for a non-type
template argument.
/* Perhaps PARM is something like S<U> and ARG is S<int>.
Then, we should unify `int' and `U'. */
t = arg;
else
/* There's no chance of unification succeeding. */
return unify_parameter_deduction_failure (ui, parm);
This should be type_mismatch.
case FIELD_DECL:
case TEMPLATE_DECL:
/* Matched cases are handled by the ARG == PARM test above. */
return unify_parameter_deduction_failure (ui, parm);
Another case where we should talk about the arg/parm mismatch.
+ case rr_invalid_copy:
+ inform (loc,
+ " cannot instantiate member function templates to "
+ "copy class objects to their class type");
The standardese is misleading here (and is fixed in C++11); you
certainly can instantiate a constructor template to copy an object of
the same type. The real problem is having a constructor taking a single
parameter with the type of the class.
if (TEMPLATE_TYPE_LEVEL (parm)
!= template_decl_level (tparm))
/* The PARM is not one we're trying to unify. Just check
to see if it matches ARG. */
/* FIXME: What to return here? */
return (TREE_CODE (arg) == TREE_CODE (parm)
&& same_type_p (parm, arg)) ? 0 : 1;
unify_type_mismatch seems appropriate here. And unify_success, of course.
if (TEMPLATE_PARM_LEVEL (parm)
!= template_decl_level (tparm))
/* The PARM is not one we're trying to unify. Just check
to see if it matches ARG. */
return !(TREE_CODE (arg) == TREE_CODE (parm)
&& cp_tree_equal (parm, arg));
No diagnostic code here in case of mismatch?
idx = TEMPLATE_PARM_IDX (parm);
targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
if (targ)
return !cp_tree_equal (targ, arg);
Seems like you're missing unify_inconsistency here.
+ case ur_parameter_pack_mismatch:
+ inform (loc, " template parmeter %qD is not a parameter pack",
+ ui->u.mismatch.parm);
+ break;
This message should indicate that this is a compiler defect
if (coerce_template_parms (parm_parms,
full_argvec,
TYPE_TI_TEMPLATE (parm),
tf_none,
/*require_all_args=*/true,
/*use_default_args=*/false, ui)
== error_mark_node)
return 1;
Rather than pass ui down into coerce_template_parms we should just note
when it fails and run it again at diagnostic time.
converted_args
= (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
/*require_all_args=*/false,
/*use_default_args=*/false, ui));
if (converted_args == error_mark_node)
return 1;
Here too.
if (TREE_CODE (arg_max) != MINUS_EXPR)
return 1;
No diagnostic code here?
case TREE_VEC:
{
int i;
if (TREE_CODE (arg) != TREE_VEC)
return 1;
if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg))
return 1;
Or here?
/* An unresolved overload is a nondeduced context. */
if (type_unknown_p (parm))
return 0;
And this should be unify_success.
if (fntype == error_mark_node)
return unify_substitution_failure (ui);
And this should remember the arguments so we can do the tsubst again at
diagnostic time.
Jason