[PATCH] c++, coroutines: Avoid expanding within templates [PR103868]

Jason Merrill jason@redhat.com
Wed Apr 20 03:45:43 GMT 2022


On 4/18/22 15:49, Eric Gallager via Gcc-patches wrote:
> On Mon, Apr 18, 2022 at 10:01 AM Iain Sandoe via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>>
>> From: Nathan Sidwell <nathan@acm.org>
>>
>> This is a forward-port of a patch by Nathan (against 10.x) which fixes an open
>> PR.
>>
>> We are ICEing because we ended up tsubst_copying something that had already
>> been tsubst, leading to an assert failure (mostly such repeated tsubsting is
>> harmless).

I wouldn't say "mostly".  It should always be avoided, it frequently 
causes problems.  Pretty much any time there's a class prvalue.

>> We had a non-dependent co_await in a non-dependent-type template fn, so we
>> processed it at definition time, and then reprocessed at instantiation time.
>> We fix this here by deferring substitution while processing templates.
>>
>> Additional observations (for a better future fix, in the GCC13 timescale):
>>
>> Exprs only have dependent type if at least one operand is dependent which was
>> what the current code was intending to do.  Coroutines have the additional
>> wrinkle, that the current fn's type is an implicit operand.
>>
>> So, if the coroutine function's type is not dependent, and the operand is not
>> dependent, we should determine the type of the co_await expression using the
>> DEPENDENT_EXPR wrapper machinery.  That allows us to determine the
>> subexpression type, but leave its operand unchanged and then instantiate it
>> later.

Sure, like what build_x_binary_op and the like do.

>> Tested on x86_64-darwin (it does also fix the original testcase, but that is
>> far too time-consuming for the testsuite).

The compiler change seems fine as a temporary workaround.  Is it not 
feasible to write a new short testcase that reproduces the problem, now 
that you understand it?

>> OK for master? / backports? (when?)
>> thanks,
>> Iain
>>
>>          PR c++/103868
>>
>> gcc/cp/ChangeLog:
>>
>>          * coroutines.cc (finish_co_await_expr): Do not process non-dependent
>>          coroutine expressions at template definition time.
>>          (finish_co_yield_expr): Likewise.
>>          (finish_co_return_stmt): Likewise.
>>
>> gcc/testsuite/ChangeLog:
>>
>>          * g++.dg/coroutines/pr103868.C: New test.
>>
>> Co-Authored-by: Iain Sandoe <iain@sandoe.co.uk>
>> ---
>>   gcc/cp/coroutines.cc                       |   18 +-
>>   gcc/testsuite/g++.dg/coroutines/pr103868.C | 7390 ++++++++++++++++++++
>>   2 files changed, 7396 insertions(+), 12 deletions(-)
>>   create mode 100644 gcc/testsuite/g++.dg/coroutines/pr103868.C
>>
>> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
>> index cdf6503c4d3..a9ce6e050dd 100644
>> --- a/gcc/cp/coroutines.cc
>> +++ b/gcc/cp/coroutines.cc
>> @@ -1148,10 +1148,8 @@ finish_co_await_expr (location_t kw, tree expr)
>>        extraneous warnings during substitution.  */
>>     suppress_warning (current_function_decl, OPT_Wreturn_type);
>>
>> -  /* If we don't know the promise type, we can't proceed, build the
>> -     co_await with the expression unchanged.  */
>> -  tree functype = TREE_TYPE (current_function_decl);
>> -  if (dependent_type_p (functype) || type_dependent_expression_p (expr))
>> +  /* Defer processing when we have dependent types.  */
>> +  if (processing_template_decl)
>>       {
>>         tree aw_expr = build5_loc (kw, CO_AWAIT_EXPR, unknown_type_node, expr,
>>                                   NULL_TREE, NULL_TREE, NULL_TREE,
>> @@ -1222,10 +1220,8 @@ finish_co_yield_expr (location_t kw, tree expr)
>>        extraneous warnings during substitution.  */
>>     suppress_warning (current_function_decl, OPT_Wreturn_type);
>>
>> -  /* If we don't know the promise type, we can't proceed, build the
>> -     co_await with the expression unchanged.  */
>> -  tree functype = TREE_TYPE (current_function_decl);
>> -  if (dependent_type_p (functype) || type_dependent_expression_p (expr))
>> +  /* Defer processing when we have dependent types.  */
>> +  if (processing_template_decl)
>>       return build2_loc (kw, CO_YIELD_EXPR, unknown_type_node, expr, NULL_TREE);
>>
>>     if (!coro_promise_type_found_p (current_function_decl, kw))
>> @@ -1307,10 +1303,8 @@ finish_co_return_stmt (location_t kw, tree expr)
>>         && check_for_bare_parameter_packs (expr))
>>       return error_mark_node;
>>
>> -  /* If we don't know the promise type, we can't proceed, build the
>> -     co_return with the expression unchanged.  */
>> -  tree functype = TREE_TYPE (current_function_decl);
>> -  if (dependent_type_p (functype) || type_dependent_expression_p (expr))
>> +  /* Defer processing when we have dependent types.  */
>> +  if (processing_template_decl)
>>       {
>>         /* co_return expressions are always void type, regardless of the
>>           expression type.  */



More information about the Gcc-patches mailing list