From: Jakub Jelinek Date: Wed, 28 Jan 2026 09:08:14 +0000 (+0100) Subject: c++: Implement part of CWG3044 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=72c20dda8e4b8dbab707a3b23b3cdc5eb862a83a;p=thirdparty%2Fgcc.git 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 * 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 --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 614b006069d..de101b180e3 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 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 20a7413c145..7cc01f1d97f 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 ce0b39f5b6a..c49c5f2f9ff 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 89f6cce2670..b1ab50c1cea 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 00000000000..0d6d3f2d461 --- /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 5103b3420f5..c8a3879d5d6 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