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
>