riccibruno updated this revision to Diff 188043.
riccibruno retitled this revision from "[Sema] SequenceChecker: Handle 
references and members" to "[Sema] SequenceChecker: Handle references, members 
and structured bindings.".
riccibruno edited the summary of this revision.

Repository:
  rC Clang

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

https://reviews.llvm.org/D57660

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaChecking.cpp
  test/SemaCXX/warn-unsequenced.cpp

Index: test/SemaCXX/warn-unsequenced.cpp
===================================================================
--- test/SemaCXX/warn-unsequenced.cpp
+++ test/SemaCXX/warn-unsequenced.cpp
@@ -160,17 +160,21 @@
   void member_f(S1 &s);
 };
 
+class SomeClass { public: static int x; };
+union SomeUnion { public: static int x; };
+
 void S1::member_f(S1 &s) {
-  ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-             // 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'}}
+  ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to member 'a'}}
+             // cxx17-warning@-1 {{multiple unsequenced modifications to member 'a'}}
+  a + ++a; // cxx11-warning {{unsequenced modification and access to member 'a'}}
+           // cxx17-warning@-1 {{unsequenced modification and access to member 'a'}}
   ++a + ++b; // no-warning
   a + ++b; // no-warning
 
-  // TODO: Warn here.
-  ++s.a + ++s.a; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.a + ++s.a; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.a + ++s.a; // cxx11-warning {{multiple unsequenced modifications to member 'a' of 's'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'a' of 's'}}
+  s.a + ++s.a; // cxx11-warning {{unsequenced modification and access to member 'a' of 's'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'a' of 's'}}
   ++s.a + ++s.b; // no-warning
   s.a + ++s.b; // no-warning
 
@@ -180,16 +184,18 @@
   a + ++s.b; // no-warning
 
   // 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'}}
-  bf1 + ++bf1; // cxx11-warning {{unsequenced modification and access to 'bf1'}}
-               // cxx17-warning@-1 {{unsequenced modification and access to 'bf1'}}
+  ++bf1 + ++bf1; // cxx11-warning {{multiple unsequenced modifications to member 'bf1'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'bf1'}}
+  bf1 + ++bf1; // cxx11-warning {{unsequenced modification and access to member 'bf1'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'bf1'}}
   ++bf1 + ++bf2; // no-warning TODO {{multiple unsequenced modifications to}}
   bf1 + ++bf2; // no-warning TODO {{unsequenced modification and access to}}
 
   // TODO Warn here for bit-fields in the same memory location.
-  ++s.bf1 + ++s.bf1; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.bf1 + ++s.bf1; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.bf1 + ++s.bf1; // cxx11-warning {{multiple unsequenced modifications to member 'bf1' of 's'}}
+                     // cxx17-warning@-1 {{multiple unsequenced modifications to member 'bf1' of 's'}}
+  s.bf1 + ++s.bf1; // cxx11-warning {{unsequenced modification and access to member 'bf1' of 's'}}
+                   // cxx17-warning@-1 {{unsequenced modification and access to member 'bf1' of 's'}}
   ++s.bf1 + ++s.bf2; // no-warning TODO {{multiple unsequenced modifications to}}
   s.bf1 + ++s.bf2; // no-warning TODO {{unsequenced modification and access to}}
 
@@ -203,19 +209,29 @@
   Der &d_ref = d;
   S1 &s1_ref = d_ref;
 
-  ++s1_ref.a + ++d_ref.a; // no-warning TODO {{multiple unsequenced modifications to member 'a' of 'd'}}
-  ++s1_ref.a + d_ref.a; // no-warning TODO {{unsequenced modification and access to member 'a' of 'd'}}
+  ++s1_ref.a + ++d_ref.a; // cxx11-warning {{multiple unsequenced modifications to member 'a' of 'd'}}
+                          // cxx17-warning@-1 {{multiple unsequenced modifications to member 'a' of 'd'}}
+  ++s1_ref.a + d_ref.a; // cxx11-warning {{unsequenced modification and access to member 'a' of 'd'}}
+                        // cxx17-warning@-1 {{unsequenced modification and access to member 'a' of 'd'}}
   ++s1_ref.a + ++d_ref.b; // no-warning
   ++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'}}
-  ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-           // 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'}}
-  ++d_ref.x + ++S1::x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
+  ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to static member 'x' of struct 'S1'}}
+             // cxx17-warning@-1 {{multiple unsequenced modifications to static member 'x' of struct 'S1'}}
+  ++x + x; // cxx11-warning {{unsequenced modification and access to static member 'x' of struct 'S1'}}
+           // cxx17-warning@-1 {{unsequenced modification and access to static member 'x' of struct 'S1'}}
+  ++s.x + x; // cxx11-warning {{unsequenced modification and access to static member 'x' of struct 'S1'}}
+             // cxx17-warning@-1 {{unsequenced modification and access to static member 'x' of struct 'S1'}}
+  ++this->x + x; // cxx11-warning {{unsequenced modification and access to static member 'x' of struct 'S1'}}
+                 // cxx17-warning@-1 {{unsequenced modification and access to static member 'x' of struct 'S1'}}
+  ++d_ref.x + S1::x; // cxx11-warning {{unsequenced modification and access to static member 'x' of struct 'S1'}}
+                     // cxx17-warning@-1 {{unsequenced modification and access to static member 'x' of struct 'S1'}}
+
+  SomeClass::x++ + SomeClass::x; // cxx11-warning {{unsequenced modification and access to static member 'x' of class 'SomeClass'}}
+                                 // cxx17-warning@-1 {{unsequenced modification and access to static member 'x' of class 'SomeClass'}}
+  SomeUnion::x++ + SomeUnion::x; // cxx11-warning {{unsequenced modification and access to static member 'x' of union 'SomeUnion'}}
+                                 // cxx17-warning@-1 {{unsequenced modification and access to static member 'x' of union 'SomeUnion'}}
+  SomeClass::x++ + SomeUnion::x++; // no-warning
 }
 
 struct S2 {
@@ -224,15 +240,19 @@
 };
 
 void S2::f2() {
-  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
-  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
+  ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to member 'x'}}
+             // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x'}}
+  x + ++x; // cxx11-warning {{unsequenced modification and access to member 'x'}}
+           // cxx17-warning@-1 {{unsequenced modification and access to member 'x'}}
   ++x + ++y; // no-warning
   x + ++y; // no-warning
 }
 
 void f2(S2 &s) {
-  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.x + ++s.x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 's'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 's'}}
+  s.x + ++s.x; // cxx11-warning {{unsequenced modification and access to member 'x' of 's'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 's'}}
   ++s.x + ++s.y; // no-warning
   s.x + ++s.y; // no-warning
 }
