summaryrefslogtreecommitdiffstats
path: root/test/SemaCXX/warn-thread-safety-analysis.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/SemaCXX/warn-thread-safety-analysis.cpp')
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp669
1 files changed, 631 insertions, 38 deletions
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index 17a1931..bd555ac 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -24,10 +24,6 @@
__attribute__ ((shared_locks_required(__VA_ARGS__)))
#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
-//-----------------------------------------//
-// Helper fields
-//-----------------------------------------//
-
class __attribute__((lockable)) Mutex {
public:
@@ -60,6 +56,15 @@ class SCOPED_LOCKABLE ReleasableMutexLock {
};
+// The universal lock, written "*", allows checking to be selectively turned
+// off for a particular piece of code.
+void beginNoWarnOnReads() SHARED_LOCK_FUNCTION("*");
+void endNoWarnOnReads() UNLOCK_FUNCTION("*");
+void beginNoWarnOnWrites() EXCLUSIVE_LOCK_FUNCTION("*");
+void endNoWarnOnWrites() UNLOCK_FUNCTION("*");
+
+
+// For testing handling of smart pointers.
template<class T>
class SmartPtr {
public:
@@ -76,6 +81,15 @@ private:
};
+// For testing destructor calls and cleanup.
+class MyString {
+public:
+ MyString(const char* s);
+ ~MyString();
+};
+
+
+
Mutex sls_mu;
Mutex sls_mu2 __attribute__((acquired_after(sls_mu)));
@@ -529,7 +543,8 @@ void late_bad_0() {
LateFoo fooB;
fooA.mu.Lock();
fooB.a = 5; // \
- // expected-warning{{writing variable 'a' requires locking 'fooB.mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'fooB.mu' exclusively}} \
+ // expected-note{{found near match 'fooA.mu'}}
fooA.mu.Unlock();
}
@@ -549,7 +564,8 @@ void late_bad_2() {
LateBar BarA;
BarA.FooPointer->mu.Lock();
BarA.Foo.a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'BarA.Foo.mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.Foo.mu' exclusively}} \
+ // expected-note{{found near match 'BarA.FooPointer->mu'}}
BarA.FooPointer->mu.Unlock();
}
@@ -557,7 +573,8 @@ void late_bad_3() {
LateBar BarA;
BarA.Foo.mu.Lock();
BarA.FooPointer->a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'BarA.FooPointer->mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.FooPointer->mu' exclusively}} \
+ // expected-note{{found near match 'BarA.Foo.mu'}}
BarA.Foo.mu.Unlock();
}
@@ -565,7 +582,8 @@ void late_bad_4() {
LateBar BarA;
BarA.Foo.mu.Lock();
BarA.Foo2.a = 2; // \
- // expected-warning{{writing variable 'a' requires locking 'BarA.Foo2.mu' exclusively}}
+ // expected-warning{{writing variable 'a' requires locking 'BarA.Foo2.mu' exclusively}} \
+ // expected-note{{found near match 'BarA.Foo.mu'}}
BarA.Foo.mu.Unlock();
}
@@ -1233,7 +1251,9 @@ void func()
{
b1->MyLock();
b1->a_ = 5;
- b2->a_ = 3; // expected-warning {{writing variable 'a_' requires locking 'b2->mu1_' exclusively}}
+ b2->a_ = 3; // \
+ // expected-warning {{writing variable 'a_' requires locking 'b2->mu1_' exclusively}} \
+ // expected-note {{found near match 'b1->mu1_'}}
b2->MyLock();
b2->MyUnlock();
b1->MyUnlock();
@@ -1263,11 +1283,13 @@ int func(int i)
int x;
b3->mu1_.Lock();
res = b1.a_ + b3->b_; // expected-warning {{reading variable 'a_' requires locking 'b1.mu1_'}} \
- // expected-warning {{writing variable 'res' requires locking 'mu' exclusively}}
+ // expected-warning {{writing variable 'res' requires locking 'mu' exclusively}} \
+ // expected-note {{found near match 'b3->mu1_'}}
*p = i; // expected-warning {{reading variable 'p' requires locking 'mu'}} \
// expected-warning {{writing the value pointed to by 'p' requires locking 'mu' exclusively}}
b1.a_ = res + b3->b_; // expected-warning {{reading variable 'res' requires locking 'mu'}} \
- // expected-warning {{writing variable 'a_' requires locking 'b1.mu1_' exclusively}}
+ // expected-warning {{writing variable 'a_' requires locking 'b1.mu1_' exclusively}} \
+ // expected-note {{found near match 'b3->mu1_'}}
b3->b_ = *b1.q; // expected-warning {{reading the value pointed to by 'q' requires locking 'mu'}}
b3->mu1_.Unlock();
b1.b_ = res; // expected-warning {{reading variable 'res' requires locking 'mu'}}
@@ -1292,8 +1314,12 @@ class Foo {
child->Func(new_foo); // There shouldn't be any warning here as the
// acquired lock is not in child.
- child->bar(7); // expected-warning {{calling function 'bar' requires exclusive lock on 'child->lock_'}}
- child->a_ = 5; // expected-warning {{writing variable 'a_' requires locking 'child->lock_' exclusively}}
+ child->bar(7); // \
+ // expected-warning {{calling function 'bar' requires exclusive lock on 'child->lock_'}} \
+ // expected-note {{found near match 'lock_'}}
+ child->a_ = 5; // \
+ // expected-warning {{writing variable 'a_' requires locking 'child->lock_' exclusively}} \
+ // expected-note {{found near match 'lock_'}}
lock_.Unlock();
}
@@ -1491,7 +1517,8 @@ namespace substitution_test {
DataLocker dlr;
dlr.lockData(d1);
foo(d2); // \
- // expected-warning {{calling function 'foo' requires exclusive lock on 'd2->mu'}}
+ // expected-warning {{calling function 'foo' requires exclusive lock on 'd2->mu'}} \
+ // expected-note {{found near match 'd1->mu'}}
dlr.unlockData(d1);
}
};
@@ -1516,22 +1543,6 @@ namespace constructor_destructor_tests {
}
-namespace invalid_lock_expression_test {
-
-class LOCKABLE MyLockable {
-public:
- MyLockable() __attribute__((exclusive_lock_function)) { }
- ~MyLockable() { }
-};
-
-// create an empty lock expression
-void foo() {
- MyLockable lock; // \
- // expected-warning {{cannot resolve lock expression}}
-}
-
-} // end namespace invalid_lock_expression_test
-
namespace template_member_test {
struct S { int n; };
@@ -1638,6 +1649,8 @@ void bar() {
}; // end namespace FunctionAttrTest
+namespace TryLockTest {
+
struct TestTryLock {
Mutex mu;
int a GUARDED_BY(mu);
@@ -1734,8 +1747,36 @@ struct TestTryLock {
b = !b;
}
}
+
+ // Test merge of exclusive trylock
+ void foo11() {
+ if (cond) {
+ if (!mu.TryLock())
+ return;
+ }
+ else {
+ mu.Lock();
+ }
+ a = 10;
+ mu.Unlock();
+ }
+
+ // Test merge of shared trylock
+ void foo12() {
+ if (cond) {
+ if (!mu.ReaderTryLock())
+ return;
+ }
+ else {
+ mu.ReaderLock();
+ }
+ int i = a;
+ mu.Unlock();
+ }
}; // end TestTrylock
+} // end namespace TrylockTest
+
namespace TestTemplateAttributeInstantiation {
@@ -1829,7 +1870,8 @@ void test() {
f1.mu_.Unlock();
bt.barTD(&f1); // \
- // expected-warning {{calling function 'barTD' requires exclusive lock on 'f1.mu_'}}
+ // expected-warning {{calling function 'barTD' requires exclusive lock on 'f1.mu_'}} \
+ // expected-note {{found near match 'bt.fooBase.mu_'}}
bt.fooBase.mu_.Unlock();
bt.fooBaseT.mu_.Unlock();
@@ -2235,27 +2277,32 @@ void test() {
bar.getFoo().mu_.Lock();
bar.getFooey().a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'bar.getFooey().mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFooey().mu_' exclusively}} \
+ // expected-note {{found near match 'bar.getFoo().mu_'}}
bar.getFoo().mu_.Unlock();
bar.getFoo2(a).mu_.Lock();
bar.getFoo2(b).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'bar.getFoo2(b).mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFoo2(b).mu_' exclusively}} \
+ // expected-note {{found near match 'bar.getFoo2(a).mu_'}}
bar.getFoo2(a).mu_.Unlock();
bar.getFoo3(a, b).mu_.Lock();
bar.getFoo3(a, c).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'bar.getFoo3(a,c).mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'bar.getFoo3(a,c).mu_' exclusively}} \
+ // expected-note {{'bar.getFoo3(a,b).mu_'}}
bar.getFoo3(a, b).mu_.Unlock();
getBarFoo(bar, a).mu_.Lock();
getBarFoo(bar, b).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking 'getBarFoo(bar,b).mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking 'getBarFoo(bar,b).mu_' exclusively}} \
+ // expected-note {{'getBarFoo(bar,a).mu_'}}
getBarFoo(bar, a).mu_.Unlock();
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock();
(a > 0 ? fooArray[b] : fooArray[c]).a = 0; // \
- // expected-warning {{writing variable 'a' requires locking '((a#_)#_#fooArray[b]).mu_' exclusively}}
+ // expected-warning {{writing variable 'a' requires locking '((a#_)#_#fooArray[b]).mu_' exclusively}} \
+ // expected-note {{'((a#_)#_#fooArray[_]).mu_'}}
(a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();
}
@@ -2314,7 +2361,9 @@ void test1(Foo* f1, Foo* f2) {
f1->a = 0;
f1->foo();
- f1->foo2(f2); // expected-warning {{calling function 'foo2' requires exclusive lock on 'f2->mu_'}}
+ f1->foo2(f2); // \
+ // expected-warning {{calling function 'foo2' requires exclusive lock on 'f2->mu_'}} \
+ // expected-note {{found near match 'f1->mu_'}}
Foo::getMu(f2)->Lock();
f1->foo2(f2);
@@ -2354,7 +2403,9 @@ void test2(Bar* b1, Bar* b2) {
b1->b = 0;
b1->bar();
- b1->bar2(b2); // expected-warning {{calling function 'bar2' requires exclusive lock on 'b2->mu_'}}
+ b1->bar2(b2); // \
+ // expected-warning {{calling function 'bar2' requires exclusive lock on 'b2->mu_'}} \
+ // // expected-note {{found near match 'b1->mu_'}}
b2->getMu()->Lock();
b1->bar2(b2);
@@ -3119,3 +3170,545 @@ void test() {
} // end namespace ExistentialPatternMatching
+
+namespace StringIgnoreTest {
+
+class Foo {
+public:
+ Mutex mu_;
+ void lock() EXCLUSIVE_LOCK_FUNCTION("");
+ void unlock() UNLOCK_FUNCTION("");
+ void goober() EXCLUSIVE_LOCKS_REQUIRED("");
+ void roober() SHARED_LOCKS_REQUIRED("");
+};
+
+
+class Bar : public Foo {
+public:
+ void bar(Foo* f) {
+ f->unlock();
+ f->goober();
+ f->roober();
+ f->lock();
+ };
+};
+
+} // end namespace StringIgnoreTest
+
+
+namespace LockReturnedScopeFix {
+
+class Base {
+protected:
+ struct Inner;
+ bool c;
+
+ const Mutex& getLock(const Inner* i);
+
+ void lockInner (Inner* i) EXCLUSIVE_LOCK_FUNCTION(getLock(i));
+ void unlockInner(Inner* i) UNLOCK_FUNCTION(getLock(i));
+ void foo(Inner* i) EXCLUSIVE_LOCKS_REQUIRED(getLock(i));
+
+ void bar(Inner* i);
+};
+
+
+struct Base::Inner {
+ Mutex lock_;
+ void doSomething() EXCLUSIVE_LOCKS_REQUIRED(lock_);
+};
+
+
+const Mutex& Base::getLock(const Inner* i) LOCK_RETURNED(i->lock_) {
+ return i->lock_;
+}
+
+
+void Base::foo(Inner* i) {
+ i->doSomething();
+}
+
+void Base::bar(Inner* i) {
+ if (c) {
+ i->lock_.Lock();
+ unlockInner(i);
+ }
+ else {
+ lockInner(i);
+ i->lock_.Unlock();
+ }
+}
+
+} // end namespace LockReturnedScopeFix
+
+
+namespace TrylockWithCleanups {
+
+struct Foo {
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+};
+
+Foo* GetAndLockFoo(const MyString& s)
+ EXCLUSIVE_TRYLOCK_FUNCTION(true, &Foo::mu_);
+
+static void test() {
+ Foo* lt = GetAndLockFoo("foo");
+ if (!lt) return;
+ int a = lt->a;
+ lt->mu_.Unlock();
+}
+
+} // end namespace TrylockWithCleanups
+
+
+namespace UniversalLock {
+
+class Foo {
+ Mutex mu_;
+ bool c;
+
+ int a GUARDED_BY(mu_);
+ void r_foo() SHARED_LOCKS_REQUIRED(mu_);
+ void w_foo() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+
+ void test1() {
+ int b;
+
+ beginNoWarnOnReads();
+ b = a;
+ r_foo();
+ endNoWarnOnReads();
+
+ beginNoWarnOnWrites();
+ a = 0;
+ w_foo();
+ endNoWarnOnWrites();
+ }
+
+ // don't warn on joins with universal lock
+ void test2() {
+ if (c) {
+ beginNoWarnOnWrites();
+ }
+ a = 0; // \
+ // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ endNoWarnOnWrites(); // \
+ // expected-warning {{unlocking '*' that was not locked}}
+ }
+
+
+ // make sure the universal lock joins properly
+ void test3() {
+ if (c) {
+ mu_.Lock();
+ beginNoWarnOnWrites();
+ }
+ else {
+ beginNoWarnOnWrites();
+ mu_.Lock();
+ }
+ a = 0;
+ endNoWarnOnWrites();
+ mu_.Unlock();
+ }
+
+
+ // combine universal lock with other locks
+ void test4() {
+ beginNoWarnOnWrites();
+ mu_.Lock();
+ mu_.Unlock();
+ endNoWarnOnWrites();
+
+ mu_.Lock();
+ beginNoWarnOnWrites();
+ endNoWarnOnWrites();
+ mu_.Unlock();
+
+ mu_.Lock();
+ beginNoWarnOnWrites();
+ mu_.Unlock();
+ endNoWarnOnWrites();
+ }
+};
+
+} // end namespace UniversalLock
+
+
+namespace TemplateLockReturned {
+
+template<class T>
+class BaseT {
+public:
+ virtual void baseMethod() = 0;
+ Mutex* get_mutex() LOCK_RETURNED(mutex_) { return &mutex_; }
+
+ Mutex mutex_;
+ int a GUARDED_BY(mutex_);
+};
+
+
+class Derived : public BaseT<int> {
+public:
+ void baseMethod() EXCLUSIVE_LOCKS_REQUIRED(get_mutex()) {
+ a = 0;
+ }
+};
+
+} // end namespace TemplateLockReturned
+
+
+namespace ExprMatchingBugFix {
+
+class Foo {
+public:
+ Mutex mu_;
+};
+
+
+class Bar {
+public:
+ bool c;
+ Foo* foo;
+ Bar(Foo* f) : foo(f) { }
+
+ struct Nested {
+ Foo* foo;
+ Nested(Foo* f) : foo(f) { }
+
+ void unlockFoo() UNLOCK_FUNCTION(&Foo::mu_);
+ };
+
+ void test();
+};
+
+
+void Bar::test() {
+ foo->mu_.Lock();
+ if (c) {
+ Nested *n = new Nested(foo);
+ n->unlockFoo();
+ }
+ else {
+ foo->mu_.Unlock();
+ }
+}
+
+}; // end namespace ExprMatchingBugfix
+
+
+namespace ComplexNameTest {
+
+class Foo {
+public:
+ static Mutex mu_;
+
+ Foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) { }
+ ~Foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) { }
+
+ int operator[](int i) EXCLUSIVE_LOCKS_REQUIRED(mu_) { return 0; }
+};
+
+class Bar {
+public:
+ static Mutex mu_;
+
+ Bar() LOCKS_EXCLUDED(mu_) { }
+ ~Bar() LOCKS_EXCLUDED(mu_) { }
+
+ int operator[](int i) LOCKS_EXCLUDED(mu_) { return 0; }
+};
+
+
+void test1() {
+ Foo f; // expected-warning {{calling function 'Foo' requires exclusive lock on 'mu_'}}
+ int a = f[0]; // expected-warning {{calling function 'operator[]' requires exclusive lock on 'mu_'}}
+} // expected-warning {{calling function '~Foo' requires exclusive lock on 'mu_'}}
+
+
+void test2() {
+ Bar::mu_.Lock();
+ {
+ Bar b; // expected-warning {{cannot call function 'Bar' while mutex 'mu_' is locked}}
+ int a = b[0]; // expected-warning {{cannot call function 'operator[]' while mutex 'mu_' is locked}}
+ } // expected-warning {{cannot call function '~Bar' while mutex 'mu_' is locked}}
+ Bar::mu_.Unlock();
+}
+
+}; // end namespace ComplexNameTest
+
+
+namespace UnreachableExitTest {
+
+class FemmeFatale {
+public:
+ FemmeFatale();
+ ~FemmeFatale() __attribute__((noreturn));
+};
+
+void exitNow() __attribute__((noreturn));
+void exitDestruct(const MyString& ms) __attribute__((noreturn));
+
+Mutex fatalmu_;
+
+void test1() EXCLUSIVE_LOCKS_REQUIRED(fatalmu_) {
+ exitNow();
+}
+
+void test2() EXCLUSIVE_LOCKS_REQUIRED(fatalmu_) {
+ FemmeFatale femme;
+}
+
+bool c;
+
+void test3() EXCLUSIVE_LOCKS_REQUIRED(fatalmu_) {
+ if (c) {
+ exitNow();
+ }
+ else {
+ FemmeFatale femme;
+ }
+}
+
+void test4() EXCLUSIVE_LOCKS_REQUIRED(fatalmu_) {
+ exitDestruct("foo");
+}
+
+} // end namespace UnreachableExitTest
+
+
+namespace VirtualMethodCanonicalizationTest {
+
+class Base {
+public:
+ virtual Mutex* getMutex() = 0;
+};
+
+class Base2 : public Base {
+public:
+ Mutex* getMutex();
+};
+
+class Base3 : public Base2 {
+public:
+ Mutex* getMutex();
+};
+
+class Derived : public Base3 {
+public:
+ Mutex* getMutex(); // overrides Base::getMutex()
+};
+
+void baseFun(Base *b) EXCLUSIVE_LOCKS_REQUIRED(b->getMutex()) { }
+
+void derivedFun(Derived *d) EXCLUSIVE_LOCKS_REQUIRED(d->getMutex()) {
+ baseFun(d);
+}
+
+} // end namespace VirtualMethodCanonicalizationTest
+
+
+namespace TemplateFunctionParamRemapTest {
+
+template <class T>
+struct Cell {
+ T dummy_;
+ Mutex* mu_;
+};
+
+class Foo {
+public:
+ template <class T>
+ void elr(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+
+ void test();
+};
+
+template<class T>
+void Foo::elr(Cell<T>* c1) { }
+
+void Foo::test() {
+ Cell<int> cell;
+ elr(&cell); // \
+ // expected-warning {{calling function 'elr' requires exclusive lock on 'cell.mu_'}}
+}
+
+
+template<class T>
+void globalELR(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+
+template<class T>
+void globalELR(Cell<T>* c1) { }
+
+void globalTest() {
+ Cell<int> cell;
+ globalELR(&cell); // \
+ // expected-warning {{calling function 'globalELR' requires exclusive lock on 'cell.mu_'}}
+}
+
+
+template<class T>
+void globalELR2(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+
+// second declaration
+template<class T>
+void globalELR2(Cell<T>* c2);
+
+template<class T>
+void globalELR2(Cell<T>* c3) { }
+
+// re-declaration after definition
+template<class T>
+void globalELR2(Cell<T>* c4);
+
+void globalTest2() {
+ Cell<int> cell;
+ globalELR2(&cell); // \
+ // expected-warning {{calling function 'globalELR2' requires exclusive lock on 'cell.mu_'}}
+}
+
+
+template<class T>
+class FooT {
+public:
+ void elr(Cell<T>* c) __attribute__((exclusive_locks_required(c->mu_)));
+};
+
+template<class T>
+void FooT<T>::elr(Cell<T>* c1) { }
+
+void testFooT() {
+ Cell<int> cell;
+ FooT<int> foo;
+ foo.elr(&cell); // \
+ // expected-warning {{calling function 'elr' requires exclusive lock on 'cell.mu_'}}
+}
+
+} // end namespace TemplateFunctionParamRemapTest
+
+
+namespace SelfConstructorTest {
+
+class SelfLock {
+public:
+ SelfLock() EXCLUSIVE_LOCK_FUNCTION(mu_);
+ ~SelfLock() UNLOCK_FUNCTION(mu_);
+
+ void foo() EXCLUSIVE_LOCKS_REQUIRED(mu_);
+
+ Mutex mu_;
+};
+
+class LOCKABLE SelfLock2 {
+public:
+ SelfLock2() EXCLUSIVE_LOCK_FUNCTION();
+ ~SelfLock2() UNLOCK_FUNCTION();
+
+ void foo() EXCLUSIVE_LOCKS_REQUIRED(this);
+};
+
+
+void test() {
+ SelfLock s;
+ s.foo();
+}
+
+void test2() {
+ SelfLock2 s2;
+ s2.foo();
+}
+
+} // end namespace SelfConstructorTest
+
+
+namespace MultipleAttributeTest {
+
+class Foo {
+ Mutex mu1_;
+ Mutex mu2_;
+ int a GUARDED_BY(mu1_);
+ int b GUARDED_BY(mu2_);
+ int c GUARDED_BY(mu1_) GUARDED_BY(mu2_);
+ int* d PT_GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
+
+ void foo1() EXCLUSIVE_LOCKS_REQUIRED(mu1_)
+ EXCLUSIVE_LOCKS_REQUIRED(mu2_);
+ void foo2() SHARED_LOCKS_REQUIRED(mu1_)
+ SHARED_LOCKS_REQUIRED(mu2_);
+ void foo3() LOCKS_EXCLUDED(mu1_)
+ LOCKS_EXCLUDED(mu2_);
+ void lock() EXCLUSIVE_LOCK_FUNCTION(mu1_)
+ EXCLUSIVE_LOCK_FUNCTION(mu2_);
+ void readerlock() EXCLUSIVE_LOCK_FUNCTION(mu1_)
+ EXCLUSIVE_LOCK_FUNCTION(mu2_);
+ void unlock() UNLOCK_FUNCTION(mu1_)
+ UNLOCK_FUNCTION(mu2_);
+ bool trylock() EXCLUSIVE_TRYLOCK_FUNCTION(true, mu1_)
+ EXCLUSIVE_TRYLOCK_FUNCTION(true, mu2_);
+ bool readertrylock() SHARED_TRYLOCK_FUNCTION(true, mu1_)
+ SHARED_TRYLOCK_FUNCTION(true, mu2_);
+
+ void test();
+};
+
+
+void Foo::foo1() {
+ a = 1;
+ b = 2;
+}
+
+void Foo::foo2() {
+ int result = a + b;
+}
+
+void Foo::foo3() { }
+void Foo::lock() { }
+void Foo::readerlock() { }
+void Foo::unlock() { }
+bool Foo::trylock() { return true; }
+bool Foo::readertrylock() { return true; }
+
+
+void Foo::test() {
+ mu1_.Lock();
+ foo1(); // expected-warning {{}}
+ c = 0; // expected-warning {{}}
+ *d = 0; // expected-warning {{}}
+ mu1_.Unlock();
+
+ mu1_.ReaderLock();
+ foo2(); // expected-warning {{}}
+ int x = c; // expected-warning {{}}
+ int y = *d; // expected-warning {{}}
+ mu1_.Unlock();
+
+ mu2_.Lock();
+ foo3(); // expected-warning {{}}
+ mu2_.Unlock();
+
+ lock();
+ a = 0;
+ b = 0;
+ unlock();
+
+ readerlock();
+ int z = a + b;
+ unlock();
+
+ if (trylock()) {
+ a = 0;
+ b = 0;
+ unlock();
+ }
+
+ if (readertrylock()) {
+ int zz = a + b;
+ unlock();
+ }
+}
+
+
+} // end namespace MultipleAttributeTest
+
+
OpenPOWER on IntegriCloud