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