rZhBoYao updated this revision to Diff 543559.
rZhBoYao added a comment.

Refactor VisitCXXOperatorCallExpr and mark CWG2571 as done in Clang 15 
(deliberately the same version P2128R6 was implemented) since this patch only 
fix the diagnostics around it.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156057/new/

https://reviews.llvm.org/D156057

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CXX/drs/dr25xx.cpp
  clang/test/SemaCXX/warn-unsequenced.cpp
  clang/www/cxx_dr_status.html

Index: clang/www/cxx_dr_status.html
===================================================================
--- clang/www/cxx_dr_status.html
+++ clang/www/cxx_dr_status.html
@@ -15233,7 +15233,7 @@
     <td><a href="https://cplusplus.github.io/CWG/issues/2571.html";>2571</a></td>
     <td>CD6</td>
     <td>Evaluation order for subscripting</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="full" align="center">Clang 15</td>
   </tr>
   <tr class="open" id="2572">
     <td><a href="https://cplusplus.github.io/CWG/issues/2572.html";>2572</a></td>
Index: clang/test/SemaCXX/warn-unsequenced.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsequenced.cpp
+++ clang/test/SemaCXX/warn-unsequenced.cpp
@@ -1,7 +1,9 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=cxx11 -std=c++11 -Wno-unused -Wno-uninitialized \
-// RUN:            -Wunsequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
-// RUN: %clang_cc1 -fsyntax-only -verify=cxx17 -std=c++17 -Wno-unused -Wno-uninitialized \
-// RUN:            -Wunsequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
+// RUN:            -Wunsequenced -Windeterminately-sequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify=since-cxx17 -std=c++17 -Wno-unused -Wno-uninitialized \
+// RUN:            -Wunsequenced -Windeterminately-sequenced %s
+// RUN: %clang_cc1 -fsyntax-only -verify=since-cxx17 -std=c++23 -Wno-unused -Wno-uninitialized \
+// RUN:            -Wunsequenced -Windeterminately-sequenced %s
 
 int f(int, int = 0);
 int g1();
@@ -20,17 +22,17 @@
   int xs[10];
   ++a = 0; // ok
   a + ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-           // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+           // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
   a = ++a; // ok
   a + a++; // cxx11-warning {{unsequenced modification and access to 'a'}}
-           // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+           // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
   a = a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
   ++ ++a; // ok
   (a++, a++); // ok
   ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-             // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+             // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   a++ + a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-             // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+             // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   (a++, a) = 0; // ok, increment is sequenced before value computation of LHS
   a = xs[++a]; // ok
   a = xs[a++]; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
