]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Implement part of CWG3044
authorJakub Jelinek <jakub@redhat.com>
Wed, 28 Jan 2026 09:08:14 +0000 (10:08 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 28 Jan 2026 09:08:14 +0000 (10:08 +0100)
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  <jakub@redhat.com>

* 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
gcc/testsuite/g++.dg/cpp26/expansion-stmt1.C
gcc/testsuite/g++.dg/cpp26/expansion-stmt18.C
gcc/testsuite/g++.dg/cpp26/expansion-stmt2.C
gcc/testsuite/g++.dg/cpp26/expansion-stmt25.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp26/expansion-stmt3.C

index 614b006069dd1294a4a2cea45b6ea3e006deb535..de101b180e3845013911a74ef5fead44b3e2e3b8 100644 (file)
@@ -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 ();
index 20a7413c14577dd072476a0f5998c96aa8337f1d..7cc01f1d97f3100ab0cef040ab7d094bfdd19aa0 100644 (file)
@@ -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
index ce0b39f5b6a2923297ce2b05e2b3670fc8b38f18..c49c5f2f9ff8249821938e69dbd68d97b882776d 100644 (file)
@@ -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
index 89f6cce2670c8eea4a669bddc0decb19d4e7850c..b1ab50c1cea7fddaac333d95275e0ba385bd23e2 100644 (file)
@@ -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 (file)
index 0000000..0d6d3f2
--- /dev/null
@@ -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 }
+}
index 5103b3420f5e292bd8e5d68b08f8ac5d67102e9a..c8a3879d5d665a8d22c9694cfbf61618463ec01c 100644 (file)
@@ -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