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

Reply via email to