@@ -248,15 +268,19 @@
 };
 
 void S3::f3() {
-  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
-  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
+  ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to member 'x'}}
+             // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x'}}
+  x + ++x; // cxx11-warning {{unsequenced modification and access to member 'x'}}
+           // cxx17-warning@-1 {{unsequenced modification and access to member 'x'}}
   ++x + ++y; // no-warning
   x + ++y; // no-warning
 }
 
 void f3(S3 &s) {
-  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.x + ++s.x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 's'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 's'}}
+  s.x + ++s.x; // cxx11-warning {{unsequenced modification and access to member 'x' of 's'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 's'}}
   ++s.x + ++s.y; // no-warning
   s.x + ++s.y; // no-warning
 }
@@ -267,8 +291,10 @@
 };
 
 void S4::f4() {
-  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
-  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
+  ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to member 'x'}}
+             // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x'}}
+  x + ++x; // cxx11-warning {{unsequenced modification and access to member 'x'}}
+           // cxx17-warning@-1 {{unsequenced modification and access to member 'x'}}
   ++x + ++y; // no-warning
   x + ++y; // no-warning
   ++S3::y + ++y; // no-warning
@@ -276,8 +302,10 @@
 }
 
 void f4(S4 &s) {
-  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.x + ++s.x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 's'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 's'}}
+  s.x + ++s.x; // cxx11-warning {{unsequenced modification and access to member 'x' of 's'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 's'}}
   ++s.x + ++s.y; // no-warning
   s.x + ++s.y; // no-warning
   ++s.S3::y + ++s.y; // no-warning
@@ -290,22 +318,28 @@
 };
 
 void f5() {
-  ++Ux + ++Ux; // no-warning TODO {{multiple unsequenced modifications to}}
-  Ux + ++Ux; // no-warning TODO {{unsequenced modification and access to}}
+  ++Ux + ++Ux; // cxx11-warning {{multiple unsequenced modifications to member 'Ux' of ''}}
+               // cxx17-warning@-1 {{multiple unsequenced modifications to member 'Ux' of ''}}
+  Ux + ++Ux; // cxx11-warning {{unsequenced modification and access to member 'Ux' of ''}}
+             // cxx17-warning@-1 {{unsequenced modification and access to member 'Ux' of ''}}
   ++Ux + ++Uy; // no-warning
   Ux + ++Uy; // no-warning
 }
 
 void f6() {
   struct S { unsigned x, y; } s;
-  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.x + ++s.x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 's'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 's'}}
+  s.x + ++s.x; // cxx11-warning {{unsequenced modification and access to member 'x' of 's'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 's'}}
   ++s.x + ++s.y; // no-warning
   s.x + ++s.y; // no-warning
 
   struct { unsigned x, y; } t;
-  ++t.x + ++t.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  t.x + ++t.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++t.x + ++t.x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 't'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 't'}}
+  t.x + ++t.x; // cxx11-warning {{unsequenced modification and access to member 'x' of 't'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 't'}}
   ++t.x + ++t.y; // no-warning
   t.x + ++t.y; // no-warning
 }
@@ -314,18 +348,18 @@
 
 namespace references {
 void reference_f() {
-  // TODO: Check that we can see through references.
-  // For now this is completely unhandled.
+  // Check that we can see through references.
   int a;
-  int xs[10];
   int &b = a;
   int &c = b;
   int &ra1 = c;
   int &ra2 = b;
   int other;
 
-  ++ra1 + ++ra2; // no-warning TODO {{multiple unsequenced modifications to}}
-  ra1 + ++ra2; // no-warning TODO {{unsequenced modification and access to}}
+  ++ra1 + ++ra2; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to 'a'}}
+  ra1 + ++ra2; // cxx11-warning {{unsequenced modification and access to 'a'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
   ++ra1 + ++other; // no-warning
   ra1 + ++other; // no-warning
 
@@ -357,10 +391,10 @@
   A a;
   {
     auto [x, y] = a;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // 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'}}
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of structured binding '[x, y]'}}
+               // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of structured binding '[x, y]'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to member 'x' of structured binding '[x, y]'}}
+             // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of structured binding '[x, y]'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
     ++x + ++a.x; // no-warning
@@ -368,16 +402,19 @@
   }
   {
     auto &[x, y] = a;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // 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'}}
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 'a'}}
+               // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 'a'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to member 'x' of 'a'}}
+             // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 'a'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
-    ++x + ++a.x; // no-warning TODO
-    ++x + a.x; // no-warning TODO
+    ++x + ++a.x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 'a'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 'a'}}
+    ++x + a.x; // cxx11-warning {{unsequenced modification and access to member 'x' of 'a'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 'a'}}
   }
 }
