Re: [PATCH] c++: Fix up check_return_expr for expansion stmts [PR126420]

Jason Merrill <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
On 7/27/26 4:54 PM, Jakub Jelinek wrote:
> Hi!
> 
> The first testcase below is rejected because of a deduction failure,
> the second testcase ICEs.
> I'm not sure what is the right behavior on the first testcase,
> we reject it because we see the return during parsing, the current
> function isn't a template, so FNDECL_USED_AUTO is already set from
> start_preparsed_function, but processing_template_decl is obviously
> true in the body, the return value is not dependent, so we think
> it is something that really happens in the function.
> But because the expansion statement has 0 iterations, the body is
> never instantiated.
> We do error (and so does clang++) on
> auto foo () { if (false) return 42; return 42L; }
> but I think not instantiating something is different from mere
> if (false).

It is different, and https://eel.is/c++draft/dcl#spec.auto.general-4 
specifically excludes discarded statements (if constexpr) from 
deduction.  This does also resemble the situation where a pack expansion 
is only valid for an empty pack, which is IFNDR.  But we need to have a 
specific answer about the effect if there is no other return; does foo 
return int or void?

So I think your patch makes sense.  OK.

> Anyway, the other issue is an ICE, because there is return x;
> where x is dependent, so the return type is not deduced just yet
> and as the body is never instantiated, it isn't deduced later on
> either, but because current_function_returns_value was set, we
> try to construct RESULT_DECL for that and crash on that.
> 
> The following patch just defers what check_return_expr normally
> does in expansion statement bodies.  For expansion statement not
> within a template check_return_expr will be called again when
> we try to instantiate the body (if at all), similarly for partial
> specialization we don't try to find out if the expansion stmt
> has constant number of iterations at that point and will invoke
> check_return_expr again during the final instantiation.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> Or shall we do something different?  Even if we need to clarify the
> standard, I think at least not ICEing is desirable until then.
> 
> 2026-07-27  Jakub Jelinek  <[email protected]>
> 
> 	PR c++/126420
> 	PR c++/126423
> 	* typeck.cc (check_return_expr): If in_expansion_stmt, goto
> 	dependent before even setting current_function_returns_value.
> 	* pt.cc (tsubst_stmt): Temporarily set in_expansion_stmt around
> 	partial instantiation of expansion statement body.
> 
> 	* g++.dg/cpp26/expansion-stmt43.C: New test.
> 	* g++.dg/cpp26/expansion-stmt44.C: New test.
> 
> --- gcc/cp/typeck.cc.jj	2026-06-10 22:44:05.246603008 +0200
> +++ gcc/cp/typeck.cc	2026-07-27 11:14:40.840258390 +0200
> @@ -11581,6 +11581,11 @@ check_return_expr (tree retval, bool *no
>   
>     if (processing_template_decl)
>       {
> +      /* If in expansion statement body, we don't know if the body
> +	 will be instantiated at all.  */
> +      if (in_expansion_stmt)
> +	goto dependent;
> +
>         current_function_returns_value = 1;
>   
>         if (check_for_bare_parameter_packs (retval))
> --- gcc/cp/pt.cc.jj	2026-07-26 15:37:03.624407302 +0200
> +++ gcc/cp/pt.cc	2026-07-27 11:20:14.508885954 +0200
> @@ -20151,9 +20151,12 @@ tsubst_stmt (tree t, tree args, tsubst_f
>   	    TEMPLATE_FOR_INIT_STMT (stmt) = pop_stmt_list (init);
>   	    add_stmt (stmt);
>   	    TEMPLATE_FOR_BODY (stmt) = do_pushlevel (sk_block);
> +	    auto save_in_expansion_stmt = in_expansion_stmt;
> +	    in_expansion_stmt = true;
>   	    bool prev = note_iteration_stmt_body_start ();
>   	    RECUR (TEMPLATE_FOR_BODY (t));
>   	    note_iteration_stmt_body_end (prev);
> +	    in_expansion_stmt = save_in_expansion_stmt;
>   	    TEMPLATE_FOR_BODY (stmt)
>   	      = do_poplevel (TEMPLATE_FOR_BODY (stmt));
>   	  }
> --- gcc/testsuite/g++.dg/cpp26/expansion-stmt43.C.jj	2026-07-27 11:24:29.186548629 +0200
> +++ gcc/testsuite/g++.dg/cpp26/expansion-stmt43.C	2026-07-27 11:23:44.227137784 +0200
> @@ -0,0 +1,11 @@
> +// PR c++/126420
> +// { dg-do compile { target c++14 } }
> +// { dg-options "" }
> +
> +auto
> +foo ()
> +{
> +  template for (auto x : {})	// { dg-warning "'template for' only available with" "" { target c++23_down } }
> +    return 42;
> +  return 42L;
> +}
> --- gcc/testsuite/g++.dg/cpp26/expansion-stmt44.C.jj	2026-07-27 11:24:32.134510000 +0200
> +++ gcc/testsuite/g++.dg/cpp26/expansion-stmt44.C	2026-07-27 11:24:13.297756839 +0200
> @@ -0,0 +1,10 @@
> +// PR c++/126423
> +// { dg-do compile { target c++14 } }
> +// { dg-options "" }
> +
> +auto
> +foo ()
> +{
> +  template for (auto x : {})	// { dg-warning "'template for' only available with" "" { target c++23_down } }
> +    return x;
> +}
> 
> 	Jakub
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.