rZhBoYao created this revision.
rZhBoYao added reviewers: aaron.ballman, Endill, clang-language-wg.
Herald added a project: All.
rZhBoYao requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add -Windeterminately-sequenced and fix -Wunsequenced according to P0400R0 and 
CWG2571.


Repository:
  rG LLVM Github Monorepo

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/SemaCXX/warn-unsequenced.cpp

Index: clang/test/SemaCXX/warn-unsequenced.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsequenced.cpp
+++ clang/test/SemaCXX/warn-unsequenced.cpp
@@ -1,7 +1,7 @@
 // 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: %clang_cc1 -fsyntax-only -verify=cxx17 -std=c++23 -Wno-unused -Wno-uninitialized \
+// RUN:            -Wunsequenced %s
 
 int f(int, int = 0);
 int g1();
@@ -40,15 +40,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'}}
+               // 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'}}
+                // 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'}}
+                   // 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'}}
+                   // 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.
@@ -279,15 +279,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'}}
+                              // 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'}}
   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'}}
+                                 // 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'}}
+                                          // cxx17-warning@-1 {{indeterminately sequenced modification and access to 'pf'}}
 }
 
 namespace PR20819 {
@@ -305,7 +308,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);
@@ -417,7 +424,7 @@
 
     operator+=(((void)i++,e), ((void)i++,e));
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // 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 +442,21 @@
 
     operator<<(((void)i++,e), ((void)i++,e));
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'i'}}
 
+#if __cplusplus >= 202302L
+    ((void)i++,e)[((void)i++,e), ++i];
+    // 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'}}
+    // 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 +476,7 @@
 
     operator<<(operator<<(s, i++), i++);
     // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning@-2 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'i'}}
   }
 }
 
@@ -805,7 +817,7 @@
 
   foo(num++, num++);
   // cxx11-warning@-1 {{multiple unsequenced modifications to 'num'}}
-  // cxx17-warning@-2 {{multiple unsequenced modifications to 'num'}}
+  // cxx17-warning@-2 {{multiple indeterminately sequenced modifications to 'num'}}
   return 1;
 }
 
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,15 +16431,11 @@
     // 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:
@@ -16403,28 +16451,49 @@
     case OO_GreaterGreaterEqual:
       SequencingKind = RHSBeforeLHS;
       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;
-
+    case OO_Subscript:
+      SequencingKind = SemaRef.getLangOpts().CPlusPlus23
+                           ? IndeterminatelySequenced // CWG2571
+                           : LHSBeforeRHS;
+      break;
     case OO_Call:
-      SequencingKind = LHSBeforeRest;
+      SequencingKind = IndeterminatelySequenced;
       break;
-
     default:
       SequencingKind = NoSequencing;
       break;
     }
 
-    if (SequencingKind == NoSequencing)
-      return VisitCallExpr(CXXOCE);
+    if (SequencingKind == NoSequencing) {
+      SequenceTree::Seq Parent = Region;
+      SequenceTree::Seq CalleeRegion = Tree.allocate(Parent);
+      SequenceTree::Seq OtherRegion = Tree.allocate(Parent);
+
+      // Visit the callee expression first.
+      Region = CalleeRegion;
+      {
+        SequencedSubexpression Sequenced(*this);
+        Visit(CXXOCE->getCallee());
+      }
+
+      // Then visit the argument expressions.
+      Region = OtherRegion;
+      for (const Expr *Argument : CXXOCE->arguments())
+        Visit(Argument);
+
+      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 +16501,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 +16579,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,6 +688,7 @@
 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]>;
 
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