+
 void testb() {
   B b;
   {
@@ -399,6 +436,8 @@
              // cxx17-warning@-1 {{unsequenced modification and access to 'x'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
+    // TODO: We don't handle these cases because we don't track memory locations
+    // through array subscript expressions for now.
     ++x + ++b[0]; // no-warning TODO
     ++x + b[0]; // no-warning TODO
   }
@@ -428,10 +467,10 @@
   D d;
   {
     auto [x, y] = d;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // 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'}}
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of structured binding '[x, y]'}}
+               // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of structured binding '[x, y]'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to member 'x' of structured binding '[x, y]'}}
+             // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of structured binding '[x, y]'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
     ++x + ++d.x; // no-warning
@@ -439,14 +478,16 @@
   }
   {
     auto &[x, y] = d;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // 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'}}
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 'd'}}
+               // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 'd'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to member 'x' of 'd'}}
+             // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 'd'}}
     ++x + ++y; // no-warning
     ++x + y; // no-warning
-    ++x + ++d.x; // no-warning TODO
-    ++x + d.x; // no-warning TODO
+    ++x + ++d.x; // cxx11-warning {{multiple unsequenced modifications to member 'x' of 'd'}}
+                 // cxx17-warning@-1 {{multiple unsequenced modifications to member 'x' of 'd'}}
+    ++x + d.x; // cxx11-warning {{unsequenced modification and access to member 'x' of 'd'}}
+               // cxx17-warning@-1 {{unsequenced modification and access to member 'x' of 'd'}}
   }
 }
 } // namespace bindings
@@ -516,7 +557,8 @@
   var<int>++ + var<int>; // cxx11-warning {{unsequenced modification and access to 'var<int>'}}
                          // 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<int>++; // cxx11-warning {{multiple unsequenced modifications to 'var<int>'}}
+                    // cxx17-warning@-1 {{multiple unsequenced modifications to 'var<int>'}}
   r++ + var<long>++; // no-warning
 }
 
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -11644,10 +11644,87 @@
 
 namespace {
 
+/// An approximation of a C++ memory location used by SequenceChecker.
+/// TODO: Handle bit-fields.
+/// TODO: Give better info with references.
+class MemoryLocation {
+  friend struct llvm::DenseMapInfo<MemoryLocation>;
+  /// An object. As a special case this represent the C++ implicit object
+  /// if the ValueDecl * is null and the flag is true.
+  llvm::PointerIntPair<const ValueDecl *, 1> ObjectOrCXXThis;
+  /// If non-null, a field in a record type.
+  const ValueDecl *Field = nullptr;
+
+public:
+  struct CXXThisTag {};
+  MemoryLocation() = default;
+  MemoryLocation(const ValueDecl *Object, const ValueDecl *Field)
+      : ObjectOrCXXThis(Object, /*IsCXXThis=*/false), Field(Field) {}
+  MemoryLocation(CXXThisTag, const ValueDecl *Field)
+      : ObjectOrCXXThis(nullptr, /*IsCXXThis=*/true), Field(Field) {}
+  MemoryLocation(void *OpaqueObject, const ValueDecl *Field) : Field(Field) {
+    ObjectOrCXXThis.setFromOpaqueValue(OpaqueObject);
+  }
+
+  explicit operator bool() const { return getObject() || isCXXThis(); }
+  const ValueDecl *getObject() const { return ObjectOrCXXThis.getPointer(); }
+  bool isCXXThis() const { return ObjectOrCXXThis.getInt(); }
+  const ValueDecl *getField() const { return Field; }
+  void *getOpaqueObject() const { return ObjectOrCXXThis.getOpaqueValue(); }
+
+  friend bool operator==(const MemoryLocation &MemoryLoc1,
+                         const MemoryLocation &MemoryLoc2) {
+    return !(MemoryLoc1 != MemoryLoc2);
+  }
+  friend bool operator!=(const MemoryLocation &MemoryLoc1,
+                         const MemoryLocation &MemoryLoc2) {
+    return (MemoryLoc1.ObjectOrCXXThis != MemoryLoc2.ObjectOrCXXThis) ||
+           (MemoryLoc1.Field != MemoryLoc2.Field);
+  }
+}; // class MemoryLocation
+
+} // namespace
+
+namespace llvm {
+
+template <> struct llvm::DenseMapInfo<MemoryLocation> {
+  using FirstTy = llvm::PointerIntPair<const ValueDecl *, 1>;
+  using SecondTy = const ValueDecl *;
+  using FirstInfo = llvm::DenseMapInfo<FirstTy>;
+  using SecondInfo = llvm::DenseMapInfo<SecondTy>;
+
+  static MemoryLocation getEmptyKey() {
+    return MemoryLocation(FirstInfo::getEmptyKey().getOpaqueValue(),
+                          SecondInfo::getEmptyKey());
+  }
+
+  static MemoryLocation getTombstoneKey() {
+    return MemoryLocation(FirstInfo::getTombstoneKey().getOpaqueValue(),
+                          SecondInfo::getTombstoneKey());
+  }
+
+  static unsigned getHashValue(const MemoryLocation &MemoryLoc) {
+    unsigned H1 = FirstInfo::getHashValue(MemoryLoc.ObjectOrCXXThis);
+    unsigned H2 = SecondInfo::getHashValue(MemoryLoc.Field);
+    // Taken from Boost hash_combine. llvm::DenseMapInfo<std::pair>
+    // is significantly slower.
+    return H2 ^ (H1 + 0x9e3779b9 + (H2 << 6) + (H2 >> 2));
+  }
+
+  static bool isEqual(const MemoryLocation &MemoryLoc1,
+                      const MemoryLocation &MemoryLoc2) {
+    return MemoryLoc1 == MemoryLoc2;
+  }
+};
+
+} // namespace llvm
+
+namespace {
+
 /// Visitor for expressions which looks for unsequenced operations on the
-/// same object.
-class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
-  using Base = EvaluatedExprVisitor<SequenceChecker>;
+/// same memory location.
+class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
+  using Base = ConstEvaluatedExprVisitor<SequenceChecker>;
 
   /// A tree of sequenced regions within an expression. Two regions are
   /// unsequenced if one is an ancestor or a descendent of the other. When we
@@ -11716,21 +11793,18 @@
     }
   };
 
