From: Jakub Jelinek Date: Wed, 4 Feb 2026 11:29:24 +0000 (+0100) Subject: c++: Perform the iterating expansion stmt N evaluation in immediate context [PR123611] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=75930efa22fb722e734307332a81ed1505178ae6;p=thirdparty%2Fgcc.git 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 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 --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index de101b180e3..1ee8e2fff7d 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 00000000000..c2dcf2b469a --- /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 +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 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 s = { ^^int, ^^bool }; + template for (constexpr auto x : s) + ret += sizeof (typename [: x :]); + return ret; +}