@@ -40,15 +42,15 @@
   a = (a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
   f(a, a); // ok
   f(a = 0, a); // cxx11-warning {{unsequenced modification and access to 'a'}}
-               // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+               // since-cxx17-warning@-1 {{indeterminately sequenced modification and access to 'a'}}
   f(a, a += 0); // cxx11-warning {{unsequenced modification and access to 'a'}}
-                // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                // since-cxx17-warning@-1 {{indeterminately sequenced modification and access to 'a'}}
   f(a = 0, a = 0); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                   // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                   // since-cxx17-warning@-1 {{multiple indeterminately sequenced modifications to 'a'}}
   a = f(++a); // ok
   a = f(a++); // ok
   a = f(++a, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                   // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                   // since-cxx17-warning@-1 {{multiple indeterminately sequenced modifications to 'a'}}
 
   // Compound assignment "A OP= B" is equivalent to "A = A OP B" except that A
   // is evaluated only once.
@@ -59,73 +61,73 @@
 
   A agg1 = { a++, a++ }; // ok
   A agg2 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                             // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                             // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
 
   S str1(a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                    // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                    // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   S str2 = { a++, a++ }; // ok
   S str3 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                             // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                             // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
 
   struct Z { A a; S s; } z = { { ++a, ++a }, { ++a, ++a } }; // ok
   a = S { ++a, a++ }.n; // ok
   A { ++a, a++ }.x; // ok
   a = A { ++a, a++ }.x; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
   A { ++a, a++ }.x + A { ++a, a++ }.y; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                                       // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                                       // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
 
   (xs[2] && (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                          // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                          // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
 
   (0 && (a = 0)) + a; // cxx11-warning {{use of logical '&&' with constant operand}}
                       // cxx11-note@-1 {{use '&' for a bitwise operation}}
                       // cxx11-note@-2 {{remove constant to silence this warning}}
-                      // cxx17-warning@-3 {{use of logical '&&' with constant operand}}
-                      // cxx17-note@-4 {{use '&' for a bitwise operation}}
-                      // cxx17-note@-5 {{remove constant to silence this warning}}
+                      // since-cxx17-warning@-3 {{use of logical '&&' with constant operand}}
+                      // since-cxx17-note@-4 {{use '&' for a bitwise operation}}
+                      // since-cxx17-note@-5 {{remove constant to silence this warning}}
 
   (1 && (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                      // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                      // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
                       // cxx11-warning@-2 {{use of logical '&&' with constant operand}}
                       // cxx11-note@-3 {{use '&' for a bitwise operation}}
                       // cxx11-note@-4 {{remove constant to silence this warning}}
-                      // cxx17-warning@-5 {{use of logical '&&' with constant operand}}
-                      // cxx17-note@-6 {{use '&' for a bitwise operation}}
-                      // cxx17-note@-7 {{remove constant to silence this warning}}
+                      // since-cxx17-warning@-5 {{use of logical '&&' with constant operand}}
+                      // since-cxx17-note@-6 {{use '&' for a bitwise operation}}
+                      // since-cxx17-note@-7 {{remove constant to silence this warning}}
 
 
   (xs[3] || (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                          // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                          // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
   (0 || (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                      // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                      // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
                       // cxx11-warning@-2 {{use of logical '||' with constant operand}}
                       // cxx11-note@-3 {{use '|' for a bitwise operation}}
-                      // cxx17-warning@-4 {{use of logical '||' with constant operand}}
-                      // cxx17-note@-5 {{use '|' for a bitwise operation}}
+                      // since-cxx17-warning@-4 {{use of logical '||' with constant operand}}
+                      // since-cxx17-note@-5 {{use '|' for a bitwise operation}}
   (1 || (a = 0)) + a; // cxx11-warning {{use of logical '||' with constant operand}}
                       // cxx11-note@-1 {{use '|' for a bitwise operation}}
-                      // cxx17-warning@-2 {{use of logical '||' with constant operand}}
-                      // cxx17-note@-3 {{use '|' for a bitwise operation}}
+                      // since-cxx17-warning@-2 {{use of logical '||' with constant operand}}
+                      // since-cxx17-note@-3 {{use '|' for a bitwise operation}}
 
 
   (xs[4] ? a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                         // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                         // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
   (0 ? a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                     // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                     // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
   (1 ? a : ++a) + a; // ok
   (0 ? a : a++) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                     // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                     // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
   (1 ? a : a++) + a; // ok
   (xs[5] ? ++a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                           // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                           // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
 
   (++a, xs[6] ? ++a : 0) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                              // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                              // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
 
   // Here, the read of the fourth 'a' might happen before or after the write to
   // the second 'a'.
   a += (a++, a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                     // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                     // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
 
   a = a++ && a; // ok
 
@@ -141,20 +143,20 @@
 
   // This has undefined behavior if a != 0.
   (a && a++) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                  // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+                  // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
 
   // FIXME: Don't warn here.
   (xs[7] && ++a) * (!xs[7] && ++a); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                                    // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                                    // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
 
   xs[0] = (a = 1, a); // ok
   (a -= 128) &= 128; // ok
   ++a += 1; // ok
 
   xs[8] ? ++a + a++ : 0; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                         // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                         // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   xs[8] ? 0 : ++a + a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                         // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                         // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   xs[8] ? ++a : a++; // no-warning
   xs[8] ? a+=1 : a+= 2; // no-warning
   (xs[8] ? a+=1 : a+= 2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
@@ -169,9 +171,9 @@
   (true ? a : a+=2) = a; // no-warning
 
   xs[8] && (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                        // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                        // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   xs[8] || (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                        // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                        // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
 
   ((a++, false) || (a++, false)); // no-warning PR39779
   ((a++, true) && (a++, true)); // no-warning PR39779
@@ -197,17 +199,17 @@
   a = (false || ++a); // no-warning
 
   (a++) | (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                 // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                 // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   (a++) & (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                 // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                 // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   (a++) ^ (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                 // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                 // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
 
   (__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok
   (__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok
   (__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok
   (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                                            // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+                                            // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
 
 
   int *p = xs;
@@ -216,7 +218,7 @@
   (i++, xs)[i++]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
   (++i, xs)[++i]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
   (i, xs)[++i + ++i]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-                      // cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}}
+                      // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}}
   p++[p == xs]; // cxx11-warning {{unsequenced modification and access to 'p'}}
   ++p[p++ == xs]; // cxx11-warning {{unsequenced modification and access to 'p'}}
 
@@ -227,9 +229,9 @@
   (PtrMem = &S::x ,ps)->*(PtrMem); // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
   (PtrMem = &S::x ,ps)->*(PtrMem = &S::x); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
   (PtrMem = nullptr) == (PtrMem = nullptr); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
-                                            // cxx17-warning@-1 {{multiple unsequenced modifications to 'PtrMem'}}
+                                            // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'PtrMem'}}
   (PtrMem = nullptr) == PtrMem; // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
-                                // cxx17-warning@-1 {{unsequenced modification and access to 'PtrMem'}}
+                                // since-cxx17-warning@-1 {{unsequenced modification and access to 'PtrMem'}}
 
   i++ << i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
   ++i << ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
@@ -240,13 +242,13 @@
   i++ >> i; // cxx11-warning {{unsequenced modification and access to 'i'}}
   i >> i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
   (i++ << i) + i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-                  // cxx17-warning@-1 {{unsequenced modification and access to 'i'}}
+                  // since-cxx17-warning@-1 {{unsequenced modification and access to 'i'}}
   (i++ << i) << i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
 
   ++i = i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
   i = i+= 1; // no-warning
   i = i++ + ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-                 // cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}}
+                 // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}}
   ++i += ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
   ++i += i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
   (i++, i) += ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
@@ -279,15 +281,18 @@
                                   // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
 
   (i++, f)(i++, 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  f((++i, f)(i++, j++), ++j); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+                              // cxx11-warning@-1 {{multiple unsequenced modifications to 'j'}}
+                              // since-cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'j'}}
   (i++ + i++, f)(42, 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-                          // cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}}
+                          // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}}
   int (*pf)(int, int);
   (pf = f)(pf != nullptr, pf != nullptr); // cxx11-warning {{unsequenced modification and access to 'pf'}}
   pf((pf = f) != nullptr, 42); // cxx11-warning {{unsequenced modification and access to 'pf'}}
   f((pf = f, 42), (pf = f, 42)); // cxx11-warning {{multiple unsequenced modifications to 'pf'}}
-                                 // cxx17-warning@-1 {{multiple unsequenced modifications to 'pf'}}
+                                 // since-cxx17-warning@-1 {{multiple indeterminately sequenced modifications to 'pf'}}
   pf((pf = f) != nullptr, pf == nullptr); // cxx11-warning {{unsequenced modification and access to 'pf'}}
-                                          // cxx17-warning@-1 {{unsequenced modification and access to 'pf'}}
+                                          // since-cxx17-warning@-1 {{indeterminately sequenced modification and access to 'pf'}}
 }
 
 namespace PR20819 {
@@ -305,7 +310,11 @@
     E &operator=(E &);
     E operator()(E);
     E operator()(E, E);
+#if __cplusplus >= 202302L
+    E operator[](auto...);
+#else
     E operator[](E);
+#endif
   } e;
   // Binary operators with unsequenced operands.
   E operator+(E,E);
@@ -349,47 +358,47 @@
     // Binary operators with unsequenced operands.
     ((void)i++,e) + ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) - ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) * ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) / ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) % ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) ^ ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) & ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) | ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
 
     ((void)i++,e) < ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) > ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) == ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) != ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) <= ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
     ((void)i++,e) >= ((void)i++,e);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
 
     // Binary operators where the RHS is sequenced before the LHS in C++17.
     ((void)i++,e) = ((void)i++,e);
@@ -417,7 +426,7 @@
 
     operator+=(((void)i++,e), ((void)i++,e));
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'i'}}
 
     // Binary operators where the LHS is sequenced before the RHS in C++17.
     ((void)i++,e) << ((void)i++,e);
@@ -435,16 +444,21 @@
 
     operator<<(((void)i++,e), ((void)i++,e));
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'i'}}
 
+#if __cplusplus >= 202302L
+    ((void)i++,e)[((void)i++,e), ++i];
+    // since-cxx17-warning@-1 {{multiple indeterminately sequenced modifications to 'i'}}
+#else
     ((void)i++,e)[((void)i++,e)];
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
+#endif
 
     ((void)i++,e)(((void)i++,e));
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
     e(((void)i++,e), ((void)i++,e));
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'i'}}
 
     ((void)i++,e).operator()(((void)i++,e));
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
@@ -464,7 +478,7 @@
 
     operator<<(operator<<(s, i++), i++);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // since-cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'i'}}
   }
 }
 
@@ -481,9 +495,9 @@
 
 void S1::member_f(S1 &s) {
   ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-             // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+             // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
   a + ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-           // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+           // since-cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
   ++a + ++b; // no-warning
   a + ++b; // no-warning
 
@@ -500,9 +514,9 @@
 
   // TODO Warn here for bit-fields in the same memory location.
   ++bf1 + ++bf1; // cxx11-warning {{multiple unsequenced modifications to 'bf1'}}
-                 // cxx17-warning@-1 {{multiple unsequenced modifications to 'bf1'}}
+                 // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'bf1'}}
   bf1 + ++bf1; // cxx11-warning {{unsequenced modification and access to 'bf1'}}
-               // cxx17-warning@-1 {{unsequenced modification and access to 'bf1'}}
+               // since-cxx17-warning@-1 {{unsequenced modification and access to 'bf1'}}
   ++bf1 + ++bf2; // no-warning TODO {{multiple unsequenced modifications to}}
   bf1 + ++bf2; // no-warning TODO {{unsequenced modification and access to}}
 
@@ -528,12 +542,12 @@
   ++s1_ref.a + d_ref.b; // no-warning
 
   ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-             // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+             // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
   ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-           // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+           // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
   ++s.x + x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
   ++this->x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-                 // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+                 // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
   ++d_ref.x + ++S1::x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
 }
 
@@ -651,9 +665,9 @@
   // Make sure we handle reference cycles.
   int &ref_cycle = ref_cycle;
   ++ref_cycle + ++ref_cycle; // cxx11-warning {{multiple unsequenced modifications to 'ref_cycle'}}
-                             // cxx17-warning@-1 {{multiple unsequenced modifications to 'ref_cycle'}}
+                             // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'ref_cycle'}}
   ref_cycle + ++ref_cycle; // cxx11-warning {{unsequenced modification and access to 'ref_cycle'}}
-                           // cxx17-warning@-1 {{unsequenced modification and access to 'ref_cycle'}}
+                           // since-cxx17-warning@-1 {{unsequenced modification and access to 'ref_cycle'}}
 }
 } // namespace references
 
@@ -677,9 +691,9 @@
   {
     auto [x, y] = a;
     ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+               // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
     ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+             // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
     ++x + ++a.x; // no-warning
@@ -688,9 +702,9 @@
   {
     auto &[x, y] = a;
     ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+               // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
     ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+             // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
     ++x + ++a.x; // no-warning TODO
@@ -702,9 +716,9 @@
   {
     auto [x, y] = b;
     ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+               // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
     ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+             // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
     ++x + ++b[0]; // no-warning
@@ -713,9 +727,9 @@
   {
     auto &[x, y] = b;
     ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+               // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
     ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+             // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
     ++x + ++b[0]; // no-warning TODO
@@ -727,18 +741,18 @@
   {
     auto [x, y] = c;
     ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+               // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
     ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+             // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
   }
   {
     auto &[x, y] = c;
     ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+               // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
     ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+             // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
   }
@@ -748,9 +762,9 @@
   {
     auto [x, y] = d;
     ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+               // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
     ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+             // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
     ++x + ++d.x; // no-warning
@@ -759,9 +773,9 @@
   {
     auto &[x, y] = d;
     ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
+               // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'x'}}
     ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
+             // since-cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
     ++x + ++d.x; // no-warning TODO
@@ -805,13 +819,13 @@
 
   foo(num++, num++);
   // cxx11-warning@-1 {{multiple unsequenced modifications to 'num'}}
-  // cxx17-warning@-2 {{multiple unsequenced modifications to 'num'}}
+  // since-cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'num'}}
   return 1;
 }
 
 int x = Foo<int>().Run();
 // cxx11-note@-1 {{in instantiation of member function 'templates::Foo<int>::Run'}}
-// cxx17-note@-2 {{in instantiation of member function 'templates::Foo<int>::Run'}}
+// since-cxx17-note@-2 {{in instantiation of member function 'templates::Foo<int>::Run'}}
 
 
 template <typename T>
@@ -828,9 +842,9 @@
 template <typename T> int var = sizeof(T);
 void test_var() {
   var<int>++ + var<int>++; // cxx11-warning {{multiple unsequenced modifications to 'var<int>'}}
-                           // cxx17-warning@-1 {{multiple unsequenced modifications to 'var<int>'}}
+                           // since-cxx17-warning@-1 {{multiple unsequenced modifications to 'var<int>'}}
   var<int>++ + var<int>; // cxx11-warning {{unsequenced modification and access to 'var<int>'}}
-                         // cxx17-warning@-1 {{unsequenced modification and access to 'var<int>'}}
+                         // since-cxx17-warning@-1 {{unsequenced modification and access to 'var<int>'}}
   int &r = var<int>;
   r++ + var<int>++; // no-warning TODO {{multiple unsequenced modifications to 'var<int>'}}
   r++ + var<long>++; // no-warning
Index: clang/test/CXX/drs/dr25xx.cpp
===================================================================
--- clang/test/CXX/drs/dr25xx.cpp
+++ clang/test/CXX/drs/dr25xx.cpp
@@ -146,3 +146,14 @@
 
 #endif
 }
+
+namespace dr2571 { // dr2571: 15
+#if __cplusplus >= 202302L
+struct S { int operator[](auto...); };
+int c{}, d{}, f(int, int = {}),
+    a = S()[c++, (++d, f)(!c, !d)],
+    // expected-warning@-1{{indeterminately sequenced modification and access to 'c'}}
+    b = S()[f(f(c++)), c++];
+    // expected-warning@-1{{multiple indeterminately sequenced modifications to 'c'}}
+#endif
+} // namespace dr2571
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -15692,6 +15692,8 @@
     };
     SmallVector<Value, 8> Values;
 
+    const SequenceChecker &SC;
+
   public:
     /// A region within an expression which may be sequenced with respect
     /// to some other region.
@@ -15706,7 +15708,9 @@
       Seq() : Index(0) {}
     };
 
-    SequenceTree() { Values.push_back(Value(0)); }
+    SequenceTree(const SequenceChecker &SC) : SC(SC) {
+      Values.push_back(Value(0));
+    }
     Seq root() const { return Seq(0); }
 
     /// Create a new sequence of operations, which is an unsequenced
@@ -15736,6 +15740,29 @@
       return false;
     }
 
+    /// Determine whether two operations are indeterminately sequenced. This
+    /// operation is asymmetric: \p Cur should be the more recent sequence, and
+    /// \p Old should have been merged into its parent as appropriate.
+    bool isIndeterminatelySequenced(Seq Cur, Seq Old) {
+      unsigned C = representative(Cur.Index);
+      unsigned Target = representative(Old.Index);
+      for (Seq seq : llvm::iterator_range(SC.CallPostfixExprs.rbegin(),
+                                          SC.CallPostfixExprs.rend())) {
+        unsigned Sibling = seq.Index;
+        unsigned Parent = Values[Sibling].Parent;
+        if (Target <= Sibling)
+          continue;
+        if ((Target = Values[Target].Parent) != Parent)
+          continue;
+        while (C >= Target) {
+          if (C == Target)
+            return true;
+          C = Values[C].Parent;
+        }
+      }
+      return false;
+    }
+
   private:
     /// Pick a representative for a sequence.
     unsigned representative(unsigned K) {
@@ -15788,7 +15815,7 @@
   Sema &SemaRef;
 
   /// Sequenced regions within the expression.
-  SequenceTree Tree;
+  SequenceTree Tree = *this;
 
   /// Declaration modifications and references which we have seen.
   UsageInfoMap UsageMap;
@@ -15800,10 +15827,6 @@
   /// (that is, post-increment operations).
   SmallVectorImpl<std::pair<Object, Usage>> *ModAsSideEffect = nullptr;
 
-  /// Expressions to check later. We defer checking these to reduce
-  /// stack usage.
-  SmallVectorImpl<const Expr *> &WorkList;
-
   /// RAII object wrapping the visitation of a sequenced subexpression of an
   /// expression. At the end of this process, the side-effects of the evaluation
   /// become sequenced with respect to the value computation of the result, so
@@ -15864,6 +15887,22 @@
     bool EvalOK = true;
   } *EvalTracker = nullptr;
 
+  /// RAII object tracking the visitation of CallExpr and that of its
+  /// subexpressions.
+  struct InCallExprArgs {
+    InCallExprArgs(SequenceChecker &SC) : SC(SC) {
+      SC.CallPostfixExprs.push_back(SC.Region);
+    };
+
+    ~InCallExprArgs() { SC.CallPostfixExprs.pop_back(); }
+
+  private:
+    SequenceChecker &SC;
+  };
+
+  /// Only modified by InCallExprArgs
+  SmallVector<SequenceTree::Seq, 4> CallPostfixExprs;
+
   /// Find the object which is produced by the specified expression,
   /// if any.
   Object getObject(const Expr *E, bool Mod) const {
@@ -15892,7 +15931,11 @@
   void addUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, UsageKind UK) {
     // Get the old usage for the given object and usage kind.
     Usage &U = UI.Uses[UK];
-    if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) {
+    bool FoundUnsequenced = U.UsageExpr && Tree.isUnsequenced(Region, U.Seq);
+    bool FoundIndeterminatelySequenced =
+        U.UsageExpr && SemaRef.LangOpts.CPlusPlus17 &&
+        Tree.isIndeterminatelySequenced(Region, U.Seq);
+    if (!FoundUnsequenced && !FoundIndeterminatelySequenced) {
       // If we have a modification as side effect and are in a sequenced
       // subexpression, save the old Usage so that we can restore it later
       // in SequencedSubexpression::~SequencedSubexpression.
@@ -15915,7 +15958,11 @@
       return;
 
     const Usage &U = UI.Uses[OtherKind];
-    if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq))
+    bool FoundUnsequenced = U.UsageExpr && Tree.isUnsequenced(Region, U.Seq);
+    bool FoundIndeterminatelySequenced =
+        U.UsageExpr && SemaRef.LangOpts.CPlusPlus17 &&
+        Tree.isIndeterminatelySequenced(Region, U.Seq);
+    if (!FoundUnsequenced && !FoundIndeterminatelySequenced)
       return;
 
     const Expr *Mod = U.UsageExpr;
@@ -15925,8 +15972,12 @@
 
     SemaRef.DiagRuntimeBehavior(
         Mod->getExprLoc(), {Mod, ModOrUse},
-        SemaRef.PDiag(IsModMod ? diag::warn_unsequenced_mod_mod
-                               : diag::warn_unsequenced_mod_use)
+        SemaRef.PDiag(!FoundUnsequenced && FoundIndeterminatelySequenced
+                          ? IsModMod
+                                ? diag::warn_indeterminately_sequenced_mod_mod
+                                : diag::warn_indeterminately_sequenced_mod_use
+                      : IsModMod ? diag::warn_unsequenced_mod_mod
+                                 : diag::warn_unsequenced_mod_use)
             << O << SourceRange(ModOrUse->getExprLoc()));
     UI.Diagnosed = true;
   }
@@ -15985,13 +16036,9 @@
   }
 
 public:
-  SequenceChecker(Sema &S, const Expr *E,
-                  SmallVectorImpl<const Expr *> &WorkList)
-      : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) {
+  SequenceChecker(Sema &S, const Expr *E)
+      : Base(S.Context), SemaRef(S), Region(Tree.root()) {
     Visit(E);
-    // Silence a -Wunused-private-field since WorkList is now unused.
-    // TODO: Evaluate if it can be used, and if not remove it.
-    (void)this->WorkList;
   }
 
   void VisitStmt(const Stmt *S) {
@@ -16332,43 +16379,48 @@
     //   the value computation of its result].
     SequencedSubexpression Sequenced(*this);
     SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), [&] {
+      if (!SemaRef.getLangOpts().CPlusPlus17)
+        return Base::VisitCallExpr(CE);
+
       // C++17 [expr.call]p5
       //   The postfix-expression is sequenced before each expression in the
       //   expression-list and any default argument. [...]
-      SequenceTree::Seq CalleeRegion;
-      SequenceTree::Seq OtherRegion;
-      if (SemaRef.getLangOpts().CPlusPlus17) {
-        CalleeRegion = Tree.allocate(Region);
-        OtherRegion = Tree.allocate(Region);
-      } else {
-        CalleeRegion = Region;
-        OtherRegion = Region;
-      }
-      SequenceTree::Seq OldRegion = Region;
-
-      // Visit the callee expression first.
+      SequenceTree::Seq Parent = Region;
+      SequenceTree::Seq CalleeRegion = Tree.allocate(Parent);
       Region = CalleeRegion;
-      if (SemaRef.getLangOpts().CPlusPlus17) {
+      {
         SequencedSubexpression Sequenced(*this);
-        Visit(CE->getCallee());
-      } else {
-        Visit(CE->getCallee());
+        Visit(isa<CXXOperatorCallExpr>(CE) ? CE->getArg(0) : CE->getCallee());
       }
 
-      // Then visit the argument expressions.
-      Region = OtherRegion;
-      for (const Expr *Argument : CE->arguments())
+      // C++17 [expr.call]p5
+      //   [...] The initialization of a parameter, including every associated
+      //   value computation and side effect, is indeterminately sequenced with
+      //   respect to that of any other parameter.
+      SmallVector<SequenceTree::Seq, 16> Args;
+      auto ArgRange =
+          isa<CXXOperatorCallExpr>(CE)
+              ? llvm::iterator_range(CE->arg_begin() + 1, CE->arg_end())
+              : CE->arguments();
+      InCallExprArgs _(*this);
+      for (const Expr *Argument : ArgRange) {
+        SequencedSubexpression Sequenced(*this);
+        Region = Tree.allocate(Parent);
+        Args.push_back(Region);
         Visit(Argument);
-
-      Region = OldRegion;
-      if (SemaRef.getLangOpts().CPlusPlus17) {
-        Tree.merge(CalleeRegion);
-        Tree.merge(OtherRegion);
       }
+
+      Region = Parent;
+      Tree.merge(CalleeRegion);
+      for (SequenceTree::Seq region : Args)
+        Tree.merge(region);
     });
   }
 
   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *CXXOCE) {
+    if (!SemaRef.getLangOpts().CPlusPlus17)
+      return VisitCallExpr(CXXOCE);
+
     // C++17 [over.match.oper]p2:
     //   [...] the operator notation is first transformed to the equivalent
     //   function-call notation as summarized in Table 12 (where @ denotes one
@@ -16379,52 +16431,59 @@
     // From the above only overloaded binary operators and overloaded call
     // operators have sequencing rules in C++17 that we need to handle
     // separately.
-    if (!SemaRef.getLangOpts().CPlusPlus17 ||
-        (CXXOCE->getNumArgs() != 2 && CXXOCE->getOperator() != OO_Call))
-      return VisitCallExpr(CXXOCE);
-
     enum {
       NoSequencing,
       LHSBeforeRHS,
       RHSBeforeLHS,
-      LHSBeforeRest
+      IndeterminatelySequenced
     } SequencingKind;
-    switch (CXXOCE->getOperator()) {
-    case OO_Equal:
-    case OO_PlusEqual:
-    case OO_MinusEqual:
-    case OO_StarEqual:
-    case OO_SlashEqual:
-    case OO_PercentEqual:
-    case OO_CaretEqual:
-    case OO_AmpEqual:
-    case OO_PipeEqual:
-    case OO_LessLessEqual:
-    case OO_GreaterGreaterEqual:
+    if (CXXOCE->isAssignmentOp())
       SequencingKind = RHSBeforeLHS;
-      break;
+    else
+      switch (CXXOCE->getOperator()) {
+      case OO_LessLess:
+      case OO_GreaterGreater:
+      case OO_AmpAmp:
+      case OO_PipePipe:
+      case OO_Comma:
+      case OO_ArrowStar:
+        SequencingKind = LHSBeforeRHS;
+        break;
+      case OO_Subscript:
+        SequencingKind = SemaRef.getLangOpts().CPlusPlus23
+                             ? IndeterminatelySequenced // CWG2571
+                             : LHSBeforeRHS;
+        break;
+      case OO_Call:
+        SequencingKind = IndeterminatelySequenced;
+        break;
+      default:
+        SequencingKind = NoSequencing;
+        break;
+      }
 
-    case OO_LessLess:
-    case OO_GreaterGreater:
-    case OO_AmpAmp:
-    case OO_PipePipe:
-    case OO_Comma:
-    case OO_ArrowStar:
-    case OO_Subscript:
-      SequencingKind = LHSBeforeRHS;
-      break;
+    if (SequencingKind == NoSequencing) {
+      SequenceTree::Seq Parent = Region;
+      SequenceTree::Seq CalleeRegion = Tree.allocate(Parent);
+      SequenceTree::Seq OtherRegion = Tree.allocate(Parent);
 
-    case OO_Call:
-      SequencingKind = LHSBeforeRest;
-      break;
+      // Visit the callee expression first.
+      Region = CalleeRegion;
+      {
+        SequencedSubexpression Sequenced(*this);
+        Visit(CXXOCE->getCallee());
+      }
 
-    default:
-      SequencingKind = NoSequencing;
-      break;
-    }
+      // Then visit the argument expressions.
+      Region = OtherRegion;
+      for (const Expr *Argument : CXXOCE->arguments())
+        Visit(Argument);
 
-    if (SequencingKind == NoSequencing)
-      return VisitCallExpr(CXXOCE);
+      Region = Parent;
+      Tree.merge(CalleeRegion);
+      Tree.merge(OtherRegion);
+      return;
+    }
 
     // This is a call, so all subexpressions are sequenced before the result.
     SequencedSubexpression Sequenced(*this);
@@ -16432,63 +16491,31 @@
     SemaRef.runWithSufficientStackSpace(CXXOCE->getExprLoc(), [&] {
       assert(SemaRef.getLangOpts().CPlusPlus17 &&
              "Should only get there with C++17 and above!");
-      assert((CXXOCE->getNumArgs() == 2 || CXXOCE->getOperator() == OO_Call) &&
-             "Should only get there with an overloaded binary operator"
-             " or an overloaded call operator!");
-
-      if (SequencingKind == LHSBeforeRest) {
-        assert(CXXOCE->getOperator() == OO_Call &&
-               "We should only have an overloaded call operator here!");
-
-        // This is very similar to VisitCallExpr, except that we only have the
-        // C++17 case. The postfix-expression is the first argument of the
-        // CXXOperatorCallExpr. The expressions in the expression-list, if any,
-        // are in the following arguments.
-        //
-        // Note that we intentionally do not visit the callee expression since
-        // it is just a decayed reference to a function.
-        SequenceTree::Seq PostfixExprRegion = Tree.allocate(Region);
-        SequenceTree::Seq ArgsRegion = Tree.allocate(Region);
-        SequenceTree::Seq OldRegion = Region;
 
+      if (SequencingKind == IndeterminatelySequenced) {
+        assert((CXXOCE->getOperator() == OO_Subscript ||
+                CXXOCE->getOperator() == OO_Call) &&
+               "We should only have an overloaded call or subscript operator "
+               "here!");
         assert(CXXOCE->getNumArgs() >= 1 &&
-               "An overloaded call operator must have at least one argument"
-               " for the postfix-expression!");
-        const Expr *PostfixExpr = CXXOCE->getArgs()[0];
-        llvm::ArrayRef<const Expr *> Args(CXXOCE->getArgs() + 1,
-                                          CXXOCE->getNumArgs() - 1);
-
-        // Visit the postfix-expression first.
-        {
-          Region = PostfixExprRegion;
-          SequencedSubexpression Sequenced(*this);
-          Visit(PostfixExpr);
-        }
-
-        // Then visit the argument expressions.
-        Region = ArgsRegion;
-        for (const Expr *Arg : Args)
-          Visit(Arg);
-
-        Region = OldRegion;
-        Tree.merge(PostfixExprRegion);
-        Tree.merge(ArgsRegion);
-      } else {
-        assert(CXXOCE->getNumArgs() == 2 &&
-               "Should only have two arguments here!");
-        assert((SequencingKind == LHSBeforeRHS ||
-                SequencingKind == RHSBeforeLHS) &&
-               "Unexpected sequencing kind!");
-
-        // We do not visit the callee expression since it is just a decayed
-        // reference to a function.
-        const Expr *E1 = CXXOCE->getArg(0);
-        const Expr *E2 = CXXOCE->getArg(1);
-        if (SequencingKind == RHSBeforeLHS)
-          std::swap(E1, E2);
-
-        return VisitSequencedExpressions(E1, E2);
+               "An overloaded call or subscript operator must have at least "
+               "one argument for the postfix-expression!");
+        return VisitCallExpr(CXXOCE);
       }
+      assert(CXXOCE->getNumArgs() == 2 &&
+             "Should only have two arguments here!");
+      assert(
+          (SequencingKind == LHSBeforeRHS || SequencingKind == RHSBeforeLHS) &&
+          "Unexpected sequencing kind!");
+
+      // We do not visit the callee expression since it is just a decayed
+      // reference to a function.
+      const Expr *E1 = CXXOCE->getArg(0);
+      const Expr *E2 = CXXOCE->getArg(1);
+      if (SequencingKind == RHSBeforeLHS)
+        std::swap(E1, E2);
+
+      return VisitSequencedExpressions(E1, E2);
     });
   }
 
@@ -16542,12 +16569,7 @@
 } // namespace
 
 void Sema::CheckUnsequencedOperations(const Expr *E) {
-  SmallVector<const Expr *, 8> WorkList;
-  WorkList.push_back(E);
-  while (!WorkList.empty()) {
-    const Expr *Item = WorkList.pop_back_val();
-    SequenceChecker(*this, Item, WorkList);
-  }
+  SequenceChecker(*this, E);
 }
 
 void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2291,6 +2291,12 @@
   "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
 def warn_unsequenced_mod_use : Warning<
   "unsequenced modification and access to %0">, InGroup<Unsequenced>;
