This revision was automatically updated to reflect the committed changes.
Closed by commit rC349190: [analyzer] MoveChecker: Improve invalidation 
policies. (authored by dergachev, committed by ).

Repository:
  rC Clang

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

https://reviews.llvm.org/D55289

Files:
  lib/StaticAnalyzer/Checkers/MoveChecker.cpp
  test/Analysis/use-after-move.cpp

Index: test/Analysis/use-after-move.cpp
===================================================================
--- test/Analysis/use-after-move.cpp
+++ test/Analysis/use-after-move.cpp
@@ -116,6 +116,19 @@
   bool empty() const;
   bool isEmpty() const;
   operator bool() const;
+
+  void testUpdateField() {
+    A a;
+    A b = std::move(a);
+    a.i = 1;
+    a.foo(); // no-warning
+  }
+  void testUpdateFieldDouble() {
+    A a;
+    A b = std::move(a);
+    a.d = 1.0;
+    a.foo(); // no-warning
+  }
 };
 
 int bignum();
@@ -594,24 +607,50 @@
   foobar(a.getI(), std::move(a)); //no-warning
 }
 
-void not_known(A &a);
-void not_known(A *a);
+void not_known_pass_by_ref(A &a);
+void not_known_pass_by_const_ref(const A &a);
+void not_known_pass_by_rvalue_ref(A &&a);
+void not_known_pass_by_ptr(A *a);
+void not_known_pass_by_const_ptr(const A *a);
 
 void regionAndPointerEscapeTest() {
   {
     A a;
     A b;
     b = std::move(a);
-    not_known(a);
-    a.foo(); //no-warning
+    not_known_pass_by_ref(a);
+    a.foo(); // no-warning
+  }
+  {
+    A a;
+    A b;
+    b = std::move(a); // expected-note{{Object 'a' is moved}}
+    not_known_pass_by_const_ref(a);
+    a.foo(); // expected-warning{{Method called on moved-from object 'a'}}
+             // expected-note@-1{{Method called on moved-from object 'a'}}
+  }
+  {
+    A a;
+    A b;
+    b = std::move(a);
+    not_known_pass_by_rvalue_ref(std::move(a));
+    a.foo(); // no-warning
   }
   {
     A a;
     A b;
     b = std::move(a);
-    not_known(&a);
+    not_known_pass_by_ptr(&a);
     a.foo(); // no-warning
   }
+  {
+    A a;
+    A b;
+    b = std::move(a); // expected-note{{Object 'a' is moved}}
+    not_known_pass_by_const_ptr(&a);
+    a.foo(); // expected-warning{{Method called on moved-from object 'a'}}
+             // expected-note@-1{{Method called on moved-from object 'a'}}
+  }
 }
 
 // A declaration statement containing multiple declarations sequences the
Index: lib/StaticAnalyzer/Checkers/MoveChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -53,8 +53,8 @@
   ProgramStateRef
   checkRegionChanges(ProgramStateRef State,
                      const InvalidatedSymbols *Invalidated,
-                     ArrayRef<const MemRegion *> ExplicitRegions,
-                     ArrayRef<const MemRegion *> Regions,
+                     ArrayRef<const MemRegion *> RequestedRegions,
+                     ArrayRef<const MemRegion *> InvalidatedRegions,
                      const LocationContext *LCtx, const CallEvent *Call) const;
   void printState(raw_ostream &Out, ProgramStateRef State,
                   const char *NL, const char *Sep) const override;
@@ -525,19 +525,35 @@
 
 ProgramStateRef MoveChecker::checkRegionChanges(
     ProgramStateRef State, const InvalidatedSymbols *Invalidated,
-    ArrayRef<const MemRegion *> ExplicitRegions,
-    ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
-    const CallEvent *Call) const {
-  // In case of an InstanceCall don't remove the ThisRegion from the GDM since
-  // it is handled in checkPreCall and checkPostCall.
-  const MemRegion *ThisRegion = nullptr;
-  if (const auto *IC = dyn_cast_or_null<CXXInstanceCall>(Call)) {
-    ThisRegion = IC->getCXXThisVal().getAsRegion();
-  }
-
-  for (const auto *Region : ExplicitRegions) {
-    if (ThisRegion != Region)
-      State = removeFromState(State, Region);
+    ArrayRef<const MemRegion *> RequestedRegions,
+    ArrayRef<const MemRegion *> InvalidatedRegions,
+    const LocationContext *LCtx, const CallEvent *Call) const {
+  if (Call) {
+    // Relax invalidation upon function calls: only invalidate parameters
+    // that are passed directly via non-const pointers or non-const references
+    // or rvalue references.
+    // In case of an InstanceCall don't invalidate the this-region since
+    // it is fully handled in checkPreCall and checkPostCall.
+    const MemRegion *ThisRegion = nullptr;
+    if (const auto *IC = dyn_cast<CXXInstanceCall>(Call))
+      ThisRegion = IC->getCXXThisVal().getAsRegion();
+
+    // Requested ("explicit") regions are the regions passed into the call
+    // directly, but not all of them end up being invalidated.
+    // But when they do, they appear in the InvalidatedRegions array as well.
+    for (const auto *Region : RequestedRegions) {
+      if (ThisRegion != Region) {
+        if (llvm::find(InvalidatedRegions, Region) !=
+            std::end(InvalidatedRegions)) {
+          State = removeFromState(State, Region);
+        }
+      }
+    }
+  } else {
+    // For invalidations that aren't caused by calls, assume nothing. In
+    // particular, direct write into an object's field invalidates the status.
+    for (const auto *Region : InvalidatedRegions)
+      State = removeFromState(State, Region->getBaseRegion());
   }
 
   return State;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to