Thread-safety analysis: eliminate false positives in case where the definition
duplicates attributes on the declaration. Also eliminates a false negative in
ReleasableMutexLock. Fixing this bug required some refactoring.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159780 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index 9f01223..10f9ad2 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -2395,6 +2395,8 @@
void test1();
void test2();
void test3();
+ void test4();
+ void test5();
};
@@ -2417,6 +2419,22 @@
a = 1; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
}
+void Foo::test4() {
+ ReleasableMutexLock rlock(&mu_);
+ rlock.Release();
+ rlock.Release(); // expected-warning {{unlocking 'mu_' that was not locked}}
+}
+
+void Foo::test5() {
+ ReleasableMutexLock rlock(&mu_);
+ if (c) {
+ rlock.Release();
+ }
+ // no warning on join point for managed lock.
+ rlock.Release(); // expected-warning {{unlocking 'mu_' that was not locked}}
+}
+
+
} // end namespace ReleasableScopedLock
@@ -2457,15 +2475,21 @@
Mutex mu_;
int a GUARDED_BY(mu_);
- void foo() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+ void foo1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+ int foo2() SHARED_LOCKS_REQUIRED(mu_);
};
-void Foo::foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+void Foo::foo1() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
a = 0;
}
-};
+int Foo::foo2() SHARED_LOCKS_REQUIRED(mu_) {
+ return a;
+}
+
+}
+
namespace UnlockBug {
@@ -2487,6 +2511,7 @@
} // end namespace UnlockBug
+
namespace FoolishScopedLockableBug {
class SCOPED_LOCKABLE WTF_ScopedLockable {
@@ -2553,6 +2578,7 @@
} // end namespace FoolishScopedLockableBug
+
namespace TemporaryCleanupExpr {
class Foo {
@@ -2739,4 +2765,172 @@
+namespace DuplicateAttributeTest {
+
+class LOCKABLE Foo {
+public:
+ Mutex mu1_;
+ Mutex mu2_;
+ Mutex mu3_;
+ int a GUARDED_BY(mu1_);
+ int b GUARDED_BY(mu2_);
+ int c GUARDED_BY(mu3_);
+
+ void lock() EXCLUSIVE_LOCK_FUNCTION();
+ void unlock() UNLOCK_FUNCTION();
+
+ void lock1() EXCLUSIVE_LOCK_FUNCTION(mu1_);
+ void slock1() SHARED_LOCK_FUNCTION(mu1_);
+ void lock3() EXCLUSIVE_LOCK_FUNCTION(mu1_, mu2_, mu3_);
+ void locklots()
+ EXCLUSIVE_LOCK_FUNCTION(mu1_)
+ EXCLUSIVE_LOCK_FUNCTION(mu2_)
+ EXCLUSIVE_LOCK_FUNCTION(mu1_, mu2_, mu3_);
+
+ void unlock1() UNLOCK_FUNCTION(mu1_);
+ void unlock3() UNLOCK_FUNCTION(mu1_, mu2_, mu3_);
+ void unlocklots()
+ UNLOCK_FUNCTION(mu1_)
+ UNLOCK_FUNCTION(mu2_)
+ UNLOCK_FUNCTION(mu1_, mu2_, mu3_);
+};
+
+
+void Foo::lock() EXCLUSIVE_LOCK_FUNCTION() { }
+void Foo::unlock() UNLOCK_FUNCTION() { }
+
+void Foo::lock1() EXCLUSIVE_LOCK_FUNCTION(mu1_) {
+ mu1_.Lock();
+}
+
+void Foo::slock1() SHARED_LOCK_FUNCTION(mu1_) {
+ mu1_.Lock();
+}
+
+void Foo::lock3() EXCLUSIVE_LOCK_FUNCTION(mu1_, mu2_, mu3_) {
+ mu1_.Lock();
+ mu2_.Lock();
+ mu3_.Lock();
+}
+
+void Foo::locklots()
+ EXCLUSIVE_LOCK_FUNCTION(mu1_, mu2_)
+ EXCLUSIVE_LOCK_FUNCTION(mu2_, mu3_) {
+ mu1_.Lock();
+ mu2_.Lock();
+ mu3_.Lock();
+}
+
+void Foo::unlock1() UNLOCK_FUNCTION(mu1_) {
+ mu1_.Unlock();
+}
+
+void Foo::unlock3() UNLOCK_FUNCTION(mu1_, mu2_, mu3_) {
+ mu1_.Unlock();
+ mu2_.Unlock();
+ mu3_.Unlock();
+}
+
+void Foo::unlocklots()
+ UNLOCK_FUNCTION(mu1_, mu2_)
+ UNLOCK_FUNCTION(mu2_, mu3_) {
+ mu1_.Unlock();
+ mu2_.Unlock();
+ mu3_.Unlock();
+}
+
+
+void test0() {
+ Foo foo;
+ foo.lock();
+ foo.unlock();
+
+ foo.lock();
+ foo.lock(); // expected-warning {{locking 'foo' that is already locked}}
+ foo.unlock();
+ foo.unlock(); // expected-warning {{unlocking 'foo' that was not locked}}
+}
+
+
+void test1() {
+ Foo foo;
+ foo.lock1();
+ foo.a = 0;
+ foo.unlock1();
+
+ foo.lock1();
+ foo.lock1(); // expected-warning {{locking 'mu1_' that is already locked}}
+ foo.a = 0;
+ foo.unlock1();
+ foo.unlock1(); // expected-warning {{unlocking 'mu1_' that was not locked}}
+}
+
+
+int test2() {
+ Foo foo;
+ foo.slock1();
+ int d1 = foo.a;
+ foo.unlock1();
+
+ foo.slock1();
+ foo.slock1(); // expected-warning {{locking 'mu1_' that is already locked}}
+ int d2 = foo.a;
+ foo.unlock1();
+ foo.unlock1(); // expected-warning {{unlocking 'mu1_' that was not locked}}
+ return d1 + d2;
+}
+
+
+void test3() {
+ Foo foo;
+ foo.lock3();
+ foo.a = 0;
+ foo.b = 0;
+ foo.c = 0;
+ foo.unlock3();
+
+ foo.lock3();
+ foo.lock3(); // \
+ // expected-warning {{locking 'mu1_' that is already locked}} \
+ // expected-warning {{locking 'mu2_' that is already locked}} \
+ // expected-warning {{locking 'mu3_' that is already locked}}
+ foo.a = 0;
+ foo.b = 0;
+ foo.c = 0;
+ foo.unlock3();
+ foo.unlock3(); // \
+ // expected-warning {{unlocking 'mu1_' that was not locked}} \
+ // expected-warning {{unlocking 'mu2_' that was not locked}} \
+ // expected-warning {{unlocking 'mu3_' that was not locked}}
+}
+
+
+void testlots() {
+ Foo foo;
+ foo.locklots();
+ foo.a = 0;
+ foo.b = 0;
+ foo.c = 0;
+ foo.unlocklots();
+
+ foo.locklots();
+ foo.locklots(); // \
+ // expected-warning {{locking 'mu1_' that is already locked}} \
+ // expected-warning {{locking 'mu2_' that is already locked}} \
+ // expected-warning {{locking 'mu3_' that is already locked}}
+ foo.a = 0;
+ foo.b = 0;
+ foo.c = 0;
+ foo.unlocklots();
+ foo.unlocklots(); // \
+ // expected-warning {{unlocking 'mu1_' that was not locked}} \
+ // expected-warning {{unlocking 'mu2_' that was not locked}} \
+ // expected-warning {{unlocking 'mu3_' that was not locked}}
+}
+
+} // end namespace DuplicateAttributeTest
+
+
+
+