+def warn_indeterminately_sequenced_mod_mod : Warning<
+  "multiple indeterminately sequenced modifications to %0">,
+  InGroup<IndeterminatelySequenced>;
+def warn_indeterminately_sequenced_mod_use : Warning<
+  "indeterminately sequenced modification and access to %0">,
+  InGroup<IndeterminatelySequenced>;
 
 def select_initialized_entity_kind : TextSubstitution<
   "%select{copying variable|copying parameter|initializing template parameter|"
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -688,8 +688,9 @@
 def XorUsedAsPow : DiagGroup<"xor-used-as-pow">;
 
 def Unsequenced : DiagGroup<"unsequenced">;
+def IndeterminatelySequenced : DiagGroup<"indeterminately-sequenced">;
 // GCC name for -Wunsequenced
-def : DiagGroup<"sequence-point", [Unsequenced]>;
+def : DiagGroup<"sequence-point", [Unsequenced, IndeterminatelySequenced]>;
 
 // Preprocessor warnings.
 def AmbiguousMacro : DiagGroup<"ambiguous-macro">;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -453,6 +453,42 @@
 - Clang now emits ``-Wconstant-logical-operand`` warning even when constant logical
   operand is on left side.
   (`#37919 <https://github.com/llvm/llvm-project/issues/37919>`_)
