Hi!

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).

This is on top of 
https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700380.html
(but only needed in the testsuite part, because of the const qual
additions nearby).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2025-11-14  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.

--- gcc/cp/pt.cc.jj     2025-11-14 16:40:33.885192060 +0100
+++ gcc/cp/pt.cc        2025-11-14 16:40:41.348088573 +0100
@@ -32776,7 +32776,7 @@ finish_expansion_stmt (tree expansion_st
     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))
     {
@@ -32921,10 +32921,28 @@ finish_expansion_stmt (tree expansion_st
          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 ();
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C.jj     2025-11-14 
16:40:33.886188245 +0100
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C        2025-11-14 
16:41:22.740057791 +0100
@@ -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
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C.jj     2025-11-14 
16:40:33.886305770 +0100
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C        2025-11-14 
16:41:45.869193857 +0100
@@ -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
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C.jj     2025-11-14 
16:40:33.886411212 +0100
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C        2025-11-14 
16:42:00.935339109 +0100
@@ -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
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C.jj    2025-11-14 
16:40:33.886508170 +0100
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C       2025-11-14 
16:41:34.239702362 +0100
@@ -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
--- gcc/testsuite/g++.dg/cpp26/expansion-stmt25.C.jj    2025-11-14 
16:40:41.350003201 +0100
+++ gcc/testsuite/g++.dg/cpp26/expansion-stmt25.C       2025-11-14 
16:40:41.350003201 +0100
@@ -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 }
+}

        Jakub

Reply via email to