[gcc r16-9473] c++: Fix up check_return_expr for expansion stmts [PR126420]

Jakub Jelinek via Gcc-cvs <[email protected]> Fri, 31 Jul 2026 07:44:09 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:9225ecd793ed88a94c1f3754f7a45d2dfc74e47a

commit r16-9473-g9225ecd793ed88a94c1f3754f7a45d2dfc74e47a
Author: Jakub Jelinek <[email protected]>
Date:   Fri Jul 31 08:47:54 2026 +0200

    c++: Fix up check_return_expr for expansion stmts [PR126420]
    
    The first testcase below is rejected because of a deduction failure,
    the second testcase ICEs.
    The first testcase is IFNDR according to
    https://eel.is/c++draft/temp.res.general#6.2
    - no valid specialization, ignoring static_assert-declarations that
      fail, can be generated for the compound-statement of an
      expansion-statement and there is no instantiation of it,
    so rejecting it is fine and accepting it silently too.
    But we ICE on the second testcase and that is a problem,
    we set current_function_returns_value = 1 in check_return_expr
    when the return value is dependent, and then don't instantiate it,
    and as it is the only return from the function, when we try to expand
    it we try to create dependent RESULT_DECL etc. for it and ICE.
    
    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.
    
    2026-07-30  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.
    
    Reviewed-by: Jason Merrill <[email protected]>
    (cherry picked from commit 72fba287f32b4a86c55c24b475de891fc88de217)

Diff:
---
 gcc/cp/pt.cc                                  |  3 +++
 gcc/cp/typeck.cc                              |  5 +++++
 gcc/testsuite/g++.dg/cpp26/expansion-stmt43.C | 11 +++++++++++
 gcc/testsuite/g++.dg/cpp26/expansion-stmt44.C | 10 ++++++++++
 4 files changed, 29 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dd578bef0bb3..4359ae8e5569 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19983,9 +19983,12 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    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));
 	  }
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index f6b8b26c542c..31972a07e639 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -11476,6 +11476,11 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
 
   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))
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt43.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt43.C
new file mode 100644
index 000000000000..591baf9d3833
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt43.C
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt44.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt44.C
new file mode 100644
index 000000000000..6a4b600c5185
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt44.C
@@ -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;
+}