-  /// An object for which we can track unsequenced uses.
-  using Object = NamedDecl *;
-
-  /// Different flavors of object usage which we track. We only track the
-  /// least-sequenced usage of each kind.
+  /// Different flavors of memory location usage which we track. We only
+  /// track the least-sequenced usage of each kind.
   enum UsageKind {
-    /// A read of an object. Multiple unsequenced reads are OK.
+    /// A read of a memory location. Multiple unsequenced reads are OK.
     UK_Use,
 
-    /// A modification of an object which is sequenced before the value
+    /// A modification of a memory location which is sequenced before the value
     /// computation of the expression, such as ++n in C++.
     UK_ModAsValue,
 
-    /// A modification of an object which is not sequenced before the value
-    /// computation of the expression, such as n++.
+    /// A modification of an memory location which is not sequenced before the
+    /// value computation of the expression, such as n++.
     UK_ModAsSideEffect,
 
     UK_Count = UK_ModAsSideEffect + 1
@@ -11739,21 +11813,21 @@
   /// Bundle together a sequencing region and the expression corresponding
   /// to a specific usage. One Usage is stored for each usage kind in UsageInfo.
   struct Usage {
-    Expr *UsageExpr = nullptr;
+    const Expr *UsageExpr = nullptr;
     SequenceTree::Seq Seq;
     Usage() = default;
-    Usage(Expr *UsageExpr, SequenceTree::Seq Seq)
+    Usage(const Expr *UsageExpr, SequenceTree::Seq Seq)
         : UsageExpr(UsageExpr), Seq(Seq) {}
   };
 
   class UsageInfo {
     /// The expressions corresponding to each usage kind.
-    Expr *UsageExprs[UK_Count]{};
+    const Expr *UsageExprs[UK_Count]{};
 
     /// The sequencing regions corresponding to each usage kind.
     SequenceTree::Seq Seqs[UK_Count]{};
 
-    /// Have we issued a diagnostic for this object already?
+    /// Have we issued a diagnostic for this memory location already?
     bool Diagnosed = false;
 
   public:
@@ -11769,7 +11843,7 @@
     void markDiagnosed() { Diagnosed = true; }
     bool alreadyDiagnosed() const { return Diagnosed; }
   };
-  using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>;
+  using UsageInfoMap = llvm::SmallDenseMap<MemoryLocation, UsageInfo, 16>;
 
   Sema &SemaRef;
 
@@ -11784,11 +11858,11 @@
 
   /// Filled in with declarations which were modified as a side-effect
   /// (that is, post-increment operations).
-  SmallVectorImpl<std::pair<Object, Usage>> *ModAsSideEffect = nullptr;
+  SmallVectorImpl<std::pair<MemoryLocation, Usage>> *ModAsSideEffect = nullptr;
 
   /// Expressions to check later. We defer checking these to reduce
   /// stack usage.
-  SmallVectorImpl<Expr *> &WorkList;
+  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
@@ -11802,7 +11876,8 @@
     }
 
     ~SequencedSubexpression() {
-      for (std::pair<Object, Usage> &M : llvm::reverse(ModAsSideEffect)) {
+      for (std::pair<MemoryLocation, Usage> &M :
+           llvm::reverse(ModAsSideEffect)) {
         // Add a new usage with usage kind UK_ModAsValue, and then restore
         // the previous usage with UK_ModAsSideEffect (thus clearing it if
         // the previous one was empty).
@@ -11815,8 +11890,8 @@
     }
 
     SequenceChecker &Self;
-    SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
-    SmallVectorImpl<std::pair<Object, Usage>> *OldModAsSideEffect;
+    SmallVector<std::pair<MemoryLocation, Usage>, 4> ModAsSideEffect;
+    SmallVectorImpl<std::pair<MemoryLocation, Usage>> *OldModAsSideEffect;
   };
 
   /// RAII object wrapping the visitation of a subexpression which we might
@@ -11849,48 +11924,120 @@
     bool EvalOK = true;
   } *EvalTracker = nullptr;
 
-  /// Find the object which is produced by the specified expression,
+  /// Find the memory location which is produced by the specified expression,
   /// if any.
-  Object getObject(Expr *E, bool Mod) const {
+  static MemoryLocation getMemoryLocation(const Expr *E, bool Mod) {
+    return getMemoryLocationImpl(E, Mod, /*RefsSeenPtr=*/nullptr);
+  }
+
+  /// Implementation of getMemoryLocation().
+  /// \param RefsSeenPtr is used to avoid reference cycles. When such a cycle
+  /// is possible we check first if \param RefsSeenPtr is non-null. If it is
+  /// non-null we use the pointed SmallPtrSet and if null we create one on the
+  /// stack. This allow us to avoid creating the SmallPtrSet when we don't
+  /// strictly have to.
+  static MemoryLocation
+  getMemoryLocationImpl(const Expr *E, bool Mod,
+                        llvm::SmallPtrSetImpl<const VarDecl *> *RefsSeenPtr) {
     E = E->IgnoreParenCasts();
-    if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+    if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
       if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec))
