}
+bool getStaticBooleanValue(Expr* E, bool& TCond) {
+ if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E)) {
+ TCond = false;
+ return true;
+ } else if (CXXBoolLiteralExpr *BLE = dyn_cast<CXXBoolLiteralExpr>(E)) {
+ TCond = BLE->getValue();
+ return true;
+ } else if (IntegerLiteral *ILE = dyn_cast<IntegerLiteral>(E)) {
+ TCond = ILE->getValue().getBoolValue();
+ return true;
+ } else if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) {
+ return getStaticBooleanValue(CE->getSubExpr(), TCond);
+ }
+ return false;
+}
+
+
// If Cond can be traced back to a function call, return the call expression.
// The negate variable should be called with false, and will be set to true
// if the function call is negated, e.g. if (!mu.tryLock(...))
if (const CallExpr *CallExp = dyn_cast<CallExpr>(Cond)) {
return CallExp;
}
+ else if (const ParenExpr *PE = dyn_cast<ParenExpr>(Cond)) {
+ return getTrylockCallExpr(PE->getSubExpr(), C, Negate);
+ }
else if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Cond)) {
return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
}
Negate = !Negate;
return getTrylockCallExpr(UOP->getSubExpr(), C, Negate);
}
+ return 0;
+ }
+ else if (const BinaryOperator *BOP = dyn_cast<BinaryOperator>(Cond)) {
+ if (BOP->getOpcode() == BO_EQ || BOP->getOpcode() == BO_NE) {
+ if (BOP->getOpcode() == BO_NE)
+ Negate = !Negate;
+
+ bool TCond = false;
+ if (getStaticBooleanValue(BOP->getRHS(), TCond)) {
+ if (!TCond) Negate = !Negate;
+ return getTrylockCallExpr(BOP->getLHS(), C, Negate);
+ }
+ else if (getStaticBooleanValue(BOP->getLHS(), TCond)) {
+ if (!TCond) Negate = !Negate;
+ return getTrylockCallExpr(BOP->getRHS(), C, Negate);
+ }
+ return 0;
+ }
+ return 0;
}
// FIXME -- handle && and || as well.
- return NULL;
+ return 0;
}
-// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
-// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 -Wc++98-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 %s
+
+// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 -Wc++98-compat %s
+// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
#define LOCKABLE __attribute__ ((lockable))
#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
+namespace TryLockEqTest {
+
+class Foo {
+ Mutex mu_;
+ int a GUARDED_BY(mu_);
+ bool c;
+
+ int tryLockMutexI() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu_);
+ Mutex* tryLockMutexP() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu_);
+ void unlock() UNLOCK_FUNCTION(mu_);
+
+ void test1();
+ void test2();
+};
+
+
+void Foo::test1() {
+ if (tryLockMutexP() == 0) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+
+ if (tryLockMutexP() != 0) {
+ a = 0;
+ unlock();
+ }
+
+ if (0 != tryLockMutexP()) {
+ a = 0;
+ unlock();
+ }
+
+ if (!(tryLockMutexP() == 0)) {
+ a = 0;
+ unlock();
+ }
+
+ if (tryLockMutexI() == 0) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+
+ if (0 == tryLockMutexI()) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+
+ if (tryLockMutexI() == 1) {
+ a = 0;
+ unlock();
+ }
+
+ if (mu_.TryLock() == false) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+
+ if (mu_.TryLock() == true) {
+ a = 0;
+ unlock();
+ }
+ else {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ }
+
+#if __has_feature(cxx_nullptr)
+ if (tryLockMutexP() == nullptr) {
+ a = 0; // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+ return;
+ }
+ a = 0;
+ unlock();
+#endif
+}
+
+
+void Foo::test2() {
+/* FIXME: these tests depend on changes to the CFG.
+ *
+ if (mu_.TryLock() && c) {
+ a = 0;
+ unlock();
+ }
+ else return;
+
+ if (c && mu_.TryLock()) {
+ a = 0;
+ unlock();
+ }
+ else return;
+
+ if (!(mu_.TryLock() && c))
+ return;
+ a = 0;
+ unlock();
+
+ if (!(c && mu_.TryLock()))
+ return;
+ a = 0;
+ unlock();
+
+ if (!(mu_.TryLock() == 0) && c) {
+ a = 0;
+ unlock();
+ }
+
+ if (!mu_.TryLock() || c)
+ return;
+ a = 0;
+ unlock();
+*/
+}
+
+
+} // end namespace TryLockEqTest