[PATCH, v3] coroutines: Fix ICE on invalid (PR93458).

2020-01-30 Thread Iain Sandoe
Hi Nathan,

Nathan Sidwell  wrote:

> On 1/29/20 10:39 AM, Iain Sandoe wrote:
>> Hi Nathan,

>> +  /* If we are missing fundmental information, such as the traits, then 
>> don't
>> + emit this for every keyword in a TU.  This particular error is per TU
>> + so we don't need to keep the indicator per function.  */
>> +  static bool traits_error_emitted = false;
> 
> You can of course move this into the if's block scope.
done.

>> +  if (traits_decl == error_mark_node)
>> +{
>> +  if (!traits_error_emitted)
>> +error_at (kw, "cannot find % template");
> 
> Give the name you were looking for:
>   "%<%E::%E%> ...", std_node, coro_traits_identifier

I had the “complain” flag on to the lookup so that it was emitting an error with
that information.

however. ….
> also, what if you find something, but it's not a type template?

… I’ve switched the complain off on lookup_qualified_name and now check for
a type template.

I took the liberty of repeating this treatment in the coroutine handle lookup 
code
(new testcases attached).

so the errors now look like:

"cannot find a valid coroutine traits template using 'std::coroutine_traits’”

and

"cannot find a valid coroutine handle class template using 
'std::coroutine_handle’”

.. but open to tweaking them if there could be bette wording.

>>/* Coroutine traits template.  */
>>coro_traits_templ = find_coro_traits_template_decl (loc);
>> -  gcc_checking_assert (coro_traits_templ != NULL);
>> +  if (coro_traits_templ == NULL_TREE
>> +  || coro_traits_templ == error_mark_node)
>> +return false;
> 
> ISTM that find_coro_traits_template_decl should be returning exactly one of 
> NULL_TREE of error_mark_node on failure.  Its users don't particularly care 
> why it failed (not found vs found ambiguous/not template).

fair enough, settled for NULL_TREE.
> +  /* Save the coroutine data on the side to avoid the overhead on every

>> +  if (!coro_info->coro_ret_type_error_emitted)
>> +error_at (DECL_SOURCE_LOCATION (fndecl), "a coroutine must have a"
>> +  " class or struct return type");
> 
> Perhaps something like "coroutine return type %qT is not a class"?  I.e. show 
> them the type.
> (structs are classes, there's no need to say 'class or struct’)

yes, that’s nicer, done.

>> +  coro_info->coro_ret_type_error_emitted = true;
>> +  return false;
>> +}
>> +
>>tree templ_class = instantiate_coro_traits (fndecl, loc);
>>  /* Find the promise type for that.  */
>> @@ -422,7 +454,7 @@ coro_promise_type_found_p (tree fndecl, location_t loc)
>>/* Try to find the handle type for the promise.  */
>>tree handle_type =
>>  instantiate_coro_handle_for_promise_type (loc, coro_info->promise_type);
>> -  if (handle_type == NULL_TREE)
>> +  if (handle_type == NULL_TREE || handle_type == error_mark_node)
> 
> similar to coro_traits_template_decl.

gave this a similar treatment.

As below with those changes and additional test cases,
OK / tweak error messages?
thanks
Iain.

Since coroutine-ness is discovered lazily, we encounter the diagnostics
during each keyword parse.  We were not handling the case where a user code
failed to include fundamental information (e.g. the traits) in a graceful
manner.

Once we've emitted an error for this level of fail, then we suppress
additional copies (otherwise the same thing will be reported for every
coroutine keyword seen).

gcc/cp/ChangeLog:

2020-01-30  Iain Sandoe  

* coroutines.cc (struct coroutine_info): Add a bool flag to note
that we emitted an error for a bad function return type.
(get_coroutine_info): Tolerate an unset info table in case of
missing traits.
(find_coro_traits_template_decl): In case of error or if we didn't
find a type template, note we emitted the error and suppress
duplicates.
(find_coro_handle_template_decl): Likewise.
(instantiate_coro_traits): Only check for error_mark_node in the
return from lookup_qualified_name.
(coro_promise_type_found_p): Reorder initialization so that we check
for the traits and their usability before allocation of the info
table.  Check for a suitable return type and emit a diagnostic for
here instead of relying on the lookup machinery.  This allows the
error to have a better location, and means we can suppress multiple
copies.
(coro_function_valid_p): Re-check for a valid promise (and thus the
traits) before proceeding.  Tolerate missing info as a fatal error.

gcc/testsuite/ChangeLog:

2020-01-30  Iain Sandoe  

* g++.dg/coroutines/pr93458-1-missing-traits.C: New test.
* g++.dg/coroutines/pr93458-2-bad-traits.C: New test.
* g++.dg/coroutines/pr93458-3-missing-handle.C: New test.
* g++.dg/coroutines/pr93458-4-bad-coro-handle.C: New test.
* g++.dg/coroutines/pr93458-5-bad-coro-type.C:

Re: [PATCH, v3] coroutines: Fix ICE on invalid (PR93458).

2020-01-31 Thread Nathan Sidwell

On 1/30/20 9:43 AM, Iain Sandoe wrote:

Hi Nathan,



however. ….

also, what if you find something, but it's not a type template?


… I’ve switched the complain off on lookup_qualified_name and now check for
a type template.


I'm not sure that's helpful.  I think you should still complain on the 
lookup.  If that returns error_mark_node, you're done.  If it returns 
NULL, does it emit an error?  If not, you should emit a not found error. 
 Finally, if it does return a thing, check if it's a class template 
decl (or alias template I guess --  DECL_TEMPLATE_RESULT being a 
TYPE_DECL is close enough) and if not, error on that (X is not a 
template class).  Then the user's fully clued in.



I took the liberty of repeating this treatment in the coroutine handle lookup 
code
(new testcases attached).

so the errors now look like:

"cannot find a valid coroutine traits template using 'std::coroutine_traits’”


hm, 'valid'.  If you find a template_decl, but cannot instantiate it, 
that sounds not valid.  But I suspect you do not diagnose that here, 
because in general you cannot :)


sorry to be a pain.

nathan
--
Nathan Sidwell