-        return getObject(UO->getSubExpr(), Mod);
-    } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+        return getMemoryLocationImpl(UO->getSubExpr(), Mod, RefsSeenPtr);
+    }
+
+    else if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
       if (BO->getOpcode() == BO_Comma)
-        return getObject(BO->getRHS(), Mod);
+        return getMemoryLocationImpl(BO->getRHS(), Mod, RefsSeenPtr);
       if (Mod && BO->isAssignmentOp())
-        return getObject(BO->getLHS(), Mod);
-    } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
-      // FIXME: Check for more interesting cases, like "x.n = ++x.n".
-      if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts()))
-        return ME->getMemberDecl();
-    } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
-      // FIXME: If this is a reference, map through to its value.
-      return DRE->getDecl();
-    return nullptr;
-  }
+        return getMemoryLocationImpl(BO->getLHS(), Mod, RefsSeenPtr);
+    }
 
-  /// Note that an object was modified or used by an expression.
-  /// UI is the UsageInfo for the object O as obtained via the UsageMap.
-  void addUsage(Object O, UsageInfo &UI, Expr *UsageExpr, UsageKind UK) {
-    // Get the old usage for the given object and usage kind.
+    else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
+      if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+        return MemoryLocation(
+            /*Base=*/getMemoryLocationImpl(ME->getBase(), Mod, RefsSeenPtr)
+                .getOpaqueObject(),
+            /*Field=*/FD);
+
+      if (const auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
+        if (!RefsSeenPtr) {
+          llvm::SmallPtrSet<const VarDecl *, 1> RefsSeen;
+          return maybeLookThroughRefs(VD, Mod, RefsSeen);
+        } else {
+          return maybeLookThroughRefs(VD, Mod, *RefsSeenPtr);
+        }
+      }
+    }
+
+    else if (const auto *CXXTE = dyn_cast<CXXThisExpr>(E)) {
+      return MemoryLocation(MemoryLocation::CXXThisTag(), /*Field=*/nullptr);
+    }
+
+    else if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+      const ValueDecl *ReferencedDecl = DRE->getDecl();
+      if (const auto *VD = dyn_cast<VarDecl>(ReferencedDecl)) {
+        if (!RefsSeenPtr) {
+          llvm::SmallPtrSet<const VarDecl *, 1> RefsSeen;
+          return maybeLookThroughRefs(VD, Mod, RefsSeen);
+        } else {
+          return maybeLookThroughRefs(VD, Mod, *RefsSeenPtr);
+        }
+      }
+
+      if (const auto *BD = dyn_cast<BindingDecl>(ReferencedDecl)) {
+        MemoryLocation MemoryLoc =
+            getMemoryLocationImpl(BD->getBinding(), Mod, RefsSeenPtr);
+        // If we found a memory location, return it. Otherwise pretend that the
+        // binding is the memory location since this is better than not finding
+        // anything.
+        return MemoryLoc ? MemoryLoc : MemoryLocation(BD, /*Field=*/nullptr);
+      }
+    }
+    return MemoryLocation();
+  }
+
+  static MemoryLocation
+  maybeLookThroughRefs(const VarDecl *VD, bool Mod,
+                       llvm::SmallPtrSetImpl<const VarDecl *> &RefsSeen) {
+    MemoryLocation MemoryLoc;
+    // If this is a reference, look through it.
+    if (VD->getType()->isReferenceType() && VD->hasInit()) {
+      // But only if we don't have a cycle.
+      bool Inserted = RefsSeen.insert(VD).second;
+      if (Inserted)
+        MemoryLoc = getMemoryLocationImpl(VD->getInit(), Mod, &RefsSeen);
+    }
+    // If we found a memory location, return it. Otherwise pretend that the
+    // given VarDecl is the memory location since this is better than not
+    // finding anything.
+    return MemoryLoc ? MemoryLoc : MemoryLocation(VD, /*Field=*/nullptr);
+  }
+
+  /// Note that a memory location was modified or used by an expression.
+  /// UI is the UsageInfo for the memory location MemoryLoc as obtained
+  /// via the UsageMap.
+  void addUsage(MemoryLocation MemoryLoc, UsageInfo &UI, const Expr *UsageExpr,
+                UsageKind UK) {
+    assert(MemoryLoc && "addUsage requires a valid MemoryLocation!");
+    // Get the old usage for the given memory location and usage kind.
     Usage U = UI.getUsage(UK);
     if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) {
       // 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.
       if (UK == UK_ModAsSideEffect && ModAsSideEffect)
-        ModAsSideEffect->push_back(std::make_pair(O, U));
+        ModAsSideEffect->push_back(std::make_pair(MemoryLoc, U));
       // Then record the new usage with the current sequencing region.
       UI.setUsage(UK, Usage(UsageExpr, Region));
     }
   }
 
   /// Check whether a modification or use conflicts with a prior usage.
-  /// UI is the UsageInfo for the object O as obtained via the UsageMap.
-  void checkUsage(Object O, UsageInfo &UI, Expr *UsageExpr, UsageKind OtherKind,
-                  bool IsModMod) {
+  /// UI is the UsageInfo for the memory location MemoryLoc as obtained
+  /// via the UsageMap.
+  void checkUsage(MemoryLocation MemoryLoc, UsageInfo &UI,
+                  const Expr *UsageExpr, UsageKind OtherKind, bool IsModMod) {
+    assert(MemoryLoc && "checkUsage requires a valid MemoryLocation!");
     if (UI.alreadyDiagnosed())
       return;
 
@@ -11898,15 +12045,68 @@
     if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq))
       return;
 
