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

commit r16-7280-g75930efa22fb722e734307332a81ed1505178ae6
Author: Jakub Jelinek <[email protected]>
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  <[email protected]>
    
            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;
+}

Reply via email to