[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