-    Expr *Mod = U.UsageExpr;
-    Expr *ModOrUse = UsageExpr;
+    const Expr *Mod = U.UsageExpr;
+    const Expr *ModOrUse = UsageExpr;
     if (OtherKind == UK_Use)
       std::swap(Mod, ModOrUse);
 
-    SemaRef.Diag(Mod->getExprLoc(),
-                 IsModMod ? diag::warn_unsequenced_mod_mod
-                          : diag::warn_unsequenced_mod_use)
-      << O << SourceRange(ModOrUse->getExprLoc());
+    enum MemberDiagKind { MDK_NotMember, MDK_Member, MDK_StaticMember };
+    enum OfDiagKind {
+      ODK_NoOf,
+      ODK_Of,
+      ODK_OfStruct,
+      ODK_OfUnion,
+      ODK_OfClass,
+      ODK_OfStructuredBinding
+    };
+    const ValueDecl *Object = MemoryLoc.getObject();
+    const ValueDecl *Field = MemoryLoc.getField();
+    const TagDecl *TD = nullptr;
+
+    MemberDiagKind MemberDiag =
+        (Field != nullptr) ? MDK_Member
+                           : (Object && isa<VarDecl>(Object) &&
+                              cast<VarDecl>(Object)->isStaticDataMember())
+                                 ? MDK_StaticMember
+                                 : MDK_NotMember;
+    OfDiagKind OfDiag = ODK_NoOf;
+    if (MemberDiag == MDK_Member) {
+      if (Object) {
+        if (isa<DecompositionDecl>(Object))
+          OfDiag = ODK_OfStructuredBinding;
+        else
+          OfDiag = ODK_Of;
+      }
+    } else if (MemberDiag == MDK_StaticMember) {
+      TD = dyn_cast<TagDecl>(cast<VarDecl>(Object)->getDeclContext());
+      if (TD) {
+        switch (TD->getTagKind()) {
+        case TTK_Struct:
+          OfDiag = ODK_OfStruct;
+          break;
+        case TTK_Class:
+          OfDiag = ODK_OfClass;
+          break;
+        case TTK_Union:
+          OfDiag = ODK_OfUnion;
+          break;
+        default:
+          break;
+        }
+      }
+    }
+
+    const ValueDecl *FirstDiagElement =
+        MemberDiag == MDK_Member ? Field : Object;
+    const ValueDecl *SecondDiagElement =
+        MemberDiag == MDK_Member ? Object : nullptr;
+
+    SemaRef.Diag(Mod->getExprLoc(), IsModMod ? diag::warn_unsequenced_mod_mod
+                                             : diag::warn_unsequenced_mod_use)
+        << static_cast<unsigned>(MemberDiag) << static_cast<unsigned>(OfDiag)
+        << FirstDiagElement << SecondDiagElement << TD
+        << SourceRange(ModOrUse->getExprLoc());
+
     UI.markDiagnosed();
   }
 
@@ -11916,11 +12116,12 @@
   //  "((++k)++, k) = k" or "k = (k++, k++)". Both contain unsequenced
   //  operations before C++17 and both are well-defined in C++17).
   //
-  // When visiting a node which uses/modify an object we first call notePreUse
-  // or notePreMod before visiting its sub-expression(s). At this point the
-  // children of the current node have not yet been visited and so the eventual
-  // uses/modifications resulting from the children of the current node have not
-  // been recorded yet.
+  // When visiting a node which uses/modify a memory location we first call
+  // notePreUse or notePreMod before visiting its sub-expression(s). At this
+  // point the children of the current node have not yet been visited and so
+  // the eventual uses/modifications resulting from the children of the current
+  // node have not been recorded yet. They will therefore not be wrongly
+  // detected by the call(s) to checkUsage.
   //
   // We then visit the children of the current node. After that notePostUse or
   // notePostMod is called. These will 1) detect an unsequenced modification
@@ -11936,61 +12137,71 @@
   // modification as side effect) when exiting the scope of the sequenced
   // subexpression.
 
-  void notePreUse(Object O, Expr *UseExpr) {
-    UsageInfo &UI = UsageMap[O];
+  void notePreUse(MemoryLocation MemoryLoc, const Expr *UseExpr) {
+    assert(MemoryLoc && "notePreUse requires a valid memory location!");
+    UsageInfo &UI = UsageMap[MemoryLoc];
     // Uses conflict with other modifications.
-    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/false);
+    checkUsage(MemoryLoc, UI, UseExpr, /*OtherKind=*/UK_ModAsValue,
+               /*IsModMod=*/false);
   }
 
-  void notePostUse(Object O, Expr *UseExpr) {
-    UsageInfo &UI = UsageMap[O];
-    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect,
+  void notePostUse(MemoryLocation MemoryLoc, const Expr *UseExpr) {
+    assert(MemoryLoc && "notePostUse requires a valid memory location!");
+    UsageInfo &UI = UsageMap[MemoryLoc];
+    checkUsage(MemoryLoc, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect,
                /*IsModMod=*/false);
-    addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use);
+    addUsage(MemoryLoc, UI, UseExpr, /*UsageKind=*/UK_Use);
   }
 
-  void notePreMod(Object O, Expr *ModExpr) {
-    UsageInfo &UI = UsageMap[O];
+  void notePreMod(MemoryLocation MemoryLoc, const Expr *ModExpr) {
+    assert(MemoryLoc && "notePreMod requires a valid memory location!");
+    UsageInfo &UI = UsageMap[MemoryLoc];
     // Modifications conflict with other modifications and with uses.
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/true);
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, /*IsModMod=*/false);
+    checkUsage(MemoryLoc, UI, ModExpr, /*OtherKind=*/UK_ModAsValue,
+               /*IsModMod=*/true);
+    checkUsage(MemoryLoc, UI, ModExpr, /*OtherKind=*/UK_Use,
+               /*IsModMod=*/false);
   }
 
