]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Perform the iterating expansion stmt N evaluation in immediate context [PR123611]
authorJakub Jelinek <jakub@redhat.com>
Wed, 4 Feb 2026 11:29:24 +0000 (12:29 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 4 Feb 2026 11:29:24 +0000 (12:29 +0100)
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.

gcc/cp/pt.cc
gcc/testsuite/g++.dg/reflect/expansion-stmt1.C [new file with mode: 0644]

index de101b180e3845013911a74ef5fead44b3e2e3b8..1ee8e2fff7df2e0edd3da6838b205c03a34ced6f 100644 (file)
@@ -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 (file)
index 0000000..c2dcf2b
--- /dev/null
@@ -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;
+}