On 05/18/2011 01:45 PM, Jason Merrill wrote:
>> 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.

Thank you for the review.  I'll go back and try things the way you suggest;
before I go off and do that, I've taken your comments to mean that:

- fn_type_unification/type_unification_real and associated callers should take
  a boolean `explain' parameter, which is normally false;

- failed calls to fn_type_unification should save the arguments for the call
  for future explanation;

- printing diagnostic messages should call fn_type_unification with the saved
  arguments and a true `explain' parameter.

This is similar to passing `struct unification_info' and really only involves
shuffling code from call.c into the unify_* functions in pt.c and some minor
changes to the rejection_reason code in call.c.  The only wrinkle I see is
that in cases like these:

>>           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.
>
>>             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 (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.

and other bits of pt.c, I'm interpreting your suggestions to mean that
tf_warning_or_error should be passed if `explain' is true.  That doesn't seem
like the best interface for diagnostics, as we'll get:

foo.cc:105:40 error: no matching function for call to bar (...)
foo.cc:105:40 note: candidates are:
bar.hh:7000:30 note: bar (...)
bar.hh:7000:30 note: [some reason]
bar.hh:4095:63 note: bar (...)
bar.hh:....... error: [some message from tf_warning_or_error code]

I'm not sure that the last location there will necessary be the same as the
one that's printed for the declaration.  I think I'll punt on that issue for
the time being until we see how the diagnostics work out.  There's also the
matter of the error vs. note diagnostic.  I think it'd be nicer to keep the
conformity of a note for all the explanations; the only way I see to do that
is something like:

- Add a tf_note flag; pass it at all appropriate call sites when explaining
  things;

- Add a tf_issue_diagnostic flag that's the union of tf_{warning,error,note};

- Change code that looks like:

  if (complain & tf_warning_or_error)
    error (<STUFF>);

  to something like:

  if (complain & tf_issue_diagnostic)
    emit_diagnostic (complain & tf_note ? DK_NOTE : DK_ERROR, <STUFF>);

  passing input_location if we're not already passing a location.

That involves a lot of code churn.  (Not a lot if you just modified the
functions above, but with this scheme, you'd have to call instantiate_template
again from the diagnostic code, and I assume you'd want to call that with
tf_note as well, which means hitting a lot more code.)  I don't see a better
way to keep the diagnostics uniform, but I might be making things too
complicated; did you have a different idea of how to implement what you were
suggesting?

-Nathan


Reply via email to