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


Reply via email to