Re: [PATCH,c++] describe reasons for function template overload resolution failure

2011-05-27 Thread Jason Merrill

On 05/26/2011 03:04 PM, Nathan Froyd wrote:

Thanks, this is looking pretty close.  A few more issues, mostly to do 
with wording of the diagnostics:



@@ -14084,7 +14350,7 @@ fn_type_unification (tree fn,
sarg = tree_cons (NULL_TREE, TREE_TYPE (substed), sarg);
  for (i = 0; i  nargs  sarg; ++i, sarg = TREE_CHAIN (sarg))
if (!same_type_p (args[i], TREE_VALUE (sarg)))
- return 1;
+ return unify_unknown (explain_p);


Here the problem is that substituting in the deduced template arguments 
didn't give us the result we were looking for; the diagnostic should 
print the substitution result and the desired result.



  if (resolve_overloaded_unification
- (tparms, targs, parm, arg, strict, sub_strict))
+ (tparms, targs, parm, arg, strict, sub_strict, explain_p))
continue;

- return 1;
+ return unify_unknown (explain_p);


Here the problem is that deduction is unable to resolve the address of 
an overloaded function.



+  inform (input_location,
+   template parameter %qD is not a parameter pack,
+ parm);
+  inform (input_location,   please report this as a bug);


Actually, I was wrong; this isn't a bug.  14.8.2.4/8 says, If A was 
transformed from a function parameter pack and P is not a parameter 
pack, type deduction fails.


But let's print the argument as well in this case.


+unify_ptrmem_cst_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+inform (input_location,
+ mismatched pointer-to-memory constants %qE and %qE,
+   parm, arg);


Here the problem is that arg is not a pointer-to-member constant at all 
(note also member, not memory).



   if (TREE_CODE (arg) != INTEGER_CST)
-   return 1;
+   return unify_constant_mismatch (explain_p, parm, arg);


This could end up complaining that arg isn't constant when the problem 
is that it's the wrong kind of constant.


You might combine unify_ptrmem_cst_mismatch, unify_constant_mismatch, 
and unify_constant_unequal to just say that arg is not a constant equal 
to parm.  Or just use unify_template_argument_mismatch.



+unify_expression_unequal (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+inform (input_location,   %qE is not equal to %qE, parm, arg);


This should say equivalent rather than equal.


+ portions of parameter pack %qT could not be deduced,


The problem here is that portions of the pack were deduced to different 
values, like unify_inconsistency but with packs.  Let's print out the 
conflicting values.



+ method type %qT is not a valid template argument, arg);


member function type


+unify_too_many_parameters (bool explain_p, int have, int wanted)
+unify_too_few_parameters (bool explain_p, int have, int wanted)


s/parameters/arguments/


  if (strict != DEDUCE_EXACT
   can_convert_arg (parm, type, TYPE_P (arg) ? NULL_TREE : arg,
  flags))
continue;

  return unify_arg_conversion (explain_p, parm, type, arg);


In the DEDUCE_EXACT case, let's use unify_type_mismatch.


   !template_template_parm_bindings_ok_p
   (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs))
return unify_inconsistent_template_template_parameters (explain_p);


Here the problem is that the template parameters of a template template 
argument are inconsistent with other deduced template arguments, as 
illustrated in the example just above this snippet.  Ideally here we'd 
print the parameter types of the template template argument and the 
parameter types of the template template parameter after substituting in 
the other template arguments.  I'm not going to insist on that now, but 
let's be a bit more verbose than inconsistent template template 
parameters.



TREE_CODE (tparm) != TYPE_DECL)
  || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
   TREE_CODE (tparm) != TEMPLATE_DECL))
-   return 1;
+   return unify_template_parameter_mismatch (explain_p,
+ parm, tparm);


Looking more closely, I have no idea how this could happen.  It seems to 
hypothesize a template type parameter that isn't a type parameter, or a 
template template parameter that isn't a template template parameter. 
Let's try asserting that this can't happen.



   converted_args
= (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
  /*require_all_args=*/false,
  /*use_default_args=*/false));
   if (converted_args == error_mark_node)
