diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-12-14 20:47:58 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-12-14 20:47:58 +0000 |
commit | 87fae78f666cda8a567d98080858cfad013a2589 (patch) | |
tree | e7e6373ae72d0f0270701d3befa258311c193c67 /test | |
parent | b53ab0e23fc3229a6e9815c0602165114591a911 (diff) | |
download | clang-87fae78f666cda8a567d98080858cfad013a2589.tar.gz |
[analyzer] MoveChecker: Improve invalidation policies.
If a moved-from object is passed into a conservatively evaluated function
by pointer or by reference, we assume that the function may reset its state.
Make sure it doesn't apply to const pointers and const references. Add a test
that demonstrates that it does apply to rvalue references.
Additionally, make sure that the object is invalidated when its contents change
for reasons other than invalidation caused by evaluating a call conservatively.
In particular, when the object's fields are manipulated directly, we should
assume that some sort of reset may be happening.
Differential Revision: https://reviews.llvm.org/D55289
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@349190 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
-rw-r--r-- | test/Analysis/use-after-move.cpp | 49 |
1 files changed, 44 insertions, 5 deletions
diff --git a/test/Analysis/use-after-move.cpp b/test/Analysis/use-after-move.cpp index 3134720e4d..1ef04a0f5a 100644 --- a/test/Analysis/use-after-move.cpp +++ b/test/Analysis/use-after-move.cpp @@ -116,6 +116,19 @@ public: 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 @@ void paramEvaluateOrderTest() { 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 |