+- Added a new warning group ``-Windeterminately-sequenced`` to diagnose indeterminately
+  sequenced accesses amongst the initializations of each function parameter, as is the
+  case from C++17 onwards. Accordingly, ``-Wunsequenced`` no longer falsely diagnoses
+  such accesses as unsequenced.
+  (`#63935 <https://github.com/llvm/llvm-project/issues/63935>`_)
+
+  *Example C++23 Code*:
+
+  .. code-block:: c++
+
+    struct S { int operator[](auto...); };
+    int c{}, d{}, f(int, int = {}),
+        a = f(c++, (++d, f)(!c, !d)),
+        b = S()[f(f(c++)), c++];
+
+  *BEFORE*:
+
+  .. code-block:: text
+
+    <source>:3:12: warning: unsequenced modification and access to 'c' [-Wunsequenced]
+        3 |     a = f(c++, (++d, f)(!c, !d)),
+          |            ^             ~
+    <source>:4:18: warning: multiple unsequenced modifications to 'c' [-Wunsequenced]
+        4 |     b = S()[f(f(c++)), c++];
+          |                  ^      ~~
+
+  *AFTER*:
+
+  .. code-block:: text
+
+    <source>:3:12: warning: indeterminately sequenced modification and access to 'c' [-Windeterminately-sequenced]
+        3 |     a = f(c++, (++d, f)(!c, !d)),
+          |            ^             ~
+    <source>:4:18: warning: multiple indeterminately sequenced modifications to 'c' [-Windeterminately-sequenced]
+        4 |     b = S()[f(f(c++)), c++];
+          |                  ^      ~~
 
 Bug Fixes in This Version
 -------------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to