-   return 1;
+   {
+ /* Run it for diagnostics.  */
+ if (explain_p)
+   coerce_template_parms (tparms, explicit_targs, NULL_TREE,
+  tf_warning_or_error,
+  

Re: [PATCH,c++] describe reasons for function template overload resolution failure

2011-05-27 Thread Jason Merrill

On 05/27/2011 04:22 PM, Nathan Froyd wrote:

+ /* The PARM is not one we're trying to unify.  Just check
+to see if it matches ARG.  */
+ int result = !(TREE_CODE (arg) == TREE_CODE (parm)
+ cp_tree_equal (parm, arg));
+ if (result)
+   unify_template_parameter_mismatch (explain_p, parm, tparm);


This should be unify_template_argument_mismatch (explain_p, parm, arg);

So we can drop unify_template_parameter_mismatch.

OK with that change.

Jason


Re: [PATCH,c++] describe reasons for function template overload resolution failure

2011-05-26 Thread Jason Merrill

On 05/25/2011 02:15 PM, Nathan Froyd wrote:

The patch below implements just such an idea.  The only twist is that
the `explain' parameter is actually a `location_t *' so that when we
provide explanations that aren't produced via tf_warning_or_error
blocks, the explanations are attached to the template itself rather than
the call, as would be done with input_location.  Requests for
non-explanation are accomplished with a NULL argument.

I'm not totally attached to this; it's almost too cute, and since
tf_warning_or_error messsages tend to be attached to the call anyway,
it's arguably inconsistent.


Yes, I think let's drop this bit and just use the call location. 
Ideally, for unification failures we'd give the source location of the 
problematic argument (which we don't always have because it might be a 
plain DECL) and for substitution failures we'd give the source location 
of the expression that substitution failed on (for which we could adjust 
input_location in tsubst_*).



I didn't see what you intended by reconstructing the arguments, so I
implemented the more straightforward saving.


I was thinking that we could try to add the candidate again, but this is 
fine.


Jason


Re: [PATCH,c++] describe reasons for function template overload resolution failure

2011-05-18 Thread Jason Merrill

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 SU and ARG is Sint.
   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 

Re: [PATCH,c++] describe reasons for function template overload resolution failure

2011-05-18 Thread Nathan Froyd
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 

Re: [PATCH,c++] describe reasons for function template overload resolution failure

2011-05-18 Thread Jason Merrill

On 05/18/2011 03:00 PM, Nathan Froyd wrote:

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.


Yes, that's what I had in mind.  Though I think you can reconstruct the 
arguments rather than save them.


...

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


Nicer, yes, but I think that's a secondary concern after usefulness of 
the actual message.  In similar cases I've introduced the errors with 
another message like %qD is implicitly deleted because the default 
definition would be ill-formed:


Or, in this case, deduction failed because substituting the template 
arguments would be ill-formed:



; 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?


That all makes sense, but I'd put it in a follow-on patch.  And wrap the 
complexity in a cp_error function that takes a complain parameter and 
either gives no message, a note, or an error depending.


Jason


Re: [PATCH,c++] describe reasons for function template overload resolution failure

2011-05-10 Thread Jason Merrill

On 05/09/2011 06:49 PM, Nathan Froyd wrote:

The patch below is an updated version of:

http://gcc.gnu.org/ml/libstdc++/2011-02/msg9.html


Sorry I didn't respond to that message.

In general, my preference is to have diagnostics collocated with the 
tests that lead to them, and just run through the same code a second 
time if we decide that we want to give a diagnostic.  For instance, 
that's what I did in joust and synthesized_method_walk.  Saving 
information ahead of time about why we reject a particular candidate 
creates overhead that is useless in the vast majority of cases, since 
most compiles succeed.


That said, I'm not going to reject this patch over this issue, but 
please keep this principle in mind with future diagnostic improvement 
patches.



+case ur_invalid_arg:
+case ur_invalid_parm:
+case ur_invalid_init_list:
+case ur_invalid_template_parm:
+  inform (loc,   an error occurred during template argument deduction);


These are all cases of bailing out when we encounter an error_mark_node 
that indicates an earlier error from an ill-formed expression or 
whatever.  I don't see any reason to have separate cases for them, and 
the message is misleading; the error didn't occur during deduction, it 
occurred before we got to deduction.  We just can't do deduction on 
ill-formed inputs.



+case ur_type_mismatch:
+case ur_pointer_mismatch:
+case ur_reference_mismatch:
+  inform (loc,mismatched types %qT and %qT,


Why make these different?  They are all cases of the argument and 
parameter types not having the same form.



+case ur_expanding_pack_to_fixed_arg_list:


This is never generated anywhere.  And the message in 
coerce_template_parms is a sorry to indicate that this is a bug in G++, 
not a problem with the user's code.



unify_failure (struct unification_info *ui, tree parm)

...

return unify_failure (ui);


This doesn't compile.  Were you testing a previous version of the patch?

I guess I'll stop reviewing the patch now and wait for an update.

Jason