https://gcc.gnu.org/g:72c20dda8e4b8dbab707a3b23b3cdc5eb862a83a
commit r16-7103-g72c20dda8e4b8dbab707a3b23b3cdc5eb862a83a Author: Jakub Jelinek <[email protected]> Date: Wed Jan 28 10:08:14 2026 +0100 c++: Implement part of CWG3044 The following patch implements part of CWG3044 resolution. Small part of it has been implemented already earlier (using ptrdiff_t as the type of i rather than leaving that unspecified), part of it can't be implemented until constexpr references are supported (removal of static keywords), but the final CWG3044 resolution wording states that it is begin + decltype(begin - begin){i} rather than just begin + i. The following patch implements that. It broke a bunch of tests because I haven't implemented operator - for those. fixed that too (plus added a testcase expected to fail now with operator - not implemented). 2026-01-28 Jakub Jelinek <[email protected]> * pt.cc (finish_expansion_stmt): Implement part of CWG3044. Add to begin decltype(begin - begin){i} with std::ptrdiff_t i instead of just i. * g++.dg/cpp26/expansion-stmt1.C (A::operator -, C::operator -): New. * g++.dg/cpp26/expansion-stmt2.C (A::operator -, C::operator -): New. * g++.dg/cpp26/expansion-stmt3.C (A::operator -, C::operator -): New. * g++.dg/cpp26/expansion-stmt18.C (A::operator -): New. * g++.dg/cpp26/expansion-stmt25.C: New test. Diff: --- gcc/cp/pt.cc | 26 ++++++++++++++++++++++---- gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C | 2 ++ gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C | 1 + gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C | 2 ++ gcc/testsuite/g++.dg/cpp26/expansion-stmt25.C | 27 +++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C | 2 ++ 6 files changed, 56 insertions(+), 4 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 614b006069dd..de101b180e38 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -33162,7 +33162,7 @@ finish_expansion_stmt (tree expansion_stmt, tree args, return; location_t loc = DECL_SOURCE_LOCATION (range_decl); - tree begin = NULL_TREE; + tree begin = NULL_TREE, begin_minus_begin_type = NULL_TREE; auto_vec<tree, 8> destruct_decls; if (BRACE_ENCLOSED_INITIALIZER_P (expansion_init)) { @@ -33309,10 +33309,28 @@ finish_expansion_stmt (tree expansion_stmt, tree args, init = CONSTRUCTOR_ELT (expansion_init, i)->value; break; case esk_iterating: - tree iter_init, auto_node, iter_type, iter; + tree iter_init, auto_node, iter_type, iter, it; + it = build_int_cst (ptrdiff_type_node, i); + if (begin_minus_begin_type == NULL_TREE) + { + ++cp_unevaluated_operand; + ++c_inhibit_evaluation_warnings; + tree begin_minus_begin + = build_x_binary_op (loc, MINUS_EXPR, begin, TREE_CODE (begin), + begin, TREE_CODE (begin), NULL_TREE, NULL, + tf_warning_or_error); + --cp_unevaluated_operand; + --c_inhibit_evaluation_warnings; + begin_minus_begin_type + = finish_decltype_type (begin_minus_begin, false, + tf_warning_or_error); + } + it = build_constructor_single (init_list_type_node, NULL_TREE, it); + CONSTRUCTOR_IS_DIRECT_INIT (it) = true; + it = finish_compound_literal (begin_minus_begin_type, it, + tf_warning_or_error, fcl_functional); iter_init - = build_x_binary_op (loc, PLUS_EXPR, begin, ERROR_MARK, - build_int_cst (ptrdiff_type_node, i), + = build_x_binary_op (loc, PLUS_EXPR, begin, ERROR_MARK, it, ERROR_MARK, NULL_TREE, NULL, tf_warning_or_error); auto_node = make_auto (); diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C index 20a7413c1457..7cc01f1d97f3 100644 --- a/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C @@ -24,6 +24,7 @@ struct A constexpr int operator * () const { return x; } constexpr bool operator != (const A &o) const { return x != o.x; } constexpr A operator + (int o) const { A r (x + o); return r; } + constexpr int operator - (const A &o) const { return x - o.x; } }; struct C { @@ -33,6 +34,7 @@ struct C constexpr C operator * () const { return *this; } constexpr bool operator != (const C &o) const { return x != o.x || y != o.y || z != o.z; } constexpr C operator + (int o) const { C r (x + o, y - o, z + o); return r; } + constexpr int operator - (const C &o) const { return x - o.x; } }; namespace N diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C index ce0b39f5b6a2..c49c5f2f9ff8 100644 --- a/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C @@ -11,6 +11,7 @@ struct A constexpr int operator * () const { return x; } constexpr bool operator != (const A &o) const { return x != o.x; } constexpr A operator + (int o) const { A r (x + o); return r; } + constexpr int operator - (const A &o) const { return x - o.x; } }; namespace N diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C index 89f6cce2670c..b1ab50c1cea7 100644 --- a/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C @@ -24,6 +24,7 @@ struct A constexpr int operator * () const { return x; } constexpr bool operator != (const A &o) const { return x != o.x; } constexpr A operator + (int o) const { A r (x + o); return r; } + constexpr int operator - (const A &o) const { return x - o.x; } }; struct C { @@ -33,6 +34,7 @@ struct C constexpr C operator * () const { return *this; } constexpr bool operator != (const C &o) const { return x != o.x || y != o.y || z != o.z; } constexpr C operator + (int o) const { C r (x + o, y - o, z + o); return r; } + constexpr int operator - (const C &o) const { return x - o.x; } }; namespace N diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt25.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt25.C new file mode 100644 index 000000000000..0d6d3f2d4615 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt25.C @@ -0,0 +1,27 @@ +// C++26 P1306R5 - Expansion statements +// { dg-do compile { target c++14 } } +// { dg-options "" } + +struct A +{ + int x; + constexpr explicit A (int v) : x(v) {} + constexpr A &operator ++ () { ++x; return *this; } + constexpr int operator * () const { return x; } + constexpr bool operator != (const A &o) const { return x != o.x; } + constexpr A operator + (int o) const { A r (x + o); return r; } +}; + +namespace N +{ + struct B { constexpr B () {} }; + constexpr A begin (B &) { return A (0); } + constexpr A end (B &) { return A (6); } +} + +void +foo () +{ + template for (auto i : N::B {}) // { dg-warning "'template for' only available with" "" { target c++23_down } } + ; // { dg-error "no match for 'operator-' in '__for_begin - __for_begin ' \\\(operand types are 'const A' and 'const A'\\\)" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C b/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C index 5103b3420f5e..c8a3879d5d66 100644 --- a/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C +++ b/gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C @@ -24,6 +24,7 @@ struct A constexpr int operator * () const { return x; } constexpr bool operator != (const A &o) const { return x != o.x; } constexpr A operator + (int o) const { A r (x + o); return r; } + constexpr int operator - (const A &o) const { return x - o.x; } }; struct C { @@ -33,6 +34,7 @@ struct C constexpr C operator * () const { return *this; } constexpr bool operator != (const C &o) const { return x != o.x || y != o.y || z != o.z; } constexpr C operator + (int o) const { C r (x + o, y - o, z + o); return r; } + constexpr int operator - (const C &o) const { return x - o.x; } }; namespace N
