[gcc r16-7280] c++: Perform the iterating expansion stmt N evaluation in immediate context [PR123611]

Jakub Jelinek jakub@gcc.gnu.org
Wed Feb 4 11:30:26 GMT 2026


https://gcc.gnu.org/g:75930efa22fb722e734307332a81ed1505178ae6

commit r16-7280-g75930efa22fb722e734307332a81ed1505178ae6
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Feb 4 12:29:24 2026 +0100

    c++: Perform the iterating expansion stmt N evaluation in immediate context [PR123611]
    
    For the N evaluation for iterating expansion stmts where the standard says
    to evaluate:
    [] consteval {
      std::ptrdiff_t result = 0;
      for (auto i = begin; i != end; ++i) ++result;
      return result;                                // distance from begin to end
    }()
    right now (subject to further changes in CWG3140) I wanted to save compile
    time/memory and effort to actually construct the lambda and it is evaluated
    just using TARGET_EXPRs.  On the following testcase it makes a difference,
    when the lambda is consteval, the expressions inside of it are evaluated
    in immediate context and so the testcase should be accepted, but we
    currently reject it when i has consteval-only type and expansion stmt
    doesn't appear in an immediate or immediate-escalating function.
    
    The following patch fixes this by forcing in_immediate_context () to be true
    around the evaluation.
    
    2026-02-04  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/123611
            * pt.cc (finish_expansion_stmt): Temporarily enable
            in_immediate_context () for the iterating expansion stmt N
            computation.
    
            * g++.dg/reflect/expansion-stmt1.C: New test.

Diff:
---
 gcc/cp/pt.cc                                   |  4 +++
 gcc/testsuite/g++.dg/reflect/expansion-stmt1.C | 49 ++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index de101b180e38..1ee8e2fff7df 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -33191,6 +33191,10 @@ finish_expansion_stmt (tree expansion_stmt, tree args,
       begin = cp_build_range_for_decls (loc, expansion_init, &end, true);
       if (!error_operand_p (begin) && !error_operand_p (end))
 	{
+	  /* In the standard this is all evaluated inside of a consteval
+	     lambda.  So, force in_immediate_context () around this.  */
+	  in_consteval_if_p_temp_override icip;
+	  in_consteval_if_p = true;
 	  tree i
 	    = build_target_expr_with_type (begin,
 					   cv_unqualified (TREE_TYPE (begin)),
diff --git a/gcc/testsuite/g++.dg/reflect/expansion-stmt1.C b/gcc/testsuite/g++.dg/reflect/expansion-stmt1.C
new file mode 100644
index 000000000000..c2dcf2b469aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/expansion-stmt1.C
@@ -0,0 +1,49 @@
+// PR c++/123611
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template <typename T>
+struct S {
+  T s[2];
+  constexpr const T *begin () const { return &s[0]; }
+  constexpr const T *end () const { return &s[2]; }
+};
+
+unsigned
+foo ()
+{
+  unsigned ret = 0;
+  static constexpr S <decltype (^^int)> s = { ^^int, ^^bool };
+  {
+    static constexpr decltype (auto) r = (s);
+    static constexpr auto b = r.begin ();
+    static constexpr auto e = r.end ();
+    using ptrdiff_t = decltype (&s - &s);
+    constexpr auto N = [] consteval {
+      ptrdiff_t res = 0;
+      for (auto i = b; i != e; ++i) ++res;
+      return res;
+    };
+    {
+      static constexpr auto i = b + decltype (b - b) { ptrdiff_t (0) };
+      constexpr auto x = *i;
+      ret += sizeof (typename [: x :]);
+    }
+    {
+      static constexpr auto i = b + decltype (b - b) { ptrdiff_t (1) };
+      constexpr auto x = *i;
+      ret += sizeof (typename [: x :]);
+    }
+  }
+  return ret;
+}
+
+unsigned
+bar ()
+{
+  unsigned ret = 0;
+  static constexpr S <decltype (^^int)> s = { ^^int, ^^bool };
+  template for (constexpr auto x : s)
+    ret += sizeof (typename [: x :]);
+  return ret;
+}


More information about the Gcc-cvs mailing list