-  void notePostMod(Object O, Expr *ModExpr, UsageKind UK) {
-    UsageInfo &UI = UsageMap[O];
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect,
+  void notePostMod(MemoryLocation MemoryLoc, const Expr *ModExpr,
+                   UsageKind UK) {
+    assert(MemoryLoc && "notePostMod requires a valid memory location!");
+    UsageInfo &UI = UsageMap[MemoryLoc];
+    checkUsage(MemoryLoc, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect,
                /*IsModMod=*/true);
-    addUsage(O, UI, ModExpr, /*UsageKind=*/UK);
+    addUsage(MemoryLoc, UI, ModExpr, /*UsageKind=*/UK);
   }
 
 public:
-  SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList)
+  SequenceChecker(Sema &S, const Expr *E,
+                  SmallVectorImpl<const Expr *> &WorkList)
       : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) {
     Visit(E);
   }
 
-  void VisitStmt(Stmt *S) {
+  void VisitStmt(const Stmt *S) {
     // Skip all statements which aren't expressions for now.
   }
 
-  void VisitExpr(Expr *E) {
+  void VisitExpr(const Expr *E) {
     // By default, just recurse to evaluated subexpressions.
     Base::VisitStmt(E);
   }
 
-  void VisitCastExpr(CastExpr *E) {
-    Object O = Object();
+  void VisitCastExpr(const CastExpr *E) {
+    MemoryLocation MemoryLoc;
     if (E->getCastKind() == CK_LValueToRValue)
-      O = getObject(E->getSubExpr(), false);
+      MemoryLoc = getMemoryLocation(E->getSubExpr(), /*Mod=*/false);
 
-    if (O)
-      notePreUse(O, E);
+    if (MemoryLoc)
+      notePreUse(MemoryLoc, E);
     VisitExpr(E);
-    if (O)
-      notePostUse(O, E);
+    if (MemoryLoc)
+      notePostUse(MemoryLoc, E);
   }
 
-  void VisitSequencedExpressions(Expr *SequencedBefore, Expr *SequencedAfter) {
+  void VisitSequencedExpressions(const Expr *SequencedBefore,
+                                 const Expr *SequencedAfter) {
     SequenceTree::Seq BeforeRegion = Tree.allocate(Region);
     SequenceTree::Seq AfterRegion = Tree.allocate(Region);
     SequenceTree::Seq OldRegion = Region;
@@ -12010,7 +12221,7 @@
     Tree.merge(AfterRegion);
   }
 
-  void VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) {
+  void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
     // C++17 [expr.sub]p1:
     //   The expression E1[E2] is identical (by definition) to *((E1)+(E2)). The
     //   expression E1 is sequenced before the expression E2.
@@ -12020,7 +12231,7 @@
       Base::VisitStmt(ASE);
   }
 
-  void VisitBinComma(BinaryOperator *BO) {
+  void VisitBinComma(const BinaryOperator *BO) {
     // C++11 [expr.comma]p1:
     //   Every value computation and side effect associated with the left
     //   expression is sequenced before every value computation and side
@@ -12028,15 +12239,15 @@
     VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
   }
 
-  void VisitBinAssign(BinaryOperator *BO) {
+  void VisitBinAssign(const BinaryOperator *BO) {
     // The modification is sequenced after the value computation of the LHS
     // and RHS, so check it before inspecting the operands and update the
     // map afterwards.
-    Object O = getObject(BO->getLHS(), true);
-    if (!O)
+    MemoryLocation MemoryLoc = getMemoryLocation(BO->getLHS(), /*Mod=*/true);
+    if (!MemoryLoc)
       return VisitExpr(BO);
 
-    notePreMod(O, BO);
+    notePreMod(MemoryLoc, BO);
 
     // C++11 [expr.ass]p7:
     //   E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated
@@ -12045,12 +12256,12 @@
     // Therefore, for a compound assignment operator, O is considered used
     // everywhere except within the evaluation of E1 itself.
     if (isa<CompoundAssignOperator>(BO))
-      notePreUse(O, BO);
+      notePreUse(MemoryLoc, BO);
 
     Visit(BO->getLHS());
 
     if (isa<CompoundAssignOperator>(BO))
-      notePostUse(O, BO);
+      notePostUse(MemoryLoc, BO);
 
     Visit(BO->getRHS());
 
@@ -12058,43 +12269,47 @@
     //   the assignment is sequenced [...] before the value computation of the
     //   assignment expression.
     // C11 6.5.16/3 has no such rule.
-    notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
-                                                       : UK_ModAsSideEffect);
+    notePostMod(MemoryLoc, BO,
+                SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+                                                : UK_ModAsSideEffect);
   }
 
-  void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) {
+  void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) {
     VisitBinAssign(CAO);
   }
 
-  void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
-  void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
-  void VisitUnaryPreIncDec(UnaryOperator *UO) {
-    Object O = getObject(UO->getSubExpr(), true);
-    if (!O)
+  void VisitUnaryPreInc(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+  void VisitUnaryPreDec(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+  void VisitUnaryPreIncDec(const UnaryOperator *UO) {
+    MemoryLocation MemoryLoc =
+        getMemoryLocation(UO->getSubExpr(), /*Mod=*/true);
+    if (!MemoryLoc)
       return VisitExpr(UO);
 
-    notePreMod(O, UO);
+    notePreMod(MemoryLoc, UO);
     Visit(UO->getSubExpr());
     // C++11 [expr.pre.incr]p1:
     //   the expression ++x is equivalent to x+=1
-    notePostMod(O, UO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
-                                                       : UK_ModAsSideEffect);
+    notePostMod(MemoryLoc, UO,
+                SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+                                                : UK_ModAsSideEffect);
   }
 
-  void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
-  void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
-  void VisitUnaryPostIncDec(UnaryOperator *UO) {
-    Object O = getObject(UO->getSubExpr(), true);
-    if (!O)
+  void VisitUnaryPostInc(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+  void VisitUnaryPostDec(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+  void VisitUnaryPostIncDec(const UnaryOperator *UO) {
+    MemoryLocation MemoryLoc =
+        getMemoryLocation(UO->getSubExpr(), /*Mod=*/true);
+    if (!MemoryLoc)
       return VisitExpr(UO);
 
-    notePreMod(O, UO);
+    notePreMod(MemoryLoc, UO);
     Visit(UO->getSubExpr());
-    notePostMod(O, UO, UK_ModAsSideEffect);
+    notePostMod(MemoryLoc, UO, UK_ModAsSideEffect);
   }
 
   /// Don't visit the RHS of '&&' or '||' if it might not be evaluated.
-  void VisitBinLOr(BinaryOperator *BO) {
+  void VisitBinLOr(const BinaryOperator *BO) {
     // The side-effects of the LHS of an '&&' are sequenced before the
     // value computation of the RHS, and hence before the value computation
     // of the '&&' itself, unless the LHS evaluates to zero. We treat them
@@ -12119,7 +12334,7 @@
       WorkList.push_back(BO->getRHS());
     }
   }
-  void VisitBinLAnd(BinaryOperator *BO) {
+  void VisitBinLAnd(const BinaryOperator *BO) {
     EvaluationTracker Eval(*this);
     {
       SequencedSubexpression Sequenced(*this);
@@ -12137,7 +12352,7 @@
 
   // Only visit the condition, unless we can be sure which subexpression will
   // be chosen.
-  void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) {
+  void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) {
     EvaluationTracker Eval(*this);
     {
       SequencedSubexpression Sequenced(*this);
@@ -12153,7 +12368,7 @@
     }
   }
 
-  void VisitCallExpr(CallExpr *CE) {
+  void VisitCallExpr(const CallExpr *CE) {
     // C++11 [intro.execution]p15:
     //   When calling a function [...], every value computation and side effect
     //   associated with any argument expression, or with the postfix expression
@@ -12166,7 +12381,7 @@
     // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
   }
 
-  void VisitCXXConstructExpr(CXXConstructExpr *CCE) {
+  void VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
     // This is a call, so all subexpressions are sequenced before the result.
     SequencedSubexpression Sequenced(*this);
 
@@ -12176,8 +12391,8 @@
     // In C++11, list initializations are sequenced.
     SmallVector<SequenceTree::Seq, 32> Elts;
     SequenceTree::Seq Parent = Region;
-    for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(),
-                                        E = CCE->arg_end();
+    for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
+                                              E = CCE->arg_end();
          I != E; ++I) {
       Region = Tree.allocate(Parent);
       Elts.push_back(Region);
@@ -12190,7 +12405,7 @@
       Tree.merge(Elts[I]);
   }
 
-  void VisitInitListExpr(InitListExpr *ILE) {
+  void VisitInitListExpr(const InitListExpr *ILE) {
     if (!SemaRef.getLangOpts().CPlusPlus11)
       return VisitExpr(ILE);
 
@@ -12198,7 +12413,7 @@
     SmallVector<SequenceTree::Seq, 32> Elts;
     SequenceTree::Seq Parent = Region;
     for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
-      Expr *E = ILE->getInit(I);
+      const Expr *E = ILE->getInit(I);
       if (!E) continue;
       Region = Tree.allocate(Parent);
       Elts.push_back(Region);
@@ -12214,11 +12429,11 @@
 
 } // namespace
 
-void Sema::CheckUnsequencedOperations(Expr *E) {
-  SmallVector<Expr *, 8> WorkList;
+void Sema::CheckUnsequencedOperations(const Expr *E) {
+  SmallVector<const Expr *, 8> WorkList;
   WorkList.push_back(E);
   while (!WorkList.empty()) {
-    Expr *Item = WorkList.pop_back_val();
+    const Expr *Item = WorkList.pop_back_val();
     SequenceChecker(*this, Item, WorkList);
   }
 }
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -10742,7 +10742,7 @@
   void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
   void CheckBoolLikeConversion(Expr *E, SourceLocation CC);
   void CheckForIntOverflow(Expr *E);
-  void CheckUnsequencedOperations(Expr *E);
+  void CheckUnsequencedOperations(const Expr *E);
 
   /// Perform semantic checks on a completed expression. This will either
   /// be a full-expression or a default argument expression.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1925,9 +1925,15 @@
   "parenthesized initializer list">;
 
 def warn_unsequenced_mod_mod : Warning<
-  "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
+  "multiple unsequenced modifications to "
+  "%select{|member |static member }0%2"
+  "%select{| of %3| of struct %4| of union %4| of class %4"
+  "| of structured binding %3}1">, InGroup<Unsequenced>;
 def warn_unsequenced_mod_use : Warning<
-  "unsequenced modification and access to %0">, InGroup<Unsequenced>;
+  "unsequenced modification and access to "
+  "%select{|member |static member }0%2"
+  "%select{| of %3| of struct %4| of union %4| of class %4"
+  "| of structured binding %3}1">, InGroup<Unsequenced>;
 
 def select_initialized_entity_kind : TextSubstitution<
   "%select{copying variable|copying parameter|"
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to