Compiler projects using llvm
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_CAPABILITY=0 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_CAPABILITY=1 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_CAPABILITY=0 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 -Wthread-safety -Wthread-safety-beta -Wno-thread-safety-negative -fcxx-exceptions -DUSE_CAPABILITY=1 %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

#include "thread-safety-annotations.h"

class LOCKABLE Mutex {
 public:
  void Lock() EXCLUSIVE_LOCK_FUNCTION();
  void ReaderLock() SHARED_LOCK_FUNCTION();
  void Unlock() UNLOCK_FUNCTION();
  void ExclusiveUnlock() EXCLUSIVE_UNLOCK_FUNCTION();
  void ReaderUnlock() SHARED_UNLOCK_FUNCTION();
  bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
  bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true);
  void LockWhen(const int &cond) EXCLUSIVE_LOCK_FUNCTION();

  void PromoteShared() SHARED_UNLOCK_FUNCTION() EXCLUSIVE_LOCK_FUNCTION();
  void DemoteExclusive() EXCLUSIVE_UNLOCK_FUNCTION() SHARED_LOCK_FUNCTION();

  // for negative capabilities
  const Mutex& operator!() const { return *this; }

  void AssertHeld()       ASSERT_EXCLUSIVE_LOCK();
  void AssertReaderHeld() ASSERT_SHARED_LOCK();
};

class SCOPED_LOCKABLE MutexLock {
 public:
  MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
  MutexLock(Mutex *mu, bool adopt) EXCLUSIVE_LOCKS_REQUIRED(mu);
  ~MutexLock() UNLOCK_FUNCTION();
};

class SCOPED_LOCKABLE ReaderMutexLock {
 public:
  ReaderMutexLock(Mutex *mu) SHARED_LOCK_FUNCTION(mu);
  ReaderMutexLock(Mutex *mu, bool adopt) SHARED_LOCKS_REQUIRED(mu);
  ~ReaderMutexLock() UNLOCK_FUNCTION();
};

class SCOPED_LOCKABLE ReleasableMutexLock {
 public:
  ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
  ~ReleasableMutexLock() UNLOCK_FUNCTION();

  void Release() UNLOCK_FUNCTION();
};

class SCOPED_LOCKABLE DoubleMutexLock {
public:
  DoubleMutexLock(Mutex *mu1, Mutex *mu2) EXCLUSIVE_LOCK_FUNCTION(mu1, mu2);
  ~DoubleMutexLock() UNLOCK_FUNCTION();
};

// 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:
  SmartPtr(T* p) : ptr_(p) { }
  SmartPtr(const SmartPtr<T>& p) : ptr_(p.ptr_) { }
  ~SmartPtr();

  T* get()        const { return ptr_; }
  T* operator->() const { return ptr_; }
  T& operator*()  const { return *ptr_; }
  T& operator[](int i) const { return ptr_[i]; }

private:
  T* ptr_;
};

template<typename T, typename U>
U& operator->*(const SmartPtr<T>& ptr, U T::*p) { return ptr->*p; }


// For testing destructor calls and cleanup.
class MyString {
public:
  MyString(const char* s);
  ~MyString();
};


// For testing operator overloading
template <class K, class T>
class MyMap {
public:
  T& operator[](const K& k);
};


// For testing handling of containers.
template <class T>
class MyContainer {
public:
  MyContainer();

  typedef T* iterator;
  typedef const T* const_iterator;

  T* begin();
  T* end();

  const T* cbegin();
  const T* cend();

  T&       operator[](int i);
  const T& operator[](int i) const;

private:
  T* ptr_;
};



Mutex sls_mu;

Mutex sls_mu2 __attribute__((acquired_after(sls_mu)));
int sls_guard_var __attribute__((guarded_var)) = 0;
int sls_guardby_var __attribute__((guarded_by(sls_mu))) = 0;

bool getBool();

class MutexWrapper {
public:
   Mutex mu;
   int x __attribute__((guarded_by(mu)));
   void MyLock() EXCLUSIVE_LOCK_FUNCTION(mu);
};

MutexWrapper sls_mw;

void sls_fun_0() {
  sls_mw.mu.Lock();
  sls_mw.x = 5;
  sls_mw.mu.Unlock();
}

void sls_fun_2() {
  sls_mu.Lock();
  int x = sls_guard_var;
  sls_mu.Unlock();
}

void sls_fun_3() {
  sls_mu.Lock();
  sls_guard_var = 2;
  sls_mu.Unlock();
}

void sls_fun_4() {
  sls_mu2.Lock();
  sls_guard_var = 2;
  sls_mu2.Unlock();
}

void sls_fun_5() {
  sls_mu.Lock();
  int x = sls_guardby_var;
  sls_mu.Unlock();
}

void sls_fun_6() {
  sls_mu.Lock();
  sls_guardby_var = 2;
  sls_mu.Unlock();
}

void sls_fun_7() {
  sls_mu.Lock();
  sls_mu2.Lock();
  sls_mu2.Unlock();
  sls_mu.Unlock();
}

void sls_fun_8() {
  sls_mu.Lock();
  if (getBool())
    sls_mu.Unlock();
  else
    sls_mu.Unlock();
}

void sls_fun_9() {
  if (getBool())
    sls_mu.Lock();
  else
    sls_mu.Lock();
  sls_mu.Unlock();
}

void sls_fun_good_6() {
  if (getBool()) {
    sls_mu.Lock();
  } else {
    if (getBool()) {
      getBool(); // EMPTY
    } else {
      getBool(); // EMPTY
    }
    sls_mu.Lock();
  }
  sls_mu.Unlock();
}

void sls_fun_good_7() {
  sls_mu.Lock();
  while (getBool()) {
    sls_mu.Unlock();
    if (getBool()) {
      if (getBool()) {
        sls_mu.Lock();
        continue;
      }
    }
    sls_mu.Lock();
  }
  sls_mu.Unlock();
}

void sls_fun_good_8() {
  sls_mw.MyLock();
  sls_mw.mu.Unlock();
}

void sls_fun_bad_1() {
  sls_mu.Unlock(); // \
    // expected-warning{{releasing mutex 'sls_mu' that was not held}}
}

void sls_fun_bad_2() {
  sls_mu.Lock(); // expected-note{{mutex acquired here}}
  sls_mu.Lock(); // \
    // expected-warning{{acquiring mutex 'sls_mu' that is already held}}
  sls_mu.Unlock();
}

void sls_fun_bad_3() {
  sls_mu.Lock(); // expected-note {{mutex acquired here}}
} // expected-warning{{mutex 'sls_mu' is still held at the end of function}}

void sls_fun_bad_4() {
  if (getBool())
    sls_mu.Lock();  // expected-note{{mutex acquired here}}
  else
    sls_mu2.Lock(); // expected-note{{mutex acquired here}}
} // expected-warning{{mutex 'sls_mu' is not held on every path through here}}  \
  // expected-warning{{mutex 'sls_mu2' is not held on every path through here}}

void sls_fun_bad_5() {
  sls_mu.Lock(); // expected-note {{mutex acquired here}}
  if (getBool())
    sls_mu.Unlock();
} // expected-warning{{mutex 'sls_mu' is not held on every path through here}}

void sls_fun_bad_6() {
  if (getBool()) {
    sls_mu.Lock(); // expected-note {{mutex acquired here}}
  } else {
    if (getBool()) {
      getBool(); // EMPTY
    } else {
      getBool(); // EMPTY
    }
  }
  sls_mu.Unlock(); // \
    expected-warning{{mutex 'sls_mu' is not held on every path through here}}\
    expected-warning{{releasing mutex 'sls_mu' that was not held}}
}

void sls_fun_bad_7() {
  sls_mu.Lock();
  while (getBool()) { // \
        expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}}
    sls_mu.Unlock();
    if (getBool()) {
      if (getBool()) {
        continue;
      }
    }
    sls_mu.Lock(); // expected-note {{mutex acquired here}}
  }
  sls_mu.Unlock();
}

void sls_fun_bad_8() {
  sls_mu.Lock(); // expected-note{{mutex acquired here}}

  do {
    sls_mu.Unlock(); // expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}}
  } while (getBool());
}

void sls_fun_bad_9() {
  do {
    sls_mu.Lock();  // \
      // expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}} \
      // expected-note{{mutex acquired here}}
  } while (getBool());
  sls_mu.Unlock();
}

void sls_fun_bad_10() {
  sls_mu.Lock();  // expected-note 2{{mutex acquired here}}
  while(getBool()) {  // expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}}
    sls_mu.Unlock();
  }
} // expected-warning{{mutex 'sls_mu' is still held at the end of function}}

void sls_fun_bad_11() {
  while (getBool()) { // \
      expected-warning{{expecting mutex 'sls_mu' to be held at start of each loop}}
    sls_mu.Lock(); // expected-note {{mutex acquired here}}
  }
  sls_mu.Unlock(); // \
    // expected-warning{{releasing mutex 'sls_mu' that was not held}}
}

void sls_fun_bad_12() {
  sls_mu.Lock(); // expected-note {{mutex acquired here}}
  while (getBool()) {
    sls_mu.Unlock();
    if (getBool()) {
      if (getBool()) {
        break;
      }
    }
    sls_mu.Lock();
  }
  sls_mu.Unlock(); // \
    expected-warning{{mutex 'sls_mu' is not held on every path through here}} \
    expected-warning{{releasing mutex 'sls_mu' that was not held}}
}

//-----------------------------------------//
// Handling lock expressions in attribute args
// -------------------------------------------//

Mutex aa_mu;

class GlobalLocker {
public:
  void globalLock() EXCLUSIVE_LOCK_FUNCTION(aa_mu);
  void globalUnlock() UNLOCK_FUNCTION(aa_mu);
};

GlobalLocker glock;

void aa_fun_1() {
  glock.globalLock();
  glock.globalUnlock();
}

void aa_fun_bad_1() {
  glock.globalUnlock(); // \
    // expected-warning{{releasing mutex 'aa_mu' that was not held}}
}

void aa_fun_bad_2() {
  glock.globalLock(); // expected-note{{mutex acquired here}}
  glock.globalLock(); // \
    // expected-warning{{acquiring mutex 'aa_mu' that is already held}}
  glock.globalUnlock();
}

void aa_fun_bad_3() {
  glock.globalLock(); // expected-note{{mutex acquired here}}
} // expected-warning{{mutex 'aa_mu' is still held at the end of function}}

//--------------------------------------------------//
// Regression tests for unusual method names
//--------------------------------------------------//

Mutex wmu;

// Test diagnostics for other method names.
class WeirdMethods {
  // FIXME: can't currently check inside constructors and destructors.
  WeirdMethods() {
    wmu.Lock(); // EXPECTED-NOTE {{mutex acquired here}}
  } // EXPECTED-WARNING {{mutex 'wmu' is still held at the end of function}}
  ~WeirdMethods() {
    wmu.Lock(); // EXPECTED-NOTE {{mutex acquired here}}
  } // EXPECTED-WARNING {{mutex 'wmu' is still held at the end of function}}
  void operator++() {
    wmu.Lock(); // expected-note {{mutex acquired here}}
  } // expected-warning {{mutex 'wmu' is still held at the end of function}}
  operator int*() {
    wmu.Lock(); // expected-note {{mutex acquired here}}
    return 0;
  } // expected-warning {{mutex 'wmu' is still held at the end of function}}
};

//-----------------------------------------------//
// Errors for guarded by or guarded var variables
// ----------------------------------------------//

int *pgb_gvar __attribute__((pt_guarded_var));
int *pgb_var __attribute__((pt_guarded_by(sls_mu)));

class PGBFoo {
 public:
  int x;
  int *pgb_field __attribute__((guarded_by(sls_mu2)))
                 __attribute__((pt_guarded_by(sls_mu)));
  void testFoo() {
    pgb_field = &x; // \
      // expected-warning {{writing variable 'pgb_field' requires holding mutex 'sls_mu2' exclusively}}
    *pgb_field = x; // expected-warning {{reading variable 'pgb_field' requires holding mutex 'sls_mu2'}} \
      // expected-warning {{writing the value pointed to by 'pgb_field' requires holding mutex 'sls_mu' exclusively}}
    x = *pgb_field; // expected-warning {{reading variable 'pgb_field' requires holding mutex 'sls_mu2'}} \
      // expected-warning {{reading the value pointed to by 'pgb_field' requires holding mutex 'sls_mu'}}
    (*pgb_field)++; // expected-warning {{reading variable 'pgb_field' requires holding mutex 'sls_mu2'}} \
      // expected-warning {{writing the value pointed to by 'pgb_field' requires holding mutex 'sls_mu' exclusively}}
  }
};

class GBFoo {
 public:
  int gb_field __attribute__((guarded_by(sls_mu)));

  void testFoo() {
    gb_field = 0; // \
      // expected-warning {{writing variable 'gb_field' requires holding mutex 'sls_mu' exclusively}}
  }

  void testNoAnal() NO_THREAD_SAFETY_ANALYSIS {
    gb_field = 0;
  }
};

GBFoo GlobalGBFoo __attribute__((guarded_by(sls_mu)));

void gb_fun_0() {
  sls_mu.Lock();
  int x = *pgb_var;
  sls_mu.Unlock();
}

void gb_fun_1() {
  sls_mu.Lock();
  *pgb_var = 2;
  sls_mu.Unlock();
}

void gb_fun_2() {
  int x;
  pgb_var = &x;
}

void gb_fun_3() {
  int *x = pgb_var;
}

void gb_bad_0() {
  sls_guard_var = 1; // \
    // expected-warning{{writing variable 'sls_guard_var' requires holding any mutex exclusively}}
}

void gb_bad_1() {
  int x = sls_guard_var; // \
    // expected-warning{{reading variable 'sls_guard_var' requires holding any mutex}}
}

void gb_bad_2() {
  sls_guardby_var = 1; // \
    // expected-warning {{writing variable 'sls_guardby_var' requires holding mutex 'sls_mu' exclusively}}
}

void gb_bad_3() {
  int x = sls_guardby_var; // \
    // expected-warning {{reading variable 'sls_guardby_var' requires holding mutex 'sls_mu'}}
}

void gb_bad_4() {
  *pgb_gvar = 1; // \
    // expected-warning {{writing the value pointed to by 'pgb_gvar' requires holding any mutex exclusively}}
}

void gb_bad_5() {
  int x = *pgb_gvar; // \
    // expected-warning {{reading the value pointed to by 'pgb_gvar' requires holding any mutex}}
}

void gb_bad_6() {
  *pgb_var = 1; // \
    // expected-warning {{writing the value pointed to by 'pgb_var' requires holding mutex 'sls_mu' exclusively}}
}

void gb_bad_7() {
  int x = *pgb_var; // \
    // expected-warning {{reading the value pointed to by 'pgb_var' requires holding mutex 'sls_mu'}}
}

void gb_bad_8() {
  GBFoo G;
  G.gb_field = 0; // \
    // expected-warning {{writing variable 'gb_field' requires holding mutex 'sls_mu'}}
}

void gb_bad_9() {
  sls_guard_var++; // \
    // expected-warning{{writing variable 'sls_guard_var' requires holding any mutex exclusively}}
  sls_guard_var--; // \
    // expected-warning{{writing variable 'sls_guard_var' requires holding any mutex exclusively}}
  ++sls_guard_var; // \
    // expected-warning{{writing variable 'sls_guard_var' requires holding any mutex exclusively}}
  --sls_guard_var;// \
    // expected-warning{{writing variable 'sls_guard_var' requires holding any mutex exclusively}}
}

//-----------------------------------------------//
// Warnings on variables with late parsed attributes
// ----------------------------------------------//

class LateFoo {
public:
  int a __attribute__((guarded_by(mu)));
  int b;

  void foo() EXCLUSIVE_LOCKS_REQUIRED(mu) { }

  void test() {
    a = 0; // \
      // expected-warning{{writing variable 'a' requires holding mutex 'mu' exclusively}}
    b = a; // \
      // expected-warning {{reading variable 'a' requires holding mutex 'mu'}}
    c = 0; // \
      // expected-warning {{writing variable 'c' requires holding mutex 'mu' exclusively}}
  }

  int c __attribute__((guarded_by(mu)));

  Mutex mu;
};

class LateBar {
 public:
  int a_ __attribute__((guarded_by(mu1_)));
  int b_;
  int *q __attribute__((pt_guarded_by(mu)));
  Mutex mu1_;
  Mutex mu;
  LateFoo Foo;
  LateFoo Foo2;
  LateFoo *FooPointer;
};

LateBar b1, *b3;

void late_0() {
  LateFoo FooA;
  LateFoo FooB;
  FooA.mu.Lock();
  FooA.a = 5;
  FooA.mu.Unlock();
}

void late_1() {
  LateBar BarA;
  BarA.FooPointer->mu.Lock();
  BarA.FooPointer->a = 2;
  BarA.FooPointer->mu.Unlock();
}

void late_bad_0() {
  LateFoo fooA;
  LateFoo fooB;
  fooA.mu.Lock();
  fooB.a = 5; // \
    // expected-warning{{writing variable 'a' requires holding mutex 'fooB.mu' exclusively}} \
    // expected-note{{found near match 'fooA.mu'}}
  fooA.mu.Unlock();
}

void late_bad_1() {
  Mutex mu;
  mu.Lock();
  b1.mu1_.Lock();
  int res = b1.a_ + b3->b_;
  b3->b_ = *b1.q; // \
    // expected-warning{{reading the value pointed to by 'q' requires holding mutex 'b1.mu'}}
  b1.mu1_.Unlock();
  b1.b_ = res;
  mu.Unlock();
}

void late_bad_2() {
  LateBar BarA;
  BarA.FooPointer->mu.Lock();
  BarA.Foo.a = 2; // \
    // expected-warning{{writing variable 'a' requires holding mutex 'BarA.Foo.mu' exclusively}} \
    // expected-note{{found near match 'BarA.FooPointer->mu'}}
  BarA.FooPointer->mu.Unlock();
}

void late_bad_3() {
  LateBar BarA;
  BarA.Foo.mu.Lock();
  BarA.FooPointer->a = 2; // \
    // expected-warning{{writing variable 'a' requires holding mutex 'BarA.FooPointer->mu' exclusively}} \
    // expected-note{{found near match 'BarA.Foo.mu'}}
  BarA.Foo.mu.Unlock();
}

void late_bad_4() {
  LateBar BarA;
  BarA.Foo.mu.Lock();
  BarA.Foo2.a = 2; // \
    // expected-warning{{writing variable 'a' requires holding mutex 'BarA.Foo2.mu' exclusively}} \
    // expected-note{{found near match 'BarA.Foo.mu'}}
  BarA.Foo.mu.Unlock();
}

//-----------------------------------------------//
// Extra warnings for shared vs. exclusive locks
// ----------------------------------------------//

void shared_fun_0() {
  sls_mu.Lock();
  do {
    sls_mu.Unlock();
    sls_mu.Lock();
  } while (getBool());
  sls_mu.Unlock();
}

void shared_fun_1() {
  sls_mu.ReaderLock(); // \
    // expected-note {{the other acquisition of mutex 'sls_mu' is here}}
  do {
    sls_mu.Unlock();
    sls_mu.Lock();  // \
      // expected-warning {{mutex 'sls_mu' is acquired exclusively and shared in the same scope}}
  } while (getBool());
  sls_mu.Unlock();
}

void shared_fun_3() {
  if (getBool())
    sls_mu.Lock();
  else
    sls_mu.Lock();
  *pgb_var = 1;
  sls_mu.Unlock();
}

void shared_fun_4() {
  if (getBool())
    sls_mu.ReaderLock();
  else
    sls_mu.ReaderLock();
  int x = sls_guardby_var;
  sls_mu.Unlock();
}

void shared_fun_8() {
  if (getBool())
    sls_mu.Lock(); // \
      // expected-warning {{mutex 'sls_mu' is acquired exclusively and shared in the same scope}}
  else
    sls_mu.ReaderLock(); // \
      // expected-note {{the other acquisition of mutex 'sls_mu' is here}}
  sls_mu.Unlock();
}

void shared_fun_9() {
  sls_mu.Lock();
  sls_mu.ExclusiveUnlock();

  sls_mu.ReaderLock();
  sls_mu.ReaderUnlock();
}

void shared_fun_10() {
  sls_mu.Lock();
  sls_mu.DemoteExclusive();
  sls_mu.ReaderUnlock();
}

void shared_fun_11() {
  sls_mu.ReaderLock();
  sls_mu.PromoteShared();
  sls_mu.Unlock();
}

void shared_bad_0() {
  sls_mu.Lock();  // \
    // expected-note {{the other acquisition of mutex 'sls_mu' is here}}
  do {
    sls_mu.Unlock();
    sls_mu.ReaderLock();  // \
      // expected-warning {{mutex 'sls_mu' is acquired exclusively and shared in the same scope}}
  } while (getBool());
  sls_mu.Unlock();
}

void shared_bad_1() {
  if (getBool())
    sls_mu.Lock(); // \
      // expected-warning {{mutex 'sls_mu' is acquired exclusively and shared in the same scope}}
  else
    sls_mu.ReaderLock(); // \
      // expected-note {{the other acquisition of mutex 'sls_mu' is here}}
  *pgb_var = 1;
  sls_mu.Unlock();
}

void shared_bad_2() {
  if (getBool())
    sls_mu.ReaderLock(); // \
      // expected-warning {{mutex 'sls_mu' is acquired exclusively and shared in the same scope}}
  else
    sls_mu.Lock(); // \
      // expected-note {{the other acquisition of mutex 'sls_mu' is here}}
  *pgb_var = 1;
  sls_mu.Unlock();
}

void shared_bad_3() {
  sls_mu.Lock();         // expected-note {{mutex acquired here}}
  sls_mu.ReaderUnlock(); // \
    // expected-warning {{releasing mutex 'sls_mu' using shared access, expected exclusive access}}
}

void shared_bad_4() {
  sls_mu.ReaderLock();      // expected-note {{mutex acquired here}}
  sls_mu.ExclusiveUnlock(); // \
    // expected-warning {{releasing mutex 'sls_mu' using exclusive access, expected shared access}}
}

void shared_bad_5() {
  sls_mu.Lock();          // expected-note {{mutex acquired here}}
  sls_mu.PromoteShared(); // \
    // expected-warning {{releasing mutex 'sls_mu' using shared access, expected exclusive access}}
  sls_mu.ExclusiveUnlock();
}

void shared_bad_6() {
  sls_mu.ReaderLock();      // expected-note {{mutex acquired here}}
  sls_mu.DemoteExclusive(); // \
    // expected-warning {{releasing mutex 'sls_mu' using exclusive access, expected shared access}}
  sls_mu.ReaderUnlock();
}

// FIXME: Add support for functions (not only methods)
class LRBar {
 public:
  void aa_elr_fun() EXCLUSIVE_LOCKS_REQUIRED(aa_mu);
  void aa_elr_fun_s() SHARED_LOCKS_REQUIRED(aa_mu);
  void le_fun() __attribute__((locks_excluded(sls_mu)));
};

class LRFoo {
 public:
  void test() EXCLUSIVE_LOCKS_REQUIRED(sls_mu);
  void testShared() SHARED_LOCKS_REQUIRED(sls_mu2);
};

void elr_fun() EXCLUSIVE_LOCKS_REQUIRED(sls_mu);
void elr_fun() {}

LRFoo MyLRFoo;
LRBar Bar;

void es_fun_0() {
  aa_mu.Lock();
  Bar.aa_elr_fun();
  aa_mu.Unlock();
}

void es_fun_1() {
  aa_mu.Lock();
  Bar.aa_elr_fun_s();
  aa_mu.Unlock();
}

void es_fun_2() {
  aa_mu.ReaderLock();
  Bar.aa_elr_fun_s();
  aa_mu.Unlock();
}

void es_fun_3() {
  sls_mu.Lock();
  MyLRFoo.test();
  sls_mu.Unlock();
}

void es_fun_4() {
  sls_mu2.Lock();
  MyLRFoo.testShared();
  sls_mu2.Unlock();
}

void es_fun_5() {
  sls_mu2.ReaderLock();
  MyLRFoo.testShared();
  sls_mu2.Unlock();
}

void es_fun_6() {
  Bar.le_fun();
}

void es_fun_7() {
  sls_mu.Lock();
  elr_fun();
  sls_mu.Unlock();
}

void es_fun_8() NO_THREAD_SAFETY_ANALYSIS;

void es_fun_8() {
  Bar.aa_elr_fun_s();
}

void es_fun_9() SHARED_LOCKS_REQUIRED(aa_mu);
void es_fun_9() {
  Bar.aa_elr_fun_s();
}

void es_fun_10() EXCLUSIVE_LOCKS_REQUIRED(aa_mu);
void es_fun_10() {
  Bar.aa_elr_fun_s();
}

void es_bad_0() {
  Bar.aa_elr_fun(); // \
    // expected-warning {{calling function 'aa_elr_fun' requires holding mutex 'aa_mu' exclusively}}
}

void es_bad_1() {
  aa_mu.ReaderLock();
  Bar.aa_elr_fun(); // \
    // expected-warning {{calling function 'aa_elr_fun' requires holding mutex 'aa_mu' exclusively}}
  aa_mu.Unlock();
}

void es_bad_2() {
  Bar.aa_elr_fun_s(); // \
    // expected-warning {{calling function 'aa_elr_fun_s' requires holding mutex 'aa_mu'}}
}

void es_bad_3() {
  MyLRFoo.test(); // \
    // expected-warning {{calling function 'test' requires holding mutex 'sls_mu' exclusively}}
}

void es_bad_4() {
  MyLRFoo.testShared(); // \
    // expected-warning {{calling function 'testShared' requires holding mutex 'sls_mu2'}}
}

void es_bad_5() {
  sls_mu.ReaderLock();
  MyLRFoo.test(); // \
    // expected-warning {{calling function 'test' requires holding mutex 'sls_mu' exclusively}}
  sls_mu.Unlock();
}

void es_bad_6() {
  sls_mu.Lock();
  Bar.le_fun(); // \
    // expected-warning {{cannot call function 'le_fun' while mutex 'sls_mu' is held}}
  sls_mu.Unlock();
}

void es_bad_7() {
  sls_mu.ReaderLock();
  Bar.le_fun(); // \
    // expected-warning {{cannot call function 'le_fun' while mutex 'sls_mu' is held}}
  sls_mu.Unlock();
}


//-----------------------------------------------//
// Unparseable lock expressions
// ----------------------------------------------//

// FIXME -- derive new tests for unhandled expressions


//----------------------------------------------------------------------------//
// The following test cases are ported from the gcc thread safety implementation
// They are each wrapped inside a namespace with the test number of the gcc test
//
// FIXME: add all the gcc tests, once this analysis passes them.
//----------------------------------------------------------------------------//

//-----------------------------------------//
// Good testcases (no errors)
//-----------------------------------------//

namespace thread_annot_lock_20 {
class Bar {
 public:
  static int func1() EXCLUSIVE_LOCKS_REQUIRED(mu1_);
  static int b_ GUARDED_BY(mu1_);
  static Mutex mu1_;
  static int a_ GUARDED_BY(mu1_);
};

Bar b1;

int Bar::func1()
{
  int res = 5;

  if (a_ == 4)
    res = b_;
  return res;
}
} // end namespace thread_annot_lock_20

namespace thread_annot_lock_22 {
// Test various usage of GUARDED_BY and PT_GUARDED_BY annotations, especially
// uses in class definitions.
Mutex mu;

class Bar {
 public:
  int a_ GUARDED_BY(mu1_);
  int b_;
  int *q PT_GUARDED_BY(mu);
  Mutex mu1_ ACQUIRED_AFTER(mu);
};

Bar b1, *b3;
int *p GUARDED_BY(mu) PT_GUARDED_BY(mu);
int res GUARDED_BY(mu) = 5;

int func(int i)
{
  int x;
  mu.Lock();
  b1.mu1_.Lock();
  res = b1.a_ + b3->b_;
  *p = i;
  b1.a_ = res + b3->b_;
  b3->b_ = *b1.q;
  b1.mu1_.Unlock();
  b1.b_ = res;
  x = res;
  mu.Unlock();
  return x;
}
} // end namespace thread_annot_lock_22

namespace thread_annot_lock_27_modified {
// test lock annotations applied to function definitions
// Modified: applied annotations only to function declarations
Mutex mu1;
Mutex mu2 ACQUIRED_AFTER(mu1);

class Foo {
 public:
  int method1(int i) SHARED_LOCKS_REQUIRED(mu2) EXCLUSIVE_LOCKS_REQUIRED(mu1);
};

int Foo::method1(int i) {
  return i;
}


int foo(int i) EXCLUSIVE_LOCKS_REQUIRED(mu2) SHARED_LOCKS_REQUIRED(mu1);
int foo(int i) {
  return i;
}

static int bar(int i) EXCLUSIVE_LOCKS_REQUIRED(mu1);
static int bar(int i) {
  return i;
}

void main() {
  Foo a;

  mu1.Lock();
  mu2.Lock();
  a.method1(1);
  foo(2);
  mu2.Unlock();
  bar(3);
  mu1.Unlock();
}
} // end namespace thread_annot_lock_27_modified


namespace thread_annot_lock_38 {
// Test the case where a template member function is annotated with lock
// attributes in a non-template class.
class Foo {
 public:
  void func1(int y) LOCKS_EXCLUDED(mu_);
  template <typename T> void func2(T x) LOCKS_EXCLUDED(mu_);
 private:
  Mutex mu_;
};

Foo *foo;

void main()
{
  foo->func1(5);
  foo->func2(5);
}
} // end namespace thread_annot_lock_38

namespace thread_annot_lock_43 {
// Tests lock canonicalization
class Foo {
 public:
  Mutex *mu_;
};

class FooBar {
 public:
  Foo *foo_;
  int GetA() EXCLUSIVE_LOCKS_REQUIRED(foo_->mu_) { return a_; }
  int a_ GUARDED_BY(foo_->mu_);
};

FooBar *fb;

void main()
{
  int x;
  fb->foo_->mu_->Lock();
  x = fb->GetA();
  fb->foo_->mu_->Unlock();
}
} // end namespace thread_annot_lock_43

namespace thread_annot_lock_49 {
// Test the support for use of lock expression in the annotations
class Foo {
 public:
  Mutex foo_mu_;
};

class Bar {
 private:
  Foo *foo;
  Mutex bar_mu_ ACQUIRED_AFTER(foo->foo_mu_);

 public:
  void Test1() {
    foo->foo_mu_.Lock();
    bar_mu_.Lock();
    bar_mu_.Unlock();
    foo->foo_mu_.Unlock();
  }
};

void main() {
  Bar bar;
  bar.Test1();
}
} // end namespace thread_annot_lock_49

namespace thread_annot_lock_61_modified {
  // Modified to fix the compiler errors
  // Test the fix for a bug introduced by the support of pass-by-reference
  // parameters.
  struct Foo { Foo &operator<< (bool) {return *this;} };
  Foo &getFoo();
  struct Bar { Foo &func () {return getFoo();} };
  struct Bas { void operator& (Foo &) {} };
  void mumble()
  {
    Bas() & Bar().func() << "" << "";
    Bas() & Bar().func() << "";
  }
} // end namespace thread_annot_lock_61_modified


namespace thread_annot_lock_65 {
// Test the fix for a bug in the support of allowing reader locks for
// non-const, non-modifying overload functions. (We didn't handle the builtin
// properly.)
enum MyFlags {
  Zero,
  One,
  Two,
  Three,
  Four,
  Five,
  Six,
  Seven,
  Eight,
  Nine
};

inline MyFlags
operator|(MyFlags a, MyFlags b)
{
  return MyFlags(static_cast<int>(a) | static_cast<int>(b));
}

inline MyFlags&
operator|=(MyFlags& a, MyFlags b)
{
    return a = a | b;
}
} // end namespace thread_annot_lock_65

namespace thread_annot_lock_66_modified {
// Modified: Moved annotation to function defn
// Test annotations on out-of-line definitions of member functions where the
// annotations refer to locks that are also data members in the class.
Mutex mu;

class Foo {
 public:
  int method1(int i) SHARED_LOCKS_REQUIRED(mu1, mu, mu2);
  int data GUARDED_BY(mu1);
  Mutex *mu1;
  Mutex *mu2;
};

int Foo::method1(int i)
{
  return data + i;
}

void main()
{
  Foo a;

  a.mu2->Lock();
  a.mu1->Lock();
  mu.Lock();
  a.method1(1);
  mu.Unlock();
  a.mu1->Unlock();
  a.mu2->Unlock();
}
} // end namespace thread_annot_lock_66_modified

namespace thread_annot_lock_68_modified {
// Test a fix to a bug in the delayed name binding with nested template
// instantiation. We use a stack to make sure a name is not resolved to an
// inner context.
template <typename T>
class Bar {
  Mutex mu_;
};

template <typename T>
class Foo {
 public:
  void func(T x) {
    mu_.Lock();
    count_ = x;
    mu_.Unlock();
  }

 private:
  T count_ GUARDED_BY(mu_);
  Bar<T> bar_;
  Mutex mu_;
};

void main()
{
  Foo<int> *foo;
  foo->func(5);
}
} // end namespace thread_annot_lock_68_modified

namespace thread_annot_lock_30_modified {
// Test delay parsing of lock attribute arguments with nested classes.
// Modified: trylocks replaced with exclusive_lock_fun
int a = 0;

class Bar {
  struct Foo;

 public:
  void MyLock() EXCLUSIVE_LOCK_FUNCTION(mu);

  int func() {
    MyLock();
//    if (foo == 0) {
//      return 0;
//    }
    a = 5;
    mu.Unlock();
    return 1;
  }

  class FooBar {
    int x;
    int y;
  };

 private:
  Mutex mu;
};

Bar *bar;

void main()
{
  bar->func();
}
} // end namespace thread_annot_lock_30_modified

namespace thread_annot_lock_47 {
// Test the support for annotations on virtual functions.
// This is a good test case. (i.e. There should be no warning emitted by the
// compiler.)
class Base {
 public:
  virtual void func1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
  virtual void func2() LOCKS_EXCLUDED(mu_);
  Mutex mu_;
};

class Child : public Base {
 public:
  virtual void func1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
  virtual void func2() LOCKS_EXCLUDED(mu_);
};

void main() {
  Child *c;
  Base *b = c;

  b->mu_.Lock();
  b->func1();
  b->mu_.Unlock();
  b->func2();

  c->mu_.Lock();
  c->func1();
  c->mu_.Unlock();
  c->func2();
}
} // end namespace thread_annot_lock_47

//-----------------------------------------//
// Tests which produce errors
//-----------------------------------------//

namespace thread_annot_lock_13 {
Mutex mu1;
Mutex mu2;

int g GUARDED_BY(mu1);
int w GUARDED_BY(mu2);

class Foo {
 public:
  void bar() LOCKS_EXCLUDED(mu_, mu1);
  int foo() SHARED_LOCKS_REQUIRED(mu_) EXCLUSIVE_LOCKS_REQUIRED(mu2);

 private:
  int a_ GUARDED_BY(mu_);
 public:
  Mutex mu_ ACQUIRED_AFTER(mu1);
};

int Foo::foo()
{
  int res;
  w = 5;
  res = a_ + 5;
  return res;
}

void Foo::bar()
{
  int x;
  mu_.Lock();
  x = foo(); // expected-warning {{calling function 'foo' requires holding mutex 'mu2' exclusively}}
  a_ = x + 1;
  mu_.Unlock();
  if (x > 5) {
    mu1.Lock();
    g = 2;
    mu1.Unlock();
  }
}

void main()
{
  Foo f1, *f2;
  f1.mu_.Lock();
  f1.bar(); // expected-warning {{cannot call function 'bar' while mutex 'f1.mu_' is held}}
  mu2.Lock();
  f1.foo();
  mu2.Unlock();
  f1.mu_.Unlock();
  f2->mu_.Lock();
  f2->bar(); // expected-warning {{cannot call function 'bar' while mutex 'f2->mu_' is held}}
  f2->mu_.Unlock();
  mu2.Lock();
  w = 2;
  mu2.Unlock();
}
} // end namespace thread_annot_lock_13

namespace thread_annot_lock_18_modified {
// Modified: Trylocks removed
// Test the ability to distnguish between the same lock field of
// different objects of a class.
  class Bar {
 public:
  bool MyLock() EXCLUSIVE_LOCK_FUNCTION(mu1_);
  void MyUnlock() UNLOCK_FUNCTION(mu1_);
  int a_ GUARDED_BY(mu1_);

 private:
  Mutex mu1_;
};

Bar *b1, *b2;

void func()
{
  b1->MyLock();
  b1->a_ = 5;
  b2->a_ = 3; // \
    // expected-warning {{writing variable 'a_' requires holding mutex 'b2->mu1_' exclusively}} \
    // expected-note {{found near match 'b1->mu1_'}}
  b2->MyLock();
  b2->MyUnlock();
  b1->MyUnlock();
}
} // end namespace thread_annot_lock_18_modified

namespace thread_annot_lock_21 {
// Test various usage of GUARDED_BY and PT_GUARDED_BY annotations, especially
// uses in class definitions.
Mutex mu;

class Bar {
 public:
  int a_ GUARDED_BY(mu1_);
  int b_;
  int *q PT_GUARDED_BY(mu);
  Mutex mu1_ ACQUIRED_AFTER(mu);
};

Bar b1, *b3;
int *p GUARDED_BY(mu) PT_GUARDED_BY(mu);

int res GUARDED_BY(mu) = 5;

int func(int i)
{
  int x;
  b3->mu1_.Lock();
  res = b1.a_ + b3->b_; // expected-warning {{reading variable 'a_' requires holding mutex 'b1.mu1_'}} \
    // expected-warning {{writing variable 'res' requires holding mutex 'mu' exclusively}} \
    // expected-note {{found near match 'b3->mu1_'}}
  *p = i; // expected-warning {{reading variable 'p' requires holding mutex 'mu'}} \
    // expected-warning {{writing the value pointed to by 'p' requires holding mutex 'mu' exclusively}}
  b1.a_ = res + b3->b_; // expected-warning {{reading variable 'res' requires holding mutex 'mu'}} \
    // expected-warning {{writing variable 'a_' requires holding mutex 'b1.mu1_' exclusively}} \
    // expected-note {{found near match 'b3->mu1_'}}
  b3->b_ = *b1.q; // expected-warning {{reading the value pointed to by 'q' requires holding mutex 'mu'}}
  b3->mu1_.Unlock();
  b1.b_ = res; // expected-warning {{reading variable 'res' requires holding mutex 'mu'}}
  x = res; // expected-warning {{reading variable 'res' requires holding mutex 'mu'}}
  return x;
}
} // end namespace thread_annot_lock_21

namespace thread_annot_lock_35_modified {
// Test the analyzer's ability to distinguish the lock field of different
// objects.
class Foo {
 private:
  Mutex lock_;
  int a_ GUARDED_BY(lock_);

 public:
  void Func(Foo* child) LOCKS_EXCLUDED(lock_) {
     Foo *new_foo = new Foo;

     lock_.Lock();

     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 holding mutex 'child->lock_' exclusively}} \
       // expected-note {{found near match 'lock_'}}
     child->a_ = 5; // \
       // expected-warning {{writing variable 'a_' requires holding mutex 'child->lock_' exclusively}} \
       // expected-note {{found near match 'lock_'}}
     lock_.Unlock();
  }

  void bar(int y) EXCLUSIVE_LOCKS_REQUIRED(lock_) {
    a_ = y;
  }
};

Foo *x;

void main() {
  Foo *child = new Foo;
  x->Func(child);
}
} // end namespace thread_annot_lock_35_modified

namespace thread_annot_lock_36_modified {
// Modified to move the annotations to function defns.
// Test the analyzer's ability to distinguish the lock field of different
// objects
class Foo {
 private:
  Mutex lock_;
  int a_ GUARDED_BY(lock_);

 public:
  void Func(Foo* child) LOCKS_EXCLUDED(lock_);
  void bar(int y) EXCLUSIVE_LOCKS_REQUIRED(lock_);
};

void Foo::Func(Foo* child) {
  Foo *new_foo = new Foo;

  lock_.Lock();

  child->lock_.Lock();
  child->Func(new_foo); // expected-warning {{cannot call function 'Func' while mutex 'child->lock_' is held}}
  child->bar(7);
  child->a_ = 5;
  child->lock_.Unlock();

  lock_.Unlock();
}

void Foo::bar(int y) {
  a_ = y;
}


Foo *x;

void main() {
  Foo *child = new Foo;
  x->Func(child);
}
} // end namespace thread_annot_lock_36_modified


namespace thread_annot_lock_42 {
// Test support of multiple lock attributes of the same kind on a decl.
class Foo {
 private:
  Mutex mu1, mu2, mu3;
  int x GUARDED_BY(mu1) GUARDED_BY(mu2);
  int y GUARDED_BY(mu2);

  void f2() LOCKS_EXCLUDED(mu1) LOCKS_EXCLUDED(mu2) LOCKS_EXCLUDED(mu3) {
    mu2.Lock();
    y = 2;
    mu2.Unlock();
  }

 public:
  void f1() EXCLUSIVE_LOCKS_REQUIRED(mu2) EXCLUSIVE_LOCKS_REQUIRED(mu1) {
    x = 5;
    f2(); // expected-warning {{cannot call function 'f2' while mutex 'mu1' is held}} \
      // expected-warning {{cannot call function 'f2' while mutex 'mu2' is held}}
  }
};

Foo *foo;

void func()
{
  foo->f1(); // expected-warning {{calling function 'f1' requires holding mutex 'foo->mu2' exclusively}} \
             // expected-warning {{calling function 'f1' requires holding mutex 'foo->mu1' exclusively}}
}
} // end namespace thread_annot_lock_42

namespace thread_annot_lock_46 {
// Test the support for annotations on virtual functions.
class Base {
 public:
  virtual void func1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
  virtual void func2() LOCKS_EXCLUDED(mu_);
  Mutex mu_;
};

class Child : public Base {
 public:
  virtual void func1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
  virtual void func2() LOCKS_EXCLUDED(mu_);
};

void main() {
  Child *c;
  Base *b = c;

  b->func1(); // expected-warning {{calling function 'func1' requires holding mutex 'b->mu_' exclusively}}
  b->mu_.Lock();
  b->func2(); // expected-warning {{cannot call function 'func2' while mutex 'b->mu_' is held}}
  b->mu_.Unlock();

  c->func1(); // expected-warning {{calling function 'func1' requires holding mutex 'c->mu_' exclusively}}
  c->mu_.Lock();
  c->func2(); // expected-warning {{cannot call function 'func2' while mutex 'c->mu_' is held}}
  c->mu_.Unlock();
}
} // end namespace thread_annot_lock_46

namespace thread_annot_lock_67_modified {
// Modified: attributes on definitions moved to declarations
// Test annotations on out-of-line definitions of member functions where the
// annotations refer to locks that are also data members in the class.
Mutex mu;
Mutex mu3;

class Foo {
 public:
  int method1(int i) SHARED_LOCKS_REQUIRED(mu1, mu, mu2, mu3);
  int data GUARDED_BY(mu1);
  Mutex *mu1;
  Mutex *mu2;
};

int Foo::method1(int i) {
  return data + i;
}

void main()
{
  Foo a;
  a.method1(1); // expected-warning {{calling function 'method1' requires holding mutex 'a.mu1'}} \
    // expected-warning {{calling function 'method1' requires holding mutex 'mu'}} \
    // expected-warning {{calling function 'method1' requires holding mutex 'a.mu2'}} \
    // expected-warning {{calling function 'method1' requires holding mutex 'mu3'}}
}
} // end namespace thread_annot_lock_67_modified


namespace substitution_test {
  class MyData  {
  public:
    Mutex mu;

    void lockData()    EXCLUSIVE_LOCK_FUNCTION(mu);
    void unlockData()  UNLOCK_FUNCTION(mu);

    void doSomething() EXCLUSIVE_LOCKS_REQUIRED(mu)  { }
  };


  class DataLocker {
  public:
    void lockData  (MyData *d) EXCLUSIVE_LOCK_FUNCTION(d->mu);
    void unlockData(MyData *d) UNLOCK_FUNCTION(d->mu);
  };


  class Foo {
  public:
    void foo(MyData* d) EXCLUSIVE_LOCKS_REQUIRED(d->mu) { }

    void bar1(MyData* d) {
      d->lockData();
      foo(d);
      d->unlockData();
    }

    void bar2(MyData* d) {
      DataLocker dlr;
      dlr.lockData(d);
      foo(d);
      dlr.unlockData(d);
    }

    void bar3(MyData* d1, MyData* d2) {
      DataLocker dlr;
      dlr.lockData(d1);   // expected-note {{mutex acquired here}}
      dlr.unlockData(d2); // \
        // expected-warning {{releasing mutex 'd2->mu' that was not held}}
    } // expected-warning {{mutex 'd1->mu' is still held at the end of function}}

    void bar4(MyData* d1, MyData* d2) {
      DataLocker dlr;
      dlr.lockData(d1);
      foo(d2); // \
        // expected-warning {{calling function 'foo' requires holding mutex 'd2->mu' exclusively}} \
        // expected-note {{found near match 'd1->mu'}}
      dlr.unlockData(d1);
    }
  };
} // end namespace substituation_test



namespace constructor_destructor_tests {
  Mutex fooMu;
  int myVar GUARDED_BY(fooMu);

  class Foo {
  public:
    Foo()  EXCLUSIVE_LOCK_FUNCTION(fooMu) { }
    ~Foo() UNLOCK_FUNCTION(fooMu) { }
  };

  void fooTest() {
    Foo foo;
    myVar = 0;
  }
}


namespace template_member_test {

  struct S { int n; };
  struct T {
    Mutex m;
    S *s GUARDED_BY(this->m);
  };
  Mutex m;
  struct U {
    union {
      int n;
    };
  } *u GUARDED_BY(m);

  template<typename U>
  struct IndirectLock {
    int DoNaughtyThings(T *t) {
      u->n = 0; // expected-warning {{reading variable 'u' requires holding mutex 'm'}}
      return t->s->n; // expected-warning {{reading variable 's' requires holding mutex 't->m'}}
    }
  };

  template struct IndirectLock<int>; // expected-note {{here}}

  struct V {
    void f(int);
    void f(double);

    Mutex m;
    V *p GUARDED_BY(this->m);
  };
  template<typename U> struct W {
    V v;
    void f(U u) {
      v.p->f(u); // expected-warning {{reading variable 'p' requires holding mutex 'v.m'}}
    }
  };
  template struct W<int>; // expected-note {{here}}

}

namespace test_scoped_lockable {

struct TestScopedLockable {
  Mutex mu1;
  Mutex mu2;
  int a __attribute__((guarded_by(mu1)));
  int b __attribute__((guarded_by(mu2)));

  bool getBool();

  void foo1() {
    MutexLock mulock(&mu1);
    a = 5;
  }

  void foo2() {
    ReaderMutexLock mulock1(&mu1);
    if (getBool()) {
      MutexLock mulock2a(&mu2);
      b = a + 1;
    }
    else {
      MutexLock mulock2b(&mu2);
      b = a + 2;
    }
  }

  void foo3() {
    MutexLock mulock_a(&mu1); // expected-note{{mutex acquired here}}
    MutexLock mulock_b(&mu1); // \
      // expected-warning {{acquiring mutex 'mu1' that is already held}}
  }

  void foo4() {
    MutexLock mulock1(&mu1), mulock2(&mu2);
    a = b+1;
    b = a+1;
  }

  void foo5() {
    DoubleMutexLock mulock(&mu1, &mu2);
    a = b + 1;
    b = a + 1;
  }
};

} // end namespace test_scoped_lockable


namespace FunctionAttrTest {

class Foo {
public:
  Mutex mu_;
  int a GUARDED_BY(mu_);
};

Foo fooObj;

void foo() EXCLUSIVE_LOCKS_REQUIRED(fooObj.mu_);

void bar() {
  foo();  // expected-warning {{calling function 'foo' requires holding mutex 'fooObj.mu_' exclusively}}
  fooObj.mu_.Lock();
  foo();
  fooObj.mu_.Unlock();
}

};  // end namespace FunctionAttrTest


namespace TryLockTest {

struct TestTryLock {
  Mutex mu;
  int a GUARDED_BY(mu);
  bool cond;

  void foo1() {
    if (mu.TryLock()) {
      a = 1;
      mu.Unlock();
    }
  }

  void foo2() {
    if (!mu.TryLock()) return;
    a = 2;
    mu.Unlock();
  }

  void foo2_builtin_expect() {
    if (__builtin_expect(!mu.TryLock(), false))
      return;
    a = 2;
    mu.Unlock();
  }

  void foo3() {
    bool b = mu.TryLock();
    if (b) {
      a = 3;
      mu.Unlock();
    }
  }

  void foo3_builtin_expect() {
    bool b = mu.TryLock();
    if (__builtin_expect(b, true)) {
      a = 3;
      mu.Unlock();
    }
  }

  void foo4() {
    bool b = mu.TryLock();
    if (!b) return;
    a = 4;
    mu.Unlock();
  }

  void foo5() {
    while (mu.TryLock()) {
      a = a + 1;
      mu.Unlock();
    }
  }

  void foo6() {
    bool b = mu.TryLock();
    b = !b;
    if (b) return;
    a = 6;
    mu.Unlock();
  }

  void foo7() {
    bool b1 = mu.TryLock();
    bool b2 = !b1;
    bool b3 = !b2;
    if (b3) {
      a = 7;
      mu.Unlock();
    }
  }

  // Test use-def chains: join points
  void foo8() {
    bool b  = mu.TryLock();
    bool b2 = b;
    if (cond)
      b = true;
    if (b) {    // b should be unknown at this point, because of the join point
      a = 8;    // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
    }
    if (b2) {   // b2 should be known at this point.
      a = 8;
      mu.Unlock();
    }
  }

  // Test use-def-chains: back edges
  void foo9() {
    bool b = mu.TryLock();

    for (int i = 0; i < 10; ++i);

    if (b) {  // b is still known, because the loop doesn't alter it
      a = 9;
      mu.Unlock();
    }
  }

  // Test use-def chains: back edges
  void foo10() {
    bool b = mu.TryLock();

    while (cond) {
      if (b) {   // b should be unknown at this point b/c of the loop
        a = 10;  // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
      }
      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();
  }

  // Test with conditional operator
  void foo13() {
    if (mu.TryLock() ? 1 : 0)
      mu.Unlock();
  }

  void foo14() {
    if (mu.TryLock() ? 0 : 1)
      return;
    mu.Unlock();
  }

  void foo15() {
    if (mu.TryLock() ? 0 : 1) // expected-note{{mutex acquired here}}
      mu.Unlock();            // expected-warning{{releasing mutex 'mu' that was not held}}
  }                           // expected-warning{{mutex 'mu' is not held on every path through here}}
};  // end TestTrylock

} // end namespace TrylockTest


namespace TestTemplateAttributeInstantiation {

class Foo1 {
public:
  Mutex mu_;
  int a GUARDED_BY(mu_);
};

class Foo2 {
public:
  int a GUARDED_BY(mu_);
  Mutex mu_;
};


class Bar {
public:
  // Test non-dependent expressions in attributes on template functions
  template <class T>
  void barND(Foo1 *foo, T *fooT) EXCLUSIVE_LOCKS_REQUIRED(foo->mu_) {
    foo->a = 0;
  }

  // Test dependent expressions in attributes on template functions
  template <class T>
  void barD(Foo1 *foo, T *fooT) EXCLUSIVE_LOCKS_REQUIRED(fooT->mu_) {
    fooT->a = 0;
  }
};


template <class T>
class BarT {
public:
  Foo1 fooBase;
  T    fooBaseT;

  // Test non-dependent expression in ordinary method on template class
  void barND() EXCLUSIVE_LOCKS_REQUIRED(fooBase.mu_) {
    fooBase.a = 0;
  }

  // Test dependent expressions in ordinary methods on template class
  void barD() EXCLUSIVE_LOCKS_REQUIRED(fooBaseT.mu_) {
    fooBaseT.a = 0;
  }

  // Test dependent expressions in template method in template class
  template <class T2>
  void barTD(T2 *fooT) EXCLUSIVE_LOCKS_REQUIRED(fooBaseT.mu_, fooT->mu_) {
    fooBaseT.a = 0;
    fooT->a = 0;
  }
};

template <class T>
class Cell {
public:
  Mutex mu_;
  // Test dependent guarded_by
  T data GUARDED_BY(mu_);

  void fooEx() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
    data = 0;
  }

  void foo() {
    mu_.Lock();
    data = 0;
    mu_.Unlock();
  }
};

void test() {
  Bar b;
  BarT<Foo2> bt;
  Foo1 f1;
  Foo2 f2;

  f1.mu_.Lock();
  f2.mu_.Lock();
  bt.fooBase.mu_.Lock();
  bt.fooBaseT.mu_.Lock();

  b.barND(&f1, &f2);
  b.barD(&f1, &f2);
  bt.barND();
  bt.barD();
  bt.barTD(&f2);

  f1.mu_.Unlock();
  bt.barTD(&f1);  // \
    // expected-warning {{calling function 'barTD<TestTemplateAttributeInstantiation::Foo1>' requires holding mutex 'f1.mu_' exclusively}} \
    // expected-note {{found near match 'bt.fooBase.mu_'}}

  bt.fooBase.mu_.Unlock();
  bt.fooBaseT.mu_.Unlock();
  f2.mu_.Unlock();

  Cell<int> cell;
  cell.data = 0; // \
    // expected-warning {{writing variable 'data' requires holding mutex 'cell.mu_' exclusively}}
  cell.foo();
  cell.mu_.Lock();
  cell.fooEx();
  cell.mu_.Unlock();
}


template <class T>
class CellDelayed {
public:
  // Test dependent guarded_by
  T data GUARDED_BY(mu_);
  static T static_data GUARDED_BY(static_mu_);

  void fooEx(CellDelayed<T> *other) EXCLUSIVE_LOCKS_REQUIRED(mu_, other->mu_) {
    this->data = other->data;
  }

  template <class T2>
  void fooExT(CellDelayed<T2> *otherT) EXCLUSIVE_LOCKS_REQUIRED(mu_, otherT->mu_) {
    this->data = otherT->data;
  }

  void foo() {
    mu_.Lock();
    data = 0;
    mu_.Unlock();
  }

  Mutex mu_;
  static Mutex static_mu_;
};

void testDelayed() {
  CellDelayed<int> celld;
  CellDelayed<int> celld2;
  celld.foo();
  celld.mu_.Lock();
  celld2.mu_.Lock();

  celld.fooEx(&celld2);
  celld.fooExT(&celld2);

  celld2.mu_.Unlock();
  celld.mu_.Unlock();
}

};  // end namespace TestTemplateAttributeInstantiation


namespace FunctionDeclDefTest {

class Foo {
public:
  Mutex mu_;
  int a GUARDED_BY(mu_);

  virtual void foo1(Foo *f_declared) EXCLUSIVE_LOCKS_REQUIRED(f_declared->mu_);
};

// EXCLUSIVE_LOCKS_REQUIRED should be applied, and rewritten to f_defined->mu_
void Foo::foo1(Foo *f_defined) {
  f_defined->a = 0;
};

void test() {
  Foo myfoo;
  myfoo.foo1(&myfoo);  // \
    // expected-warning {{calling function 'foo1' requires holding mutex 'myfoo.mu_' exclusively}}
  myfoo.mu_.Lock();
  myfoo.foo1(&myfoo);
  myfoo.mu_.Unlock();
}

};

namespace GoingNative {

  struct LOCKABLE mutex {
    void lock() EXCLUSIVE_LOCK_FUNCTION();
    void unlock() UNLOCK_FUNCTION();
    // ...
  };
  bool foo();
  bool bar();
  mutex m;
  void test() {
    m.lock();
    while (foo()) { // expected-warning {{expecting mutex 'm' to be held at start of each loop}}
      m.unlock();
      // ...
      if (bar()) {
        // ...
        if (foo())
          continue;
        //...
      }
      // ...
      m.lock(); // expected-note {{mutex acquired here}}
    }
    m.unlock();
  }

}



namespace FunctionDefinitionTest {

class Foo {
public:
  void foo1();
  void foo2();
  void foo3(Foo *other);

  template<class T>
  void fooT1(const T& dummy1);

  template<class T>
  void fooT2(const T& dummy2) EXCLUSIVE_LOCKS_REQUIRED(mu_);

  Mutex mu_;
  int a GUARDED_BY(mu_);
};

template<class T>
class FooT {
public:
  void foo();

  Mutex mu_;
  T a GUARDED_BY(mu_);
};


void Foo::foo1() NO_THREAD_SAFETY_ANALYSIS {
  a = 1;
}

void Foo::foo2() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
  a = 2;
}

void Foo::foo3(Foo *other) EXCLUSIVE_LOCKS_REQUIRED(other->mu_) {
  other->a = 3;
}

template<class T>
void Foo::fooT1(const T& dummy1) EXCLUSIVE_LOCKS_REQUIRED(mu_) {
  a = dummy1;
}

/* TODO -- uncomment with template instantiation of attributes.
template<class T>
void Foo::fooT2(const T& dummy2) {
  a = dummy2;
}
*/

void fooF1(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) {
  f->a = 1;
}

void fooF2(Foo *f);
void fooF2(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_) {
  f->a = 2;
}

void fooF3(Foo *f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_);
void fooF3(Foo *f) {
  f->a = 3;
}

template<class T>
void FooT<T>::foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
  a = 0;
}

void test() {
  int dummy = 0;
  Foo myFoo;

  myFoo.foo2();        // \
    // expected-warning {{calling function 'foo2' requires holding mutex 'myFoo.mu_' exclusively}}
  myFoo.foo3(&myFoo);  // \
    // expected-warning {{calling function 'foo3' requires holding mutex 'myFoo.mu_' exclusively}}
  myFoo.fooT1(dummy);  // \
    // expected-warning {{calling function 'fooT1<int>' requires holding mutex 'myFoo.mu_' exclusively}}

  myFoo.fooT2(dummy);  // \
    // expected-warning {{calling function 'fooT2<int>' requires holding mutex 'myFoo.mu_' exclusively}}

  fooF1(&myFoo);  // \
    // expected-warning {{calling function 'fooF1' requires holding mutex 'myFoo.mu_' exclusively}}
  fooF2(&myFoo);  // \
    // expected-warning {{calling function 'fooF2' requires holding mutex 'myFoo.mu_' exclusively}}
  fooF3(&myFoo);  // \
    // expected-warning {{calling function 'fooF3' requires holding mutex 'myFoo.mu_' exclusively}}

  myFoo.mu_.Lock();
  myFoo.foo2();
  myFoo.foo3(&myFoo);
  myFoo.fooT1(dummy);

  myFoo.fooT2(dummy);

  fooF1(&myFoo);
  fooF2(&myFoo);
  fooF3(&myFoo);
  myFoo.mu_.Unlock();

  FooT<int> myFooT;
  myFooT.foo();  // \
    // expected-warning {{calling function 'foo' requires holding mutex 'myFooT.mu_' exclusively}}
}

} // end namespace FunctionDefinitionTest


namespace SelfLockingTest {

class LOCKABLE MyLock {
public:
  int foo GUARDED_BY(this);

  void lock()   EXCLUSIVE_LOCK_FUNCTION();
  void unlock() UNLOCK_FUNCTION();

  void doSomething() {
    this->lock();  // allow 'this' as a lock expression
    foo = 0;
    doSomethingElse();
    this->unlock();
  }

  void doSomethingElse() EXCLUSIVE_LOCKS_REQUIRED(this) {
    foo = 1;
  };

  void test() {
    foo = 2;  // \
      // expected-warning {{writing variable 'foo' requires holding mutex 'this' exclusively}}
  }
};


class LOCKABLE MyLock2 {
public:
  Mutex mu_;
  int foo GUARDED_BY(this);

  // don't check inside lock and unlock functions
  void lock()   EXCLUSIVE_LOCK_FUNCTION() { mu_.Lock();   }
  void unlock() UNLOCK_FUNCTION()         { mu_.Unlock(); }

  // don't check inside constructors and destructors
  MyLock2()  { foo = 1; }
  ~MyLock2() { foo = 0; }
};


} // end namespace SelfLockingTest


namespace InvalidNonstatic {

// Forward decl here causes bogus "invalid use of non-static data member"
// on reference to mutex_ in guarded_by attribute.
class Foo;

class Foo {
  Mutex* mutex_;

  int foo __attribute__((guarded_by(mutex_)));
};

}  // end namespace InvalidNonStatic


namespace NoReturnTest {

bool condition();
void fatal() __attribute__((noreturn));

Mutex mu_;

void test1() {
  MutexLock lock(&mu_);
  if (condition()) {
    fatal();
    return;
  }
}

} // end namespace NoReturnTest


namespace TestMultiDecl {

class Foo {
public:
  int GUARDED_BY(mu_) a;
  int GUARDED_BY(mu_) b, c;

  void foo() {
    a = 0; // \
      // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
    b = 0; // \
      // expected-warning {{writing variable 'b' requires holding mutex 'mu_' exclusively}}
    c = 0; // \
      // expected-warning {{writing variable 'c' requires holding mutex 'mu_' exclusively}}
  }

private:
  Mutex mu_;
};

} // end namespace TestMultiDecl


namespace WarnNoDecl {

class Foo {
  void foo(int a);  __attribute__(( // \
    // expected-warning {{declaration does not declare anything}}
    exclusive_locks_required(a))); // \
    // expected-warning {{attribute exclusive_locks_required ignored}}
};

} // end namespace WarnNoDecl



namespace MoreLockExpressions {

class Foo {
public:
  Mutex mu_;
  int a GUARDED_BY(mu_);
};

class Bar {
public:
  int b;
  Foo* f;

  Foo& getFoo()              { return *f; }
  Foo& getFoo2(int c)        { return *f; }
  Foo& getFoo3(int c, int d) { return *f; }

  Foo& getFooey() { return *f; }
};

Foo& getBarFoo(Bar &bar, int c) { return bar.getFoo2(c); }

void test() {
  Foo foo;
  Foo *fooArray;
  Foo &(*fooFuncPtr)();
  Bar bar;
  int a;
  int b;
  int c;

  bar.getFoo().mu_.Lock();
  bar.getFoo().a = 0;
  bar.getFoo().mu_.Unlock();

  (bar.getFoo().mu_).Lock();   // test parenthesis
  bar.getFoo().a = 0;
  (bar.getFoo().mu_).Unlock();

  bar.getFoo2(a).mu_.Lock();
  bar.getFoo2(a).a = 0;
  bar.getFoo2(a).mu_.Unlock();

  bar.getFoo3(a, b).mu_.Lock();
  bar.getFoo3(a, b).a = 0;
  bar.getFoo3(a, b).mu_.Unlock();

  getBarFoo(bar, a).mu_.Lock();
  getBarFoo(bar, a).a = 0;
  getBarFoo(bar, a).mu_.Unlock();

  bar.getFoo2(10).mu_.Lock();
  bar.getFoo2(10).a = 0;
  bar.getFoo2(10).mu_.Unlock();

  bar.getFoo2(a + 1).mu_.Lock();
  bar.getFoo2(a + 1).a = 0;
  bar.getFoo2(a + 1).mu_.Unlock();

  (a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock();
  (a > 0 ? fooArray[1] : fooArray[b]).a = 0;
  (a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();

  fooFuncPtr().mu_.Lock();
  fooFuncPtr().a = 0;
  fooFuncPtr().mu_.Unlock();
}


void test2() {
  Foo *fooArray;
  Bar bar;
  int a;
  int b;
  int c;

  bar.getFoo().mu_.Lock();
  bar.getFooey().a = 0; // \
    // expected-warning {{writing variable 'a' requires holding mutex '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 holding mutex '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 holding mutex 'bar.getFoo3(a, c).mu_' exclusively}} \
    // expected-note {{found near match '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 holding mutex 'getBarFoo(bar, b).mu_' exclusively}} \
    // expected-note {{found near match '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 holding mutex '((0 < a) ? fooArray[b] : fooArray[c]).mu_' exclusively}} \
    // expected-note {{found near match '((0 < a) ? fooArray[1] : fooArray[b]).mu_'}}
  (a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock();
}


} // end namespace MoreLockExpressions


namespace TrylockJoinPoint {

class Foo {
  Mutex mu;
  bool c;

  void foo() {
    if (c) {
      if (!mu.TryLock())
        return;
    } else {
      mu.Lock();
    }
    mu.Unlock();
  }
};

} // end namespace TrylockJoinPoint


namespace LockReturned {

class Foo {
public:
  int a             GUARDED_BY(mu_);
  void foo()        EXCLUSIVE_LOCKS_REQUIRED(mu_);
  void foo2(Foo* f) EXCLUSIVE_LOCKS_REQUIRED(mu_, f->mu_);

  static void sfoo(Foo* f) EXCLUSIVE_LOCKS_REQUIRED(f->mu_);

  Mutex* getMu() LOCK_RETURNED(mu_);

  Mutex mu_;

  static Mutex* getMu(Foo* f) LOCK_RETURNED(f->mu_);
};


// Calls getMu() directly to lock and unlock
void test1(Foo* f1, Foo* f2) {
  f1->a = 0;       // expected-warning {{writing variable 'a' requires holding mutex 'f1->mu_' exclusively}}
  f1->foo();       // expected-warning {{calling function 'foo' requires holding mutex 'f1->mu_' exclusively}}

  f1->foo2(f2);    // expected-warning {{calling function 'foo2' requires holding mutex 'f1->mu_' exclusively}} \
                   // expected-warning {{calling function 'foo2' requires holding mutex 'f2->mu_' exclusively}}
  Foo::sfoo(f1);   // expected-warning {{calling function 'sfoo' requires holding mutex 'f1->mu_' exclusively}}

  f1->getMu()->Lock();

  f1->a = 0;
  f1->foo();
  f1->foo2(f2); // \
    // expected-warning {{calling function 'foo2' requires holding mutex 'f2->mu_' exclusively}} \
    // expected-note {{found near match 'f1->mu_'}}

  Foo::getMu(f2)->Lock();
  f1->foo2(f2);
  Foo::getMu(f2)->Unlock();

  Foo::sfoo(f1);

  f1->getMu()->Unlock();
}


Mutex* getFooMu(Foo* f) LOCK_RETURNED(Foo::getMu(f));

class Bar : public Foo {
public:
  int  b            GUARDED_BY(getMu());
  void bar()        EXCLUSIVE_LOCKS_REQUIRED(getMu());
  void bar2(Bar* g) EXCLUSIVE_LOCKS_REQUIRED(getMu(this), g->getMu());

  static void sbar(Bar* g)  EXCLUSIVE_LOCKS_REQUIRED(g->getMu());
  static void sbar2(Bar* g) EXCLUSIVE_LOCKS_REQUIRED(getFooMu(g));
};



// Use getMu() within other attributes.
// This requires at lest levels of substitution, more in the case of
void test2(Bar* b1, Bar* b2) {
  b1->b = 0;       // expected-warning {{writing variable 'b' requires holding mutex 'b1->mu_' exclusively}}
  b1->bar();       // expected-warning {{calling function 'bar' requires holding mutex 'b1->mu_' exclusively}}
  b1->bar2(b2);    // expected-warning {{calling function 'bar2' requires holding mutex 'b1->mu_' exclusively}} \
                   // expected-warning {{calling function 'bar2' requires holding mutex 'b2->mu_' exclusively}}
  Bar::sbar(b1);   // expected-warning {{calling function 'sbar' requires holding mutex 'b1->mu_' exclusively}}
  Bar::sbar2(b1);  // expected-warning {{calling function 'sbar2' requires holding mutex 'b1->mu_' exclusively}}

  b1->getMu()->Lock();

  b1->b = 0;
  b1->bar();
  b1->bar2(b2);  // \
    // expected-warning {{calling function 'bar2' requires holding mutex 'b2->mu_' exclusively}} \
    // // expected-note {{found near match 'b1->mu_'}}

  b2->getMu()->Lock();
  b1->bar2(b2);

  b2->getMu()->Unlock();

  Bar::sbar(b1);
  Bar::sbar2(b1);

  b1->getMu()->Unlock();
}


// Lock the mutex directly, but use attributes that call getMu()
// Also lock the mutex using getFooMu, which calls a lock_returned function.
void test3(Bar* b1, Bar* b2) {
  b1->mu_.Lock();
  b1->b = 0;
  b1->bar();

  getFooMu(b2)->Lock();
  b1->bar2(b2);
  getFooMu(b2)->Unlock();

  Bar::sbar(b1);
  Bar::sbar2(b1);

  b1->mu_.Unlock();
}

} // end namespace LockReturned


namespace ReleasableScopedLock {

class Foo {
  Mutex mu_;
  bool c;
  int a GUARDED_BY(mu_);

  void test1();
  void test2();
  void test3();
  void test4();
  void test5();
  void test6();
};


void Foo::test1() {
  ReleasableMutexLock rlock(&mu_);
  rlock.Release();
}

void Foo::test2() {
  ReleasableMutexLock rlock(&mu_);
  if (c) {            // test join point -- held/not held during release
    rlock.Release();
  }
  // No warning on join point because the lock will be released by the scope object anyway.
}

void Foo::test3() {
  ReleasableMutexLock rlock(&mu_);
  a = 0;
  rlock.Release();
  a = 1;  // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
}

void Foo::test4() {
  ReleasableMutexLock rlock(&mu_);
  rlock.Release();  // expected-note{{mutex released here}}
  rlock.Release();  // expected-warning {{releasing mutex 'mu_' that was not held}}
}

void Foo::test5() {
  ReleasableMutexLock rlock(&mu_);
  if (c) {
    rlock.Release();
  }
  // No warning on join point because the lock will be released by the scope object anyway.
  rlock.Release();  // expected-warning {{releasing mutex 'mu_' that was not held}}
}

void Foo::test6() {
  ReleasableMutexLock rlock(&mu_);
  do {
    if (c) {
      rlock.Release();
      break;
    }
  } while (c);
  // No warning on join point because the lock will be released by the scope object anyway
  a = 1; // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
}


} // end namespace ReleasableScopedLock


namespace RelockableScopedLock {

class DeferTraits {};

class SCOPED_LOCKABLE RelockableExclusiveMutexLock {
public:
  RelockableExclusiveMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
  RelockableExclusiveMutexLock(Mutex *mu, DeferTraits) LOCKS_EXCLUDED(mu);
  ~RelockableExclusiveMutexLock() EXCLUSIVE_UNLOCK_FUNCTION();

  void Lock() EXCLUSIVE_LOCK_FUNCTION();
  void Unlock() UNLOCK_FUNCTION();
};

struct SharedTraits {};
struct ExclusiveTraits {};

class SCOPED_LOCKABLE RelockableMutexLock {
public:
  RelockableMutexLock(Mutex *mu, DeferTraits) LOCKS_EXCLUDED(mu);
  RelockableMutexLock(Mutex *mu, SharedTraits) SHARED_LOCK_FUNCTION(mu);
  RelockableMutexLock(Mutex *mu, ExclusiveTraits) EXCLUSIVE_LOCK_FUNCTION(mu);
  ~RelockableMutexLock() UNLOCK_FUNCTION();

  void Lock() EXCLUSIVE_LOCK_FUNCTION();
  void Unlock() UNLOCK_FUNCTION();

  void ReaderLock() SHARED_LOCK_FUNCTION();
  void ReaderUnlock() UNLOCK_FUNCTION();

  void PromoteShared() UNLOCK_FUNCTION() EXCLUSIVE_LOCK_FUNCTION();
  void DemoteExclusive() UNLOCK_FUNCTION() SHARED_LOCK_FUNCTION();
};

Mutex mu;
int x GUARDED_BY(mu);
bool b;

void print(int);

void relock() {
  RelockableExclusiveMutexLock scope(&mu);
  x = 2;
  scope.Unlock();

  x = 3; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}

  scope.Lock();
  x = 4;
}

void deferLock() {
  RelockableExclusiveMutexLock scope(&mu, DeferTraits{});
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
  scope.Lock();
  x = 3;
}

void relockExclusive() {
  RelockableMutexLock scope(&mu, SharedTraits{});
  print(x);
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
  scope.ReaderUnlock();

  print(x); // expected-warning {{reading variable 'x' requires holding mutex 'mu'}}

  scope.Lock();
  print(x);
  x = 4;

  scope.DemoteExclusive();
  print(x);
  x = 5; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void relockShared() {
  RelockableMutexLock scope(&mu, ExclusiveTraits{});
  print(x);
  x = 2;
  scope.Unlock();

  print(x); // expected-warning {{reading variable 'x' requires holding mutex 'mu'}}

  scope.ReaderLock();
  print(x);
  x = 4; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}

  scope.PromoteShared();
  print(x);
  x = 5;
}

void deferLockShared() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  print(x); // expected-warning {{reading variable 'x' requires holding mutex 'mu'}}
  scope.ReaderLock();
  print(x);
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void doubleUnlock() {
  RelockableExclusiveMutexLock scope(&mu);
  scope.Unlock(); // expected-note{{mutex released here}}
  scope.Unlock(); // expected-warning {{releasing mutex 'mu' that was not held}}
}

void doubleLock1() {
  RelockableExclusiveMutexLock scope(&mu); // expected-note{{mutex acquired here}}
  scope.Lock(); // expected-warning {{acquiring mutex 'mu' that is already held}}
}

void doubleLock2() {
  RelockableExclusiveMutexLock scope(&mu);
  scope.Unlock();
  scope.Lock(); // expected-note{{mutex acquired here}}
  scope.Lock(); // expected-warning {{acquiring mutex 'mu' that is already held}}
}

void lockJoin() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  if (b)
    scope.Lock();
  // No warning on join point because the lock will be released by the scope object anyway.
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void unlockJoin() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  scope.Lock();
  if (b)
    scope.Unlock();
  // No warning on join point because the lock will be released by the scope object anyway.
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void loopAcquire() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  for (unsigned i = 1; i < 10; ++i)
    scope.Lock(); // We could catch this double lock with negative capabilities.
}

void loopRelease() {
  RelockableMutexLock scope(&mu, ExclusiveTraits{}); // expected-note {{mutex acquired here}}
  // We have to warn on this join point despite the lock being managed ...
  for (unsigned i = 1; i < 10; ++i) { // expected-warning {{expecting mutex 'mu' to be held at start of each loop}}
    x = 1; // ... because we might miss that this doesn't always happen under lock.
    if (i == 5)
      scope.Unlock();
  }
}

void loopPromote() {
  RelockableMutexLock scope(&mu, SharedTraits{});
  for (unsigned i = 1; i < 10; ++i) {
    x = 1; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
    if (i == 5)
      scope.PromoteShared();
  }
}

void loopDemote() {
  RelockableMutexLock scope(&mu, ExclusiveTraits{}); // expected-note {{the other acquisition of mutex 'mu' is here}}
  // We have to warn on this join point despite the lock being managed ...
  for (unsigned i = 1; i < 10; ++i) {
    x = 1; // ... because we might miss that this doesn't always happen under exclusive lock.
    if (i == 5)
      scope.DemoteExclusive(); // expected-warning {{mutex 'mu' is acquired exclusively and shared in the same scope}}
  }
}

void loopAcquireContinue() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  for (unsigned i = 1; i < 10; ++i) {
    x = 1; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
    if (i == 5) {
      scope.Lock();
      continue;
    }
  }
}

void loopReleaseContinue() {
  RelockableMutexLock scope(&mu, ExclusiveTraits{}); // expected-note {{mutex acquired here}}
  // We have to warn on this join point despite the lock being managed ...
  for (unsigned i = 1; i < 10; ++i) { // expected-warning {{expecting mutex 'mu' to be held at start of each loop}}
    x = 1; // ... because we might miss that this doesn't always happen under lock.
    if (i == 5) {
      scope.Unlock();
      continue;
    }
  }
}

void loopPromoteContinue() {
  RelockableMutexLock scope(&mu, SharedTraits{});
  for (unsigned i = 1; i < 10; ++i) {
    x = 1; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
    if (i == 5) {
      scope.PromoteShared();
      continue;
    }
  }
}

void loopDemoteContinue() {
  RelockableMutexLock scope(&mu, ExclusiveTraits{}); // expected-note {{the other acquisition of mutex 'mu' is here}}
  // We have to warn on this join point despite the lock being managed ...
  for (unsigned i = 1; i < 10; ++i) {
    x = 1; // ... because we might miss that this doesn't always happen under exclusive lock.
    if (i == 5) {
      scope.DemoteExclusive(); // expected-warning {{mutex 'mu' is acquired exclusively and shared in the same scope}}
      continue;
    }
  }
}

void exclusiveSharedJoin() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  if (b)
    scope.Lock();
  else
    scope.ReaderLock();
  // No warning on join point because the lock will be released by the scope object anyway.
  print(x);
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void sharedExclusiveJoin() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  if (b)
    scope.ReaderLock();
  else
    scope.Lock();
  // No warning on join point because the lock will be released by the scope object anyway.
  print(x);
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void assertJoin() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  if (b)
    scope.Lock();
  else
    mu.AssertHeld();
  x = 2;
}

void assertSharedJoin() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  if (b)
    scope.ReaderLock();
  else
    mu.AssertReaderHeld();
  print(x);
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void assertStrongerJoin() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  if (b)
    scope.ReaderLock();
  else
    mu.AssertHeld();
  print(x);
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void assertWeakerJoin() {
  RelockableMutexLock scope(&mu, DeferTraits{});
  if (b)
    scope.Lock();
  else
    mu.AssertReaderHeld();
  print(x);
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void directUnlock() {
  RelockableExclusiveMutexLock scope(&mu);
  mu.Unlock();
  // Debatable that there is no warning. Currently we don't track in the scoped
  // object whether it is active, but just check if the contained locks can be
  // reacquired. Here they can, because mu has been unlocked manually.
  scope.Lock();
}

void directRelock() {
  RelockableExclusiveMutexLock scope(&mu);
  scope.Unlock();
  mu.Lock();
  // Similarly debatable that there is no warning.
  scope.Unlock();
}

// Doesn't make a lot of sense, just making sure there is no crash.
void destructLock() {
  RelockableExclusiveMutexLock scope(&mu);
  scope.~RelockableExclusiveMutexLock();
  scope.Lock(); // Should be UB, so we don't really care.
}

class SCOPED_LOCKABLE MemberLock {
public:
  MemberLock() EXCLUSIVE_LOCK_FUNCTION(mutex);
  ~MemberLock() UNLOCK_FUNCTION(mutex);
  void Lock() EXCLUSIVE_LOCK_FUNCTION(mutex);
  Mutex mutex;
};

void relockShared2() {
  MemberLock lock; // expected-note{{mutex acquired here}}
  lock.Lock(); // expected-warning {{acquiring mutex 'lock.mutex' that is already held}}
}

class SCOPED_LOCKABLE WeirdScope {
private:
  Mutex *other;

public:
  WeirdScope(Mutex *mutex) EXCLUSIVE_LOCK_FUNCTION(mutex);
  void unlock() EXCLUSIVE_UNLOCK_FUNCTION() EXCLUSIVE_UNLOCK_FUNCTION(other);
  void lock() EXCLUSIVE_LOCK_FUNCTION() EXCLUSIVE_LOCK_FUNCTION(other);
  ~WeirdScope() EXCLUSIVE_UNLOCK_FUNCTION();

  void requireOther() EXCLUSIVE_LOCKS_REQUIRED(other);
};

void relockWeird() {
  WeirdScope scope(&mu);
  x = 1;
  scope.unlock(); // expected-warning {{releasing mutex 'scope.other' that was not held}}
  x = 2; // \
    // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
  scope.requireOther(); // \
    // expected-warning {{calling function 'requireOther' requires holding mutex 'scope.other' exclusively}}
  scope.lock(); // expected-note {{mutex acquired here}}
  x = 3;
  scope.requireOther();
} // expected-warning {{mutex 'scope.other' is still held at the end of function}}

} // end namespace RelockableScopedLock


namespace ScopedUnlock {

class SCOPED_LOCKABLE MutexUnlock {
public:
  MutexUnlock(Mutex *mu) EXCLUSIVE_UNLOCK_FUNCTION(mu);
  ~MutexUnlock() EXCLUSIVE_UNLOCK_FUNCTION();

  void Lock() EXCLUSIVE_UNLOCK_FUNCTION();
  void Unlock() EXCLUSIVE_LOCK_FUNCTION();
};

class SCOPED_LOCKABLE ReaderMutexUnlock {
public:
  ReaderMutexUnlock(Mutex *mu) SHARED_UNLOCK_FUNCTION(mu);
  ~ReaderMutexUnlock() EXCLUSIVE_UNLOCK_FUNCTION();

  void Lock() EXCLUSIVE_UNLOCK_FUNCTION();
  void Unlock() EXCLUSIVE_LOCK_FUNCTION();
};

Mutex mu;
int x GUARDED_BY(mu);
bool c;
void print(int);

void simple() EXCLUSIVE_LOCKS_REQUIRED(mu) {
  x = 1;
  MutexUnlock scope(&mu);
  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void simpleShared() SHARED_LOCKS_REQUIRED(mu) {
  print(x);
  ReaderMutexUnlock scope(&mu);
  print(x); // expected-warning {{reading variable 'x' requires holding mutex 'mu'}}
}

void innerUnlock() {
  MutexLock outer(&mu);
  if (x == 0) {
    MutexUnlock inner(&mu);
    x = 1; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
  }
  x = 2;
}

void innerUnlockShared() {
  ReaderMutexLock outer(&mu);
  if (x == 0) {
    ReaderMutexUnlock inner(&mu);
    print(x); // expected-warning {{reading variable 'x' requires holding mutex 'mu'}}
  }
  print(x);
}

void manual() EXCLUSIVE_LOCKS_REQUIRED(mu) {
  MutexUnlock scope(&mu);
  scope.Lock();
  x = 2;
  scope.Unlock();
  x = 3; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

void join() EXCLUSIVE_LOCKS_REQUIRED(mu) {
  MutexUnlock scope(&mu);
  if (c)
    scope.Lock();
  // No warning on join point because the lock will be released by the scope object anyway.
  scope.Lock();
}

void doubleLock() EXCLUSIVE_LOCKS_REQUIRED(mu) {
  MutexUnlock scope(&mu);
  scope.Lock(); // expected-note{{mutex acquired here}}
  scope.Lock(); // expected-warning {{acquiring mutex 'mu' that is already held}}
}

void doubleUnlock() EXCLUSIVE_LOCKS_REQUIRED(mu) {
  MutexUnlock scope(&mu); // expected-note{{mutex released here}}
  scope.Unlock(); // expected-warning {{releasing mutex 'mu' that was not held}}
}

class SCOPED_LOCKABLE MutexLockUnlock {
public:
  MutexLockUnlock(Mutex *mu1, Mutex *mu2) EXCLUSIVE_UNLOCK_FUNCTION(mu1) EXCLUSIVE_LOCK_FUNCTION(mu2);
  ~MutexLockUnlock() EXCLUSIVE_UNLOCK_FUNCTION();

  void Release() EXCLUSIVE_UNLOCK_FUNCTION();
  void Acquire() EXCLUSIVE_LOCK_FUNCTION();
};

Mutex other;
void fn() EXCLUSIVE_LOCKS_REQUIRED(other);

void lockUnlock() EXCLUSIVE_LOCKS_REQUIRED(mu) {
  MutexLockUnlock scope(&mu, &other);
  fn();
  x = 1; // expected-warning {{writing variable 'x' requires holding mutex 'mu' exclusively}}
}

} // end namespace ScopedUnlock


namespace TrylockFunctionTest {

class Foo {
public:
  Mutex mu1_;
  Mutex mu2_;
  bool c;

  bool lockBoth() EXCLUSIVE_TRYLOCK_FUNCTION(true, mu1_, mu2_);
};

bool Foo::lockBoth() {
  if (!mu1_.TryLock())
    return false;

  mu2_.Lock();
  if (!c) {
    mu1_.Unlock();
    mu2_.Unlock();
    return false;
  }

  return true;
}


}  // end namespace TrylockFunctionTest



namespace DoubleLockBug {

class Foo {
public:
  Mutex mu_;
  int a GUARDED_BY(mu_);

  void foo1() EXCLUSIVE_LOCKS_REQUIRED(mu_);
  int  foo2() SHARED_LOCKS_REQUIRED(mu_);
};


void Foo::foo1() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
  a = 0;
}

int Foo::foo2() SHARED_LOCKS_REQUIRED(mu_) {
  return a;
}

}



namespace UnlockBug {

class Foo {
public:
  Mutex mutex_;

  void foo1() EXCLUSIVE_LOCKS_REQUIRED(mutex_) {  // expected-note {{mutex acquired here}}
    mutex_.Unlock();
  }  // expected-warning {{expecting mutex 'mutex_' to be held at the end of function}}


  void foo2() SHARED_LOCKS_REQUIRED(mutex_) {   // expected-note {{mutex acquired here}}
    mutex_.Unlock();
  }  // expected-warning {{expecting mutex 'mutex_' to be held at the end of function}}
};

} // end namespace UnlockBug



namespace FoolishScopedLockableBug {

class SCOPED_LOCKABLE WTF_ScopedLockable {
public:
  WTF_ScopedLockable(Mutex* mu) EXCLUSIVE_LOCK_FUNCTION(mu);

  // have to call release() manually;
  ~WTF_ScopedLockable();

  void release() UNLOCK_FUNCTION();
};


class Foo {
  Mutex mu_;
  int a GUARDED_BY(mu_);
  bool c;

  void doSomething();

  void test1() {
    WTF_ScopedLockable wtf(&mu_);
    wtf.release();
  }

  void test2() {
    WTF_ScopedLockable wtf(&mu_);  // expected-note {{mutex acquired here}}
  }  // expected-warning {{mutex 'mu_' is still held at the end of function}}

  void test3() {
    if (c) {
      WTF_ScopedLockable wtf(&mu_);
      wtf.release();
    }
  }

  void test4() {
    if (c) {
      doSomething();
    }
    else {
      WTF_ScopedLockable wtf(&mu_);
      wtf.release();
    }
  }

  void test5() {
    if (c) {
      WTF_ScopedLockable wtf(&mu_);  // expected-note {{mutex acquired here}}
    }
  } // expected-warning {{mutex 'mu_' is not held on every path through here}}

  void test6() {
    if (c) {
      doSomething();
    }
    else {
      WTF_ScopedLockable wtf(&mu_);  // expected-note {{mutex acquired here}}
    }
  } // expected-warning {{mutex 'mu_' is not held on every path through here}}
};


} // end namespace FoolishScopedLockableBug



namespace TemporaryCleanupExpr {

class Foo {
  int a GUARDED_BY(getMutexPtr().get());

  SmartPtr<Mutex> getMutexPtr();

  void test();
};


void Foo::test() {
  {
    ReaderMutexLock lock(getMutexPtr().get());
    int b = a;
  }
  int b = a;  // expected-warning {{reading variable 'a' requires holding mutex 'getMutexPtr()'}}
}

#ifdef __cpp_guaranteed_copy_elision

void guaranteed_copy_elision() {
  MutexLock lock = MutexLock{&sls_mu};
  sls_guard_var = 0;
}

void guaranteed_copy_elision_const() {
  const MutexLock lock = MutexLock{&sls_mu};
  sls_guard_var = 0;
}

#endif

} // end namespace TemporaryCleanupExpr



namespace SmartPointerTests {

class Foo {
public:
  SmartPtr<Mutex> mu_;
  int a GUARDED_BY(mu_);
  int b GUARDED_BY(mu_.get());
  int c GUARDED_BY(*mu_);

  void Lock()   EXCLUSIVE_LOCK_FUNCTION(mu_);
  void Unlock() UNLOCK_FUNCTION(mu_);

  void test0();
  void test1();
  void test2();
  void test3();
  void test4();
  void test5();
  void test6();
  void test7();
  void test8();
};

void Foo::test0() {
  a = 0;  // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
  b = 0;  // expected-warning {{writing variable 'b' requires holding mutex 'mu_' exclusively}}
  c = 0;  // expected-warning {{writing variable 'c' requires holding mutex 'mu_' exclusively}}
}

void Foo::test1() {
  mu_->Lock();
  a = 0;
  b = 0;
  c = 0;
  mu_->Unlock();
}

void Foo::test2() {
  (*mu_).Lock();
  a = 0;
  b = 0;
  c = 0;
  (*mu_).Unlock();
}


void Foo::test3() {
  mu_.get()->Lock();
  a = 0;
  b = 0;
  c = 0;
  mu_.get()->Unlock();
}


void Foo::test4() {
  MutexLock lock(mu_.get());
  a = 0;
  b = 0;
  c = 0;
}


void Foo::test5() {
  MutexLock lock(&(*mu_));
  a = 0;
  b = 0;
  c = 0;
}


void Foo::test6() {
  Lock();
  a = 0;
  b = 0;
  c = 0;
  Unlock();
}


void Foo::test7() {
  {
    Lock();
    mu_->Unlock();
  }
  {
    mu_->Lock();
    Unlock();
  }
  {
    mu_.get()->Lock();
    mu_->Unlock();
  }
  {
    mu_->Lock();
    mu_.get()->Unlock();
  }
  {
    mu_.get()->Lock();
    (*mu_).Unlock();
  }
  {
    (*mu_).Lock();
    mu_->Unlock();
  }
}


void Foo::test8() {
  mu_->Lock();          // expected-note 2 {{mutex acquired here}}
  mu_.get()->Lock();    // expected-warning {{acquiring mutex 'mu_' that is already held}}
  (*mu_).Lock();        // expected-warning {{acquiring mutex 'mu_' that is already held}}
  mu_.get()->Unlock();  // expected-note {{mutex released here}}
  Unlock();             // expected-warning {{releasing mutex 'mu_' that was not held}}
}


class Bar {
  SmartPtr<Foo> foo;

  void test0();
  void test1();
  void test2();
  void test3();
};


void Bar::test0() {
  foo->a = 0;         // expected-warning {{writing variable 'a' requires holding mutex 'foo->mu_' exclusively}}
  (*foo).b = 0;       // expected-warning {{writing variable 'b' requires holding mutex 'foo->mu_' exclusively}}
  foo.get()->c = 0;   // expected-warning {{writing variable 'c' requires holding mutex 'foo->mu_' exclusively}}
}


void Bar::test1() {
  foo->mu_->Lock();
  foo->a = 0;
  (*foo).b = 0;
  foo.get()->c = 0;
  foo->mu_->Unlock();
}


void Bar::test2() {
  (*foo).mu_->Lock();
  foo->a = 0;
  (*foo).b = 0;
  foo.get()->c = 0;
  foo.get()->mu_->Unlock();
}


void Bar::test3() {
  MutexLock lock(foo->mu_.get());
  foo->a = 0;
  (*foo).b = 0;
  foo.get()->c = 0;
}

}  // end namespace SmartPointerTests



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_.ReaderLock();
}

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();     // expected-note{{mutex acquired here}}
  foo.lock();     // expected-warning {{acquiring mutex 'foo' that is already held}}
  foo.unlock();   // expected-note{{mutex released here}}
  foo.unlock();   // expected-warning {{releasing mutex 'foo' that was not held}}
}


void test1() {
  Foo foo;
  foo.lock1();
  foo.a = 0;
  foo.unlock1();

  foo.lock1();    // expected-note{{mutex acquired here}}
  foo.lock1();    // expected-warning {{acquiring mutex 'foo.mu1_' that is already held}}
  foo.a = 0;
  foo.unlock1();  // expected-note{{mutex released here}}
  foo.unlock1();  // expected-warning {{releasing mutex 'foo.mu1_' that was not held}}
}


int test2() {
  Foo foo;
  foo.slock1();
  int d1 = foo.a;
  foo.unlock1();

  foo.slock1();    // expected-note{{mutex acquired here}}
  foo.slock1();    // expected-warning {{acquiring mutex 'foo.mu1_' that is already held}}
  int d2 = foo.a;
  foo.unlock1();   // expected-note{{mutex released here}}
  foo.unlock1();   // expected-warning {{releasing mutex 'foo.mu1_' that was not held}}
  return d1 + d2;
}


void test3() {
  Foo foo;
  foo.lock3();
  foo.a = 0;
  foo.b = 0;
  foo.c = 0;
  foo.unlock3();

  foo.lock3(); // expected-note 3 {{mutex acquired here}}
  foo.lock3(); // \
    // expected-warning {{acquiring mutex 'foo.mu1_' that is already held}} \
    // expected-warning {{acquiring mutex 'foo.mu2_' that is already held}} \
    // expected-warning {{acquiring mutex 'foo.mu3_' that is already held}}
  foo.a = 0;
  foo.b = 0;
  foo.c = 0;
  foo.unlock3(); // expected-note 3 {{mutex released here}}
  foo.unlock3(); // \
    // expected-warning {{releasing mutex 'foo.mu1_' that was not held}} \
    // expected-warning {{releasing mutex 'foo.mu2_' that was not held}} \
    // expected-warning {{releasing mutex 'foo.mu3_' that was not held}}
}


void testlots() {
  Foo foo;
  foo.locklots();
  foo.a = 0;
  foo.b = 0;
  foo.c = 0;
  foo.unlocklots();

  foo.locklots(); // expected-note 3 {{mutex acquired here}}
  foo.locklots(); // \
    // expected-warning {{acquiring mutex 'foo.mu1_' that is already held}} \
    // expected-warning {{acquiring mutex 'foo.mu2_' that is already held}} \
    // expected-warning {{acquiring mutex 'foo.mu3_' that is already held}}
  foo.a = 0;
  foo.b = 0;
  foo.c = 0;
  foo.unlocklots(); // expected-note 3 {{mutex released here}}
  foo.unlocklots(); // \
    // expected-warning {{releasing mutex 'foo.mu1_' that was not held}} \
    // expected-warning {{releasing mutex 'foo.mu2_' that was not held}} \
    // expected-warning {{releasing mutex 'foo.mu3_' that was not held}}
}

}  // end namespace DuplicateAttributeTest



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 holding mutex '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 holding mutex 'mu_' exclusively}}
    return;
  }
  a = 0;
  unlock();

  if (0 == tryLockMutexI()) {
    a = 0;   // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
    return;
  }
  a = 0;
  unlock();

  if (tryLockMutexI() == 1) {
    a = 0;
    unlock();
  }

  if (mu_.TryLock() == false) {
    a = 0;   // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
    return;
  }
  a = 0;
  unlock();

  if (mu_.TryLock() == true) {
    a = 0;
    unlock();
  }
  else {
    a = 0;  // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
  }

#if __has_feature(cxx_nullptr)
  if (tryLockMutexP() == nullptr) {
    a = 0;  // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
    return;
  }
  a = 0;
  unlock();
#endif
}

} // end namespace TryLockEqTest


namespace ExistentialPatternMatching {

class Graph {
public:
  Mutex mu_;
};

void LockAllGraphs()   EXCLUSIVE_LOCK_FUNCTION(&Graph::mu_);
void UnlockAllGraphs() UNLOCK_FUNCTION(&Graph::mu_);

class Node {
public:
  int a GUARDED_BY(&Graph::mu_);

  void foo()  EXCLUSIVE_LOCKS_REQUIRED(&Graph::mu_) {
    a = 0;
  }
  void foo2() LOCKS_EXCLUDED(&Graph::mu_);
};

void test() {
  Graph g1;
  Graph g2;
  Node n1;

  n1.a = 0;   // expected-warning {{writing variable 'a' requires holding mutex '&ExistentialPatternMatching::Graph::mu_' exclusively}}
  n1.foo();   // expected-warning {{calling function 'foo' requires holding mutex '&ExistentialPatternMatching::Graph::mu_' exclusively}}
  n1.foo2();

  g1.mu_.Lock();
  n1.a = 0;
  n1.foo();
  n1.foo2();  // expected-warning {{cannot call function 'foo2' while mutex '&ExistentialPatternMatching::Graph::mu_' is held}}
  g1.mu_.Unlock();

  g2.mu_.Lock();
  n1.a = 0;
  n1.foo();
  n1.foo2();  // expected-warning {{cannot call function 'foo2' while mutex '&ExistentialPatternMatching::Graph::mu_' is held}}
  g2.mu_.Unlock();

  LockAllGraphs();
  n1.a = 0;
  n1.foo();
  n1.foo2();  // expected-warning {{cannot call function 'foo2' while mutex '&ExistentialPatternMatching::Graph::mu_' is held}}
  UnlockAllGraphs();

  LockAllGraphs();
  g1.mu_.Unlock();

  LockAllGraphs();
  g2.mu_.Unlock();

  LockAllGraphs(); // expected-note{{mutex acquired here}}
  g1.mu_.Lock();  // expected-warning {{acquiring mutex 'g1.mu_' that is already held}}
  g1.mu_.Unlock();
}

} // 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 holding mutex 'mu_' exclusively}}
    endNoWarnOnWrites(); // \
      // expected-warning {{releasing wildcard '*' that was not held}}
  }


  // 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 holding mutex 'mu_' exclusively}}
  int a = f[0];    // expected-warning {{calling function 'operator[]' requires holding mutex 'mu_' exclusively}}
}                  // expected-warning {{calling function '~Foo' requires holding mutex 'mu_' exclusively}}


void test2() {
  Bar::mu_.Lock();
  {
    Bar b;         // expected-warning {{cannot call function 'Bar' while mutex 'mu_' is held}}
    int a = b[0];  // expected-warning {{cannot call function 'operator[]' while mutex 'mu_' is held}}
  }                // expected-warning {{cannot call function '~Bar' while mutex 'mu_' is held}}
  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) 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<int>' requires holding mutex 'cell.mu_' exclusively}}
}


template<class T>
void globalELR(Cell<T>* c) 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<int>' requires holding mutex 'cell.mu_' exclusively}}
}


template<class T>
void globalELR2(Cell<T>* c) 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<int>' requires holding mutex 'cell.mu_' exclusively}}
}


template<class T>
class FooT {
public:
  void elr(Cell<T>* c) 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 holding mutex 'cell.mu_' exclusively}}
}

}  // 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()    SHARED_LOCK_FUNCTION(mu1_)
                       SHARED_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 assertBoth() ASSERT_EXCLUSIVE_LOCK(mu1_)
                    ASSERT_EXCLUSIVE_LOCK(mu2_);

  void alsoAssertBoth() ASSERT_EXCLUSIVE_LOCK(mu1_, mu2_);

  void assertShared() ASSERT_SHARED_LOCK(mu1_)
                      ASSERT_SHARED_LOCK(mu2_);

  void alsoAssertShared() ASSERT_SHARED_LOCK(mu1_, mu2_);

  void test();
  void testAssert();
  void testAssertShared();
};


void Foo::foo1() {
  a = 1;
  b = 2;
}

void Foo::foo2() {
  int result = a + b;
}

void Foo::foo3() { }
void Foo::lock() { mu1_.Lock();  mu2_.Lock(); }
void Foo::readerlock() { mu1_.ReaderLock();  mu2_.ReaderLock(); }
void Foo::unlock() { mu1_.Unlock();  mu2_.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();
  }
}

// Force duplication of attributes
void Foo::assertBoth() { }
void Foo::alsoAssertBoth() { }
void Foo::assertShared() { }
void Foo::alsoAssertShared() { }

void Foo::testAssert() {
  {
    assertBoth();
    a = 0;
    b = 0;
  }
  {
    alsoAssertBoth();
    a = 0;
    b = 0;
  }
}

void Foo::testAssertShared() {
  {
    assertShared();
    int zz = a + b;
  }

  {
    alsoAssertShared();
    int zz = a + b;
  }
}


}  // end namespace MultipleAttributeTest


namespace GuardedNonPrimitiveTypeTest {


class Data {
public:
  Data(int i) : dat(i) { }

  int  getValue() const { return dat; }
  void setValue(int i)  { dat = i; }

  int  operator[](int i) const { return dat; }
  int& operator[](int i)       { return dat; }

  void operator()() { }

  Data& operator+=(int);
  Data& operator-=(int);
  Data& operator*=(int);
  Data& operator/=(int);
  Data& operator%=(int);
  Data& operator^=(int);
  Data& operator&=(int);
  Data& operator|=(int);
  Data& operator<<=(int);
  Data& operator>>=(int);
  Data& operator++();
  Data& operator++(int);
  Data& operator--();
  Data& operator--(int);

private:
  int dat;
};


class DataCell {
public:
  DataCell(const Data& d) : dat(d) { }

private:
  Data dat;
};


void showDataCell(const DataCell& dc);


class Foo {
public:
  // method call tests
  void test() {
    data_.setValue(0);         // FIXME -- should be writing \
      // expected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}
    int a = data_.getValue();  // \
      // expected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}

    datap1_->setValue(0);      // FIXME -- should be writing \
      // expected-warning {{reading variable 'datap1_' requires holding mutex 'mu_'}}
    a = datap1_->getValue();   // \
      // expected-warning {{reading variable 'datap1_' requires holding mutex 'mu_'}}

    datap2_->setValue(0);      // FIXME -- should be writing \
      // expected-warning {{reading the value pointed to by 'datap2_' requires holding mutex 'mu_'}}
    a = datap2_->getValue();   // \
      // expected-warning {{reading the value pointed to by 'datap2_' requires holding mutex 'mu_'}}

    (*datap2_).setValue(0);    // FIXME -- should be writing \
      // expected-warning {{reading the value pointed to by 'datap2_' requires holding mutex 'mu_'}}
    a = (*datap2_).getValue(); // \
      // expected-warning {{reading the value pointed to by 'datap2_' requires holding mutex 'mu_'}}

    mu_.Lock();
    data_.setValue(1);
    datap1_->setValue(1);
    datap2_->setValue(1);
    mu_.Unlock();

    mu_.ReaderLock();
    a = data_.getValue();
    datap1_->setValue(0);  // reads datap1_, writes *datap1_
    a = datap1_->getValue();
    a = datap2_->getValue();
    mu_.Unlock();
  }

  // operator tests
  void test2() {
    data_    = Data(1);   // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    *datap1_ = data_;     // expected-warning {{reading variable 'datap1_' requires holding mutex 'mu_'}} \
                          // expected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}
    *datap2_ = data_;     // expected-warning {{writing the value pointed to by 'datap2_' requires holding mutex 'mu_' exclusively}} \
                          // expected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}
    data_ = *datap1_;     // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}} \
                          // expected-warning {{reading variable 'datap1_' requires holding mutex 'mu_'}}
    data_ = *datap2_;     // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}} \
                          // expected-warning {{reading the value pointed to by 'datap2_' requires holding mutex 'mu_'}}
    data_ += 1;           // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ -= 1;           // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ *= 1;           // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ /= 1;           // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ %= 1;           // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ ^= 1;           // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ &= 1;           // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ |= 1;           // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ <<= 1;          // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_ >>= 1;          // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    ++data_;              // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_++;              // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    --data_;              // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}
    data_--;              // expected-warning {{writing variable 'data_' requires holding mutex 'mu_' exclusively}}

    data_[0] = 0;         // expected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}
    (*datap2_)[0] = 0;    // expected-warning {{reading the value pointed to by 'datap2_' requires holding mutex 'mu_'}}

    data_();              // expected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}
  }

  // const operator tests
  void test3() const {
    Data mydat(data_);      // expected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}

    //FIXME
    //showDataCell(data_);    // xpected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}
    //showDataCell(*datap2_); // xpected-warning {{reading the value pointed to by 'datap2_' requires holding mutex 'mu_'}}

    int a = data_[0];       // expected-warning {{reading variable 'data_' requires holding mutex 'mu_'}}
  }

private:
  Mutex mu_;
  Data  data_   GUARDED_BY(mu_);
  Data* datap1_ GUARDED_BY(mu_);
  Data* datap2_ PT_GUARDED_BY(mu_);
};

}  // end namespace GuardedNonPrimitiveTypeTest


namespace GuardedNonPrimitive_MemberAccess {

class Cell {
public:
  Cell(int i);

  void cellMethod();

  int a;
};


class Foo {
public:
  int   a;
  Cell  c  GUARDED_BY(cell_mu_);
  Cell* cp PT_GUARDED_BY(cell_mu_);

  void myMethod();

  Mutex cell_mu_;
};


class Bar {
private:
  Mutex mu_;
  Foo  foo  GUARDED_BY(mu_);
  Foo* foop PT_GUARDED_BY(mu_);

  void test() {
    foo.myMethod();      // expected-warning {{reading variable 'foo' requires holding mutex 'mu_'}}

    int fa = foo.a;      // expected-warning {{reading variable 'foo' requires holding mutex 'mu_'}}
    foo.a  = fa;         // expected-warning {{writing variable 'foo' requires holding mutex 'mu_' exclusively}}

    fa = foop->a;        // expected-warning {{reading the value pointed to by 'foop' requires holding mutex 'mu_'}}
    foop->a = fa;        // expected-warning {{writing the value pointed to by 'foop' requires holding mutex 'mu_' exclusively}}

    fa = (*foop).a;      // expected-warning {{reading the value pointed to by 'foop' requires holding mutex 'mu_'}}
    (*foop).a = fa;      // expected-warning {{writing the value pointed to by 'foop' requires holding mutex 'mu_' exclusively}}

    foo.c  = Cell(0);    // expected-warning {{writing variable 'foo' requires holding mutex 'mu_'}} \
                         // expected-warning {{writing variable 'c' requires holding mutex 'foo.cell_mu_' exclusively}}
    foo.c.cellMethod();  // expected-warning {{reading variable 'foo' requires holding mutex 'mu_'}} \
                         // expected-warning {{reading variable 'c' requires holding mutex 'foo.cell_mu_'}}

    foop->c  = Cell(0);    // expected-warning {{writing the value pointed to by 'foop' requires holding mutex 'mu_'}} \
                           // expected-warning {{writing variable 'c' requires holding mutex 'foop->cell_mu_' exclusively}}
    foop->c.cellMethod();  // expected-warning {{reading the value pointed to by 'foop' requires holding mutex 'mu_'}} \
                           // expected-warning {{reading variable 'c' requires holding mutex 'foop->cell_mu_'}}

    (*foop).c  = Cell(0);    // expected-warning {{writing the value pointed to by 'foop' requires holding mutex 'mu_'}} \
                             // expected-warning {{writing variable 'c' requires holding mutex 'foop->cell_mu_' exclusively}}
    (*foop).c.cellMethod();  // expected-warning {{reading the value pointed to by 'foop' requires holding mutex 'mu_'}} \
                             // expected-warning {{reading variable 'c' requires holding mutex 'foop->cell_mu_'}}
  };
};

}  // namespace GuardedNonPrimitive_MemberAccess


namespace TestThrowExpr {

class Foo {
  Mutex mu_;

  bool hasError();

  void test() {
    mu_.Lock();
    if (hasError()) {
      throw "ugly";
    }
    mu_.Unlock();
  }
};

}  // end namespace TestThrowExpr


namespace UnevaluatedContextTest {

// parse attribute expressions in an unevaluated context.

static inline Mutex* getMutex1();
static inline Mutex* getMutex2();

void bar() EXCLUSIVE_LOCKS_REQUIRED(getMutex1());

void bar2() EXCLUSIVE_LOCKS_REQUIRED(getMutex1(), getMutex2());

}  // end namespace UnevaluatedContextTest


namespace LockUnlockFunctionTest {

// Check built-in lock functions
class LOCKABLE MyLockable  {
public:
  void lock()       EXCLUSIVE_LOCK_FUNCTION() { mu_.Lock(); }
  void readerLock() SHARED_LOCK_FUNCTION()    { mu_.ReaderLock(); }
  void unlock()     UNLOCK_FUNCTION()         { mu_.Unlock(); }

private:
  Mutex mu_;
};


class Foo {
public:
  // Correct lock/unlock functions
  void lock() EXCLUSIVE_LOCK_FUNCTION(mu_) {
    mu_.Lock();
  }

  void readerLock() SHARED_LOCK_FUNCTION(mu_) {
    mu_.ReaderLock();
  }

  void unlock() UNLOCK_FUNCTION(mu_) {
    mu_.Unlock();
  }

  void unlockExclusive() EXCLUSIVE_UNLOCK_FUNCTION(mu_) {
    mu_.Unlock();
  }

  void unlockShared() SHARED_UNLOCK_FUNCTION(mu_) {
    mu_.ReaderUnlock();
  }

  // Check failure to lock.
  void lockBad() EXCLUSIVE_LOCK_FUNCTION(mu_) {    // expected-note {{mutex acquired here}}
    mu2_.Lock();
    mu2_.Unlock();
  }  // expected-warning {{expecting mutex 'mu_' to be held at the end of function}}

  void readerLockBad() SHARED_LOCK_FUNCTION(mu_) {  // expected-note {{mutex acquired here}}
    mu2_.Lock();
    mu2_.Unlock();
  }  // expected-warning {{expecting mutex 'mu_' to be held at the end of function}}

  void unlockBad() UNLOCK_FUNCTION(mu_) {  // expected-note {{mutex acquired here}}
    mu2_.Lock();
    mu2_.Unlock();
  }  // expected-warning {{mutex 'mu_' is still held at the end of function}}

  // Check locking the wrong thing.
  void lockBad2() EXCLUSIVE_LOCK_FUNCTION(mu_) {   // expected-note {{mutex acquired here}}
    mu2_.Lock();            // expected-note {{mutex acquired here}}
  } // expected-warning {{expecting mutex 'mu_' to be held at the end of function}} \
    // expected-warning {{mutex 'mu2_' is still held at the end of function}}


  void readerLockBad2() SHARED_LOCK_FUNCTION(mu_) {   // expected-note {{mutex acquired here}}
    mu2_.ReaderLock();      // expected-note {{mutex acquired here}}
  } // expected-warning {{expecting mutex 'mu_' to be held at the end of function}} \
    // expected-warning {{mutex 'mu2_' is still held at the end of function}}


  void unlockBad2() UNLOCK_FUNCTION(mu_) {  // expected-note {{mutex acquired here}}
    mu2_.Unlock();  // expected-warning {{releasing mutex 'mu2_' that was not held}}
  }  // expected-warning {{mutex 'mu_' is still held at the end of function}}

private:
  Mutex mu_;
  Mutex mu2_;
};

}  // end namespace LockUnlockFunctionTest


namespace AssertHeldTest {

class Foo {
public:
  int c;
  int a GUARDED_BY(mu_);
  Mutex mu_;

  void test1() {
    mu_.AssertHeld();
    int b = a;
    a = 0;
  }

  void test2() {
    mu_.AssertReaderHeld();
    int b = a;
    a = 0;   // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
  }

  void test3() {
    if (c) {
      mu_.AssertHeld();
    }
    else {
      mu_.AssertHeld();
    }
    int b = a;
    a = 0;
  }

  void test4() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
    mu_.AssertHeld();
    int b = a;
    a = 0;
  }

  void test5() UNLOCK_FUNCTION(mu_) {
    mu_.AssertHeld();
    mu_.Unlock();
  }

  void test6() {
    mu_.AssertHeld();
    mu_.Unlock(); // should this be a warning?
  }

  void test7() {
    if (c) {
      mu_.AssertHeld();
    }
    else {
      mu_.Lock();
    }
    int b = a;
    a = 0;
    mu_.Unlock();
  }

  void test8() {
    if (c) {
      mu_.Lock();
    }
    else {
      mu_.AssertHeld();
    }
    // FIXME: should warn, because it's unclear whether we need to release or not.
    int b = a;
    a = 0;
    mu_.Unlock(); // should this be a warning?
  }

  void test9() {
    if (c) {
      mu_.AssertHeld();
    }
    else {
      mu_.Lock();  // expected-note {{mutex acquired here}}
    }
  }  // expected-warning {{mutex 'mu_' is still held at the end of function}}

  void test10() {
    if (c) {
      mu_.Lock();  // expected-note {{mutex acquired here}}
    }
    else {
      mu_.AssertHeld();
    }
  }  // expected-warning {{mutex 'mu_' is still held at the end of function}}

  void assertMu() ASSERT_EXCLUSIVE_LOCK(mu_);

  void test11() {
    assertMu();
    int b = a;
    a = 0;
  }

  void test12() {
    if (c)
      mu_.ReaderLock(); // expected-warning {{mutex 'mu_' is acquired exclusively and shared in the same scope}}
    else
      mu_.AssertHeld(); // expected-note {{the other acquisition of mutex 'mu_' is here}}
    // FIXME: should instead warn because it's unclear whether we need to release or not.
    int b = a;
    a = 0;
    mu_.Unlock();
  }

  void test13() {
    if (c)
      mu_.Lock(); // expected-warning {{mutex 'mu_' is acquired exclusively and shared in the same scope}}
    else
      mu_.AssertReaderHeld(); // expected-note {{the other acquisition of mutex 'mu_' is here}}
    // FIXME: should instead warn because it's unclear whether we need to release or not.
    int b = a;
    a = 0;
    mu_.Unlock();
  }
};

}  // end namespace AssertHeldTest


namespace LogicalConditionalTryLock {

class Foo {
public:
  Mutex mu;
  int a GUARDED_BY(mu);
  bool c;

  bool newc();

  void test1() {
    if (c && mu.TryLock()) {
      a = 0;
      mu.Unlock();
    }
  }

  void test2() {
    bool b = mu.TryLock();
    if (c && b) {
      a = 0;
      mu.Unlock();
    }
  }

  void test3() {
    if (c || !mu.TryLock())
      return;
    a = 0;
    mu.Unlock();
  }

  void test4() {
    while (c && mu.TryLock()) {
      a = 0;
      c = newc();
      mu.Unlock();
    }
  }

  void test5() {
    while (c) {
      if (newc() || !mu.TryLock())
        break;
      a = 0;
      mu.Unlock();
    }
  }

  void test6() {
    mu.Lock();
    do {
      a = 0;
      mu.Unlock();
    } while (newc() && mu.TryLock());
  }

  void test7() {
    for (bool b = mu.TryLock(); c && b;) {
      a = 0;
      mu.Unlock();
    }
  }

  void test8() {
    if (c && newc() && mu.TryLock()) {
      a = 0;
      mu.Unlock();
    }
  }

  void test9() {
    if (!(c && newc() && mu.TryLock()))
      return;
    a = 0;
    mu.Unlock();
  }

  void test10() {
    if (!(c || !mu.TryLock())) {
      a = 0;
      mu.Unlock();
    }
  }
};

}  // end namespace LogicalConditionalTryLock



namespace PtGuardedByTest {

void doSomething();

class Cell {
  public:
  int a;
};


// This mainly duplicates earlier tests, but just to make sure...
class PtGuardedByCorrectnessTest {
  Mutex  mu1;
  Mutex  mu2;
  int*   a GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
  Cell*  c GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
  int    sa[10] GUARDED_BY(mu1);
  Cell   sc[10] GUARDED_BY(mu1);

  static constexpr int Cell::*pa = &Cell::a;

  void test1() {
    mu1.Lock();
    if (a == 0) doSomething();  // OK, we don't dereference.
    a = 0;
    c = 0;
    if (sa[0] == 42) doSomething();
    sa[0] = 57;
    if (sc[0].a == 42) doSomething();
    sc[0].a = 57;
    mu1.Unlock();
  }

  void test2() {
    mu1.ReaderLock();
    if (*a == 0) doSomething();      // expected-warning {{reading the value pointed to by 'a' requires holding mutex 'mu2'}}
    *a = 0;                          // expected-warning {{writing the value pointed to by 'a' requires holding mutex 'mu2' exclusively}}

    if (c->a == 0) doSomething();    // expected-warning {{reading the value pointed to by 'c' requires holding mutex 'mu2'}}
    c->a = 0;                        // expected-warning {{writing the value pointed to by 'c' requires holding mutex 'mu2' exclusively}}
    c->*pa = 0;                      // expected-warning {{writing the value pointed to by 'c' requires holding mutex 'mu2' exclusively}}

    if ((*c).a == 0) doSomething();  // expected-warning {{reading the value pointed to by 'c' requires holding mutex 'mu2'}}
    (*c).a = 0;                      // expected-warning {{writing the value pointed to by 'c' requires holding mutex 'mu2' exclusively}}
    (*c).*pa = 0;                    // expected-warning {{writing the value pointed to by 'c' requires holding mutex 'mu2' exclusively}}

    if (a[0] == 42) doSomething();     // expected-warning {{reading the value pointed to by 'a' requires holding mutex 'mu2'}}
    a[0] = 57;                         // expected-warning {{writing the value pointed to by 'a' requires holding mutex 'mu2' exclusively}}
    if (c[0].a == 42) doSomething();   // expected-warning {{reading the value pointed to by 'c' requires holding mutex 'mu2'}}
    c[0].a = 57;                       // expected-warning {{writing the value pointed to by 'c' requires holding mutex 'mu2' exclusively}}
    mu1.Unlock();
  }

  void test3() {
    mu2.Lock();
    if (*a == 0) doSomething();      // expected-warning {{reading variable 'a' requires holding mutex 'mu1'}}
    *a = 0;                          // expected-warning {{reading variable 'a' requires holding mutex 'mu1'}}

    if (c->a == 0) doSomething();    // expected-warning {{reading variable 'c' requires holding mutex 'mu1'}}
    c->a = 0;                        // expected-warning {{reading variable 'c' requires holding mutex 'mu1'}}

    if ((*c).a == 0) doSomething();  // expected-warning {{reading variable 'c' requires holding mutex 'mu1'}}
    (*c).a = 0;                      // expected-warning {{reading variable 'c' requires holding mutex 'mu1'}}

    if (a[0] == 42) doSomething();     // expected-warning {{reading variable 'a' requires holding mutex 'mu1'}}
    a[0] = 57;                         // expected-warning {{reading variable 'a' requires holding mutex 'mu1'}}
    if (c[0].a == 42) doSomething();   // expected-warning {{reading variable 'c' requires holding mutex 'mu1'}}
    c[0].a = 57;                       // expected-warning {{reading variable 'c' requires holding mutex 'mu1'}}
    mu2.Unlock();
  }

  void test4() {  // Literal arrays
    if (sa[0] == 42) doSomething();     // expected-warning {{reading variable 'sa' requires holding mutex 'mu1'}}
    sa[0] = 57;                         // expected-warning {{writing variable 'sa' requires holding mutex 'mu1' exclusively}}
    if (sc[0].a == 42) doSomething();   // expected-warning {{reading variable 'sc' requires holding mutex 'mu1'}}
    sc[0].a = 57;                       // expected-warning {{writing variable 'sc' requires holding mutex 'mu1' exclusively}}
    sc[0].*pa = 57;                     // expected-warning {{writing variable 'sc' requires holding mutex 'mu1' exclusively}}

    if (*sa == 42) doSomething();       // expected-warning {{reading variable 'sa' requires holding mutex 'mu1'}}
    *sa = 57;                           // expected-warning {{writing variable 'sa' requires holding mutex 'mu1' exclusively}}
    if ((*sc).a == 42) doSomething();   // expected-warning {{reading variable 'sc' requires holding mutex 'mu1'}}
    (*sc).a = 57;                       // expected-warning {{writing variable 'sc' requires holding mutex 'mu1' exclusively}}
    if (sc->a == 42) doSomething();     // expected-warning {{reading variable 'sc' requires holding mutex 'mu1'}}
    sc->a = 57;                         // expected-warning {{writing variable 'sc' requires holding mutex 'mu1' exclusively}}
  }

  void test5() {
    mu1.ReaderLock();    // OK -- correct use.
    mu2.Lock();
    if (*a == 0) doSomething();
    *a = 0;

    if (c->a == 0) doSomething();
    c->a = 0;

    if ((*c).a == 0) doSomething();
    (*c).a = 0;
    mu2.Unlock();
    mu1.Unlock();
  }
};


class SmartPtr_PtGuardedBy_Test {
  Mutex mu1;
  Mutex mu2;
  SmartPtr<int>  sp GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
  SmartPtr<Cell> sq GUARDED_BY(mu1) PT_GUARDED_BY(mu2);

  static constexpr int Cell::*pa = &Cell::a;

  void test1() {
    mu1.ReaderLock();
    mu2.Lock();

    sp.get();
    if (*sp == 0) doSomething();
    *sp = 0;
    sq->a = 0;
    sq->*pa = 0;

    if (sp[0] == 0) doSomething();
    sp[0] = 0;

    mu2.Unlock();
    mu1.Unlock();
  }

  void test2() {
    mu2.Lock();

    sp.get();                      // expected-warning {{reading variable 'sp' requires holding mutex 'mu1'}}
    if (*sp == 0) doSomething();   // expected-warning {{reading variable 'sp' requires holding mutex 'mu1'}}
    *sp = 0;                       // expected-warning {{reading variable 'sp' requires holding mutex 'mu1'}}
    sq->a = 0;                     // expected-warning {{reading variable 'sq' requires holding mutex 'mu1'}}
    sq->*pa = 0;                   // expected-warning {{reading variable 'sq' requires holding mutex 'mu1'}}

    if (sp[0] == 0) doSomething();   // expected-warning {{reading variable 'sp' requires holding mutex 'mu1'}}
    sp[0] = 0;                       // expected-warning {{reading variable 'sp' requires holding mutex 'mu1'}}
    if (sq[0].a == 0) doSomething(); // expected-warning {{reading variable 'sq' requires holding mutex 'mu1'}}
    sq[0].a = 0;                     // expected-warning {{reading variable 'sq' requires holding mutex 'mu1'}}

    mu2.Unlock();
  }

  void test3() {
    mu1.Lock();

    sp.get();
    if (*sp == 0) doSomething();   // expected-warning {{reading the value pointed to by 'sp' requires holding mutex 'mu2'}}
    *sp = 0;                       // expected-warning {{reading the value pointed to by 'sp' requires holding mutex 'mu2'}}
    sq->a = 0;                     // expected-warning {{reading the value pointed to by 'sq' requires holding mutex 'mu2'}}
    sq->*pa = 0;                   // expected-warning {{reading the value pointed to by 'sq' requires holding mutex 'mu2'}}

    if (sp[0] == 0) doSomething();   // expected-warning {{reading the value pointed to by 'sp' requires holding mutex 'mu2'}}
    sp[0] = 0;                       // expected-warning {{reading the value pointed to by 'sp' requires holding mutex 'mu2'}}
    if (sq[0].a == 0) doSomething(); // expected-warning {{reading the value pointed to by 'sq' requires holding mutex 'mu2'}}
    sq[0].a = 0;                     // expected-warning {{reading the value pointed to by 'sq' requires holding mutex 'mu2'}}

    mu1.Unlock();
  }
};

}  // end namespace PtGuardedByTest


namespace NonMemberCalleeICETest {

class A {
  void Run() {
  (RunHelper)();  // expected-warning {{calling function 'RunHelper' requires holding mutex 'M' exclusively}}
 }

 void RunHelper() EXCLUSIVE_LOCKS_REQUIRED(M);
 Mutex M;
};

}  // end namespace NonMemberCalleeICETest


namespace pt_guard_attribute_type {
  int i PT_GUARDED_BY(sls_mu);  // expected-warning {{'pt_guarded_by' only applies to pointer types; type here is 'int'}}
  int j PT_GUARDED_VAR;  // expected-warning {{'pt_guarded_var' only applies to pointer types; type here is 'int'}}

  void test() {
    int i PT_GUARDED_BY(sls_mu);  // expected-warning {{'pt_guarded_by' attribute only applies to non-static data members and global variables}}
    int j PT_GUARDED_VAR;  // expected-warning {{'pt_guarded_var' attribute only applies to non-static data members and global variables}}

    typedef int PT_GUARDED_BY(sls_mu) bad1;  // expected-warning {{'pt_guarded_by' attribute only applies to}}
    typedef int PT_GUARDED_VAR bad2;  // expected-warning {{'pt_guarded_var' attribute only applies to}}
  }
}  // end namespace pt_guard_attribute_type


namespace ThreadAttributesOnLambdas {

class Foo {
  Mutex mu_;

  void LockedFunction() EXCLUSIVE_LOCKS_REQUIRED(mu_);

  void test() {
    auto func1 = [this]() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
      LockedFunction();
    };

    auto func2 = [this]() NO_THREAD_SAFETY_ANALYSIS {
      LockedFunction();
    };

    auto func3 = [this]() EXCLUSIVE_LOCK_FUNCTION(mu_) {
      mu_.Lock();
    };

    func1();  // expected-warning {{calling function 'operator()' requires holding mutex 'mu_' exclusively}}
    func2();
    func3();
    mu_.Unlock();
  }
};

}  // end namespace ThreadAttributesOnLambdas



namespace AttributeExpressionCornerCases {

class Foo {
  int a GUARDED_BY(getMu());

  Mutex* getMu()   LOCK_RETURNED("");
  Mutex* getUniv() LOCK_RETURNED("*");

  void test1() {
    a = 0;
  }

  void test2() EXCLUSIVE_LOCKS_REQUIRED(getUniv()) {
    a = 0;
  }

  void foo(Mutex* mu) EXCLUSIVE_LOCKS_REQUIRED(mu);

  void test3() {
    foo(nullptr);
  }
};


class MapTest {
  struct MuCell { Mutex* mu; };

  MyMap<MyString, Mutex*> map;
  MyMap<MyString, MuCell> mapCell;

  int a GUARDED_BY(map["foo"]);
  int b GUARDED_BY(mapCell["foo"].mu);

  void test() {
    map["foo"]->Lock();
    a = 0;
    map["foo"]->Unlock();
  }

  void test2() {
    mapCell["foo"].mu->Lock();
    b = 0;
    mapCell["foo"].mu->Unlock();
  }
};


class PreciseSmartPtr {
  SmartPtr<Mutex> mu;
  int val GUARDED_BY(mu);

  static bool compare(PreciseSmartPtr& a, PreciseSmartPtr &b) {
    a.mu->Lock();
    bool result = (a.val == b.val);   // expected-warning {{reading variable 'val' requires holding mutex 'b.mu'}} \
                                      // expected-note {{found near match 'a.mu'}}
    a.mu->Unlock();
    return result;
  }
};


class SmartRedeclare {
  SmartPtr<Mutex> mu;
  int val GUARDED_BY(mu);

  void test()  EXCLUSIVE_LOCKS_REQUIRED(mu);
  void test2() EXCLUSIVE_LOCKS_REQUIRED(mu.get());
  void test3() EXCLUSIVE_LOCKS_REQUIRED(mu.get());
};


void SmartRedeclare::test() EXCLUSIVE_LOCKS_REQUIRED(mu.get()) {
  val = 0;
}

void SmartRedeclare::test2() EXCLUSIVE_LOCKS_REQUIRED(mu) {
  val = 0;
}

void SmartRedeclare::test3() {
  val = 0;
}


namespace CustomMutex {


class LOCKABLE BaseMutex { };
class DerivedMutex : public BaseMutex { };

void customLock(const BaseMutex *m)   EXCLUSIVE_LOCK_FUNCTION(m);
void customUnlock(const BaseMutex *m) UNLOCK_FUNCTION(m);

static struct DerivedMutex custMu;

static void doSomethingRequiringLock() EXCLUSIVE_LOCKS_REQUIRED(custMu) { }

void customTest() {
  customLock(reinterpret_cast<BaseMutex*>(&custMu));  // ignore casts
  doSomethingRequiringLock();
  customUnlock(reinterpret_cast<BaseMutex*>(&custMu));
}

} // end namespace CustomMutex

} // end AttributeExpressionCornerCases


namespace ScopedLockReturnedInvalid {

class Opaque;

Mutex* getMutex(Opaque* o) LOCK_RETURNED("");

void test(Opaque* o) {
  MutexLock lock(getMutex(o));
}

}  // end namespace ScopedLockReturnedInvalid


namespace NegativeRequirements {

class Bar {
  Mutex mu;
  int a GUARDED_BY(mu);

public:
  void baz() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
    mu.Lock();
    a = 0;
    mu.Unlock();
  }
};


class Foo {
  Mutex mu;
  int a GUARDED_BY(mu);

public:
  void foo() {
    mu.Lock();    // warning?  needs !mu?
    baz();        // expected-warning {{cannot call function 'baz' while mutex 'mu' is held}}
    bar();
    mu.Unlock();
  }

  void bar() {
    bar2();       // expected-warning {{calling function 'bar2' requires negative capability '!mu'}}
  }

  void bar2() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
    baz();
  }

  void baz() EXCLUSIVE_LOCKS_REQUIRED(!mu) {
    mu.Lock();
    a = 0;
    mu.Unlock();
  }

  void test() {
    Bar b;
    b.baz();     // no warning -- in different class.
  }
};

}   // end namespace NegativeRequirements


namespace NegativeThreadRoles {

typedef int __attribute__((capability("role"))) ThreadRole;

void acquire(ThreadRole R) EXCLUSIVE_LOCK_FUNCTION(R) NO_THREAD_SAFETY_ANALYSIS {}
void release(ThreadRole R) UNLOCK_FUNCTION(R) NO_THREAD_SAFETY_ANALYSIS {}

ThreadRole FlightControl, Logger;

extern void enque_log_msg(const char *msg);
void log_msg(const char *msg) {
  enque_log_msg(msg);
}

void dispatch_log(const char *msg) __attribute__((requires_capability(!FlightControl))) {}
void dispatch_log2(const char *msg) __attribute__((requires_capability(Logger))) {}

void flight_control_entry(void) __attribute__((requires_capability(FlightControl))) {
  dispatch_log("wrong"); /* expected-warning {{cannot call function 'dispatch_log' while mutex 'FlightControl' is held}} */
  dispatch_log2("also wrong"); /* expected-warning {{calling function 'dispatch_log2' requires holding role 'Logger' exclusively}} */
}

void spawn_fake_flight_control_thread(void) {
  acquire(FlightControl);
  flight_control_entry();
  release(FlightControl);
}

extern const char *deque_log_msg(void) __attribute__((requires_capability(Logger)));
void logger_entry(void) __attribute__((requires_capability(Logger)))
                        __attribute__((requires_capability(!FlightControl))) {
  const char *msg;

  while ((msg = deque_log_msg())) {
    dispatch_log(msg);
  }
}

void spawn_fake_logger_thread(void) __attribute__((requires_capability(!FlightControl))) {
  acquire(Logger);
  logger_entry();
  release(Logger);
}

int main(void) __attribute__((requires_capability(!FlightControl))) {
  spawn_fake_flight_control_thread();
  spawn_fake_logger_thread();

  for (;;)
    ; /* Pretend to dispatch things. */

  return 0;
}

} // end namespace NegativeThreadRoles


namespace AssertSharedExclusive {

void doSomething();

class Foo {
  Mutex mu;
  int a GUARDED_BY(mu);

  void test() SHARED_LOCKS_REQUIRED(mu) {
    mu.AssertHeld();
    if (a > 0)
      doSomething();
  }
};

} // end namespace AssertSharedExclusive


namespace RangeBasedForAndReferences {

class Foo {
  struct MyStruct {
    int a;
  };

  Mutex mu;
  int a GUARDED_BY(mu);
  MyContainer<int>  cntr  GUARDED_BY(mu);
  MyStruct s GUARDED_BY(mu);
  int arr[10] GUARDED_BY(mu);

  void nonref_test() {
    int b = a;             // expected-warning {{reading variable 'a' requires holding mutex 'mu'}}
    b = 0;                 // no warning
  }

  void auto_test() {
    auto b = a;            // expected-warning {{reading variable 'a' requires holding mutex 'mu'}}
    b = 0;                 // no warning
    auto &c = a;           // no warning
    c = 0;                 // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
  }

  void ref_test() {
    int &b = a;
    int &c = b;
    int &d = c;
    b = 0;                 // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
    c = 0;                 // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}
    d = 0;                 // expected-warning {{writing variable 'a' requires holding mutex 'mu' exclusively}}

    MyStruct &rs = s;
    rs.a = 0;              // expected-warning {{writing variable 's' requires holding mutex 'mu' exclusively}}

    int (&rarr)[10] = arr;
    rarr[2] = 0;           // expected-warning {{writing variable 'arr' requires holding mutex 'mu' exclusively}}
  }

  void ptr_test() {
    int *b = &a;
    *b = 0;                // no expected warning yet
  }

  void for_test() {
    int total = 0;
    for (int i : cntr) {   // expected-warning2 {{reading variable 'cntr' requires holding mutex 'mu'}}
      total += i;
    }
  }
};


} // end namespace RangeBasedForAndReferences



namespace PassByRefTest {

class Foo {
public:
  Foo() : a(0), b(0) { }

  int a;
  int b;

  void operator+(const Foo& f);

  void operator[](const Foo& g);

  void operator()();
};

template<class T>
T&& mymove(T& f);


// test top-level functions
void copy(Foo f);
void write1(Foo& f);
void write2(int a, Foo& f);
void read1(const Foo& f);
void read2(int a, const Foo& f);
void destroy(Foo&& f);

void operator/(const Foo& f, const Foo& g);
void operator*(const Foo& f, const Foo& g);

// Test constructors.
struct FooRead {
  FooRead(const Foo &);
};
struct FooWrite {
  FooWrite(Foo &);
};

// Test variadic functions
template<typename... T>
void copyVariadic(T...) {}
template<typename... T>
void writeVariadic(T&...) {}
template<typename... T>
void readVariadic(const T&...) {}

void copyVariadicC(int, ...);

class Bar {
public:
  Mutex mu;
  Foo           foo   GUARDED_BY(mu);
  Foo           foo2  GUARDED_BY(mu);
  Foo*          foop  PT_GUARDED_BY(mu);
  SmartPtr<Foo> foosp PT_GUARDED_BY(mu);

  // test methods.
  void mwrite1(Foo& f);
  void mwrite2(int a, Foo& f);
  void mread1(const Foo& f);
  void mread2(int a, const Foo& f);

  // static methods
  static void smwrite1(Foo& f);
  static void smwrite2(int a, Foo& f);
  static void smread1(const Foo& f);
  static void smread2(int a, const Foo& f);

  void operator<<(const Foo& f);

  void test1() {
    copy(foo);             // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}}
    write1(foo);           // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    write2(10, foo);       // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    read1(foo);            // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    read2(10, foo);        // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    destroy(mymove(foo));  // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}

    copyVariadic(foo);     // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}}
    readVariadic(foo);     // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    writeVariadic(foo);    // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    copyVariadicC(1, foo); // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}}

    FooRead reader(foo);   // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    FooWrite writer(foo);  // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}

    mwrite1(foo);           // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    mwrite2(10, foo);       // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    mread1(foo);            // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    mread2(10, foo);        // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}

    smwrite1(foo);           // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    smwrite2(10, foo);       // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    smread1(foo);            // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}
    smread2(10, foo);        // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}

    foo + foo2;              // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}} \
                             // expected-warning {{passing variable 'foo2' by reference requires holding mutex 'mu'}}
    foo / foo2;              // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}} \
                             // expected-warning {{passing variable 'foo2' by reference requires holding mutex 'mu'}}
    foo * foo2;              // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}} \
                             // expected-warning {{passing variable 'foo2' by reference requires holding mutex 'mu'}}
    foo[foo2];               // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}} \
                             // expected-warning {{passing variable 'foo2' by reference requires holding mutex 'mu'}}
    foo();                   // expected-warning {{reading variable 'foo' requires holding mutex 'mu'}}
    (*this) << foo;          // expected-warning {{passing variable 'foo' by reference requires holding mutex 'mu'}}

    copy(*foop);             // expected-warning {{reading the value pointed to by 'foop' requires holding mutex 'mu'}}
    write1(*foop);           // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
    write2(10, *foop);       // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
    read1(*foop);            // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
    read2(10, *foop);        // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}
    destroy(mymove(*foop));  // expected-warning {{passing the value that 'foop' points to by reference requires holding mutex 'mu'}}

    copy(*foosp);             // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
    write1(*foosp);           // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
    write2(10, *foosp);       // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
    read1(*foosp);            // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
    read2(10, *foosp);        // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
    destroy(mymove(*foosp));  // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}

    // TODO -- these require better smart pointer handling.
    copy(*foosp.get());
    write1(*foosp.get());
    write2(10, *foosp.get());
    read1(*foosp.get());
    read2(10, *foosp.get());
    destroy(mymove(*foosp.get()));
  }
};


}  // end namespace PassByRefTest


namespace AcquiredBeforeAfterText {

class Foo {
  Mutex mu1 ACQUIRED_BEFORE(mu2, mu3);
  Mutex mu2;
  Mutex mu3;

  void test1() {
    mu1.Lock();
    mu2.Lock();
    mu3.Lock();

    mu3.Unlock();
    mu2.Unlock();
    mu1.Unlock();
  }

  void test2() {
    mu2.Lock();
    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}
    mu1.Unlock();
    mu2.Unlock();
  }

  void test3() {
    mu3.Lock();
    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}
    mu1.Unlock();
    mu3.Unlock();
  }

  void test4() EXCLUSIVE_LOCKS_REQUIRED(mu1) {
    mu2.Lock();
    mu2.Unlock();
  }

  void test5() EXCLUSIVE_LOCKS_REQUIRED(mu2) {
    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}
    mu1.Unlock();
  }

  void test6() EXCLUSIVE_LOCKS_REQUIRED(mu2) {
    mu1.AssertHeld();
  }

  void test7() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2, mu3) { }

  void test8() EXCLUSIVE_LOCKS_REQUIRED(mu3, mu2, mu1) { }
};


class Foo2 {
  Mutex mu1;
  Mutex mu2 ACQUIRED_AFTER(mu1);
  Mutex mu3 ACQUIRED_AFTER(mu1);

  void test1() {
    mu1.Lock();
    mu2.Lock();
    mu3.Lock();

    mu3.Unlock();
    mu2.Unlock();
    mu1.Unlock();
  }

  void test2() {
    mu2.Lock();
    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}
    mu1.Unlock();
    mu2.Unlock();
  }

  void test3() {
    mu3.Lock();
    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}
    mu1.Unlock();
    mu3.Unlock();
  }
};


class Foo3 {
  Mutex mu1 ACQUIRED_BEFORE(mu2);
  Mutex mu2;
  Mutex mu3 ACQUIRED_AFTER(mu2) ACQUIRED_BEFORE(mu4);
  Mutex mu4;

  void test1() {
    mu1.Lock();
    mu2.Lock();
    mu3.Lock();
    mu4.Lock();

    mu4.Unlock();
    mu3.Unlock();
    mu2.Unlock();
    mu1.Unlock();
  }

  void test2() {
    mu4.Lock();
    mu2.Lock();     // expected-warning {{mutex 'mu2' must be acquired before 'mu4'}}

    mu2.Unlock();
    mu4.Unlock();
  }

  void test3() {
    mu4.Lock();
    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu4'}}

    mu1.Unlock();
    mu4.Unlock();
  }

  void test4() {
    mu3.Lock();
    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}

    mu1.Unlock();
    mu3.Unlock();
  }
};


// Test transitive DAG traversal with AFTER
class Foo4 {
  Mutex mu1;
  Mutex mu2 ACQUIRED_AFTER(mu1);
  Mutex mu3 ACQUIRED_AFTER(mu1);
  Mutex mu4 ACQUIRED_AFTER(mu2, mu3);
  Mutex mu5 ACQUIRED_AFTER(mu4);
  Mutex mu6 ACQUIRED_AFTER(mu4);
  Mutex mu7 ACQUIRED_AFTER(mu5, mu6);
  Mutex mu8 ACQUIRED_AFTER(mu7);

  void test() {
    mu8.Lock();
    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu8'}}
    mu1.Unlock();
    mu8.Unlock();
  }
};


// Test transitive DAG traversal with BEFORE
class Foo5 {
  Mutex mu1 ACQUIRED_BEFORE(mu2, mu3);
  Mutex mu2 ACQUIRED_BEFORE(mu4);
  Mutex mu3 ACQUIRED_BEFORE(mu4);
  Mutex mu4 ACQUIRED_BEFORE(mu5, mu6);
  Mutex mu5 ACQUIRED_BEFORE(mu7);
  Mutex mu6 ACQUIRED_BEFORE(mu7);
  Mutex mu7 ACQUIRED_BEFORE(mu8);
  Mutex mu8;

  void test() {
    mu8.Lock();
    mu1.Lock();  // expected-warning {{mutex 'mu1' must be acquired before 'mu8'}}
    mu1.Unlock();
    mu8.Unlock();
  }
};


class Foo6 {
  Mutex mu1 ACQUIRED_AFTER(mu3);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu1'}}
  Mutex mu2 ACQUIRED_AFTER(mu1);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu2'}}
  Mutex mu3 ACQUIRED_AFTER(mu2);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu3'}}

  Mutex mu_b ACQUIRED_BEFORE(mu_b);  // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu_b'}}
  Mutex mu_a ACQUIRED_AFTER(mu_a);   // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu_a'}}

  void test0() {
    mu_a.Lock();
    mu_b.Lock();
    mu_b.Unlock();
    mu_a.Unlock();
  }

  void test1a() {
    mu1.Lock();
    mu1.Unlock();
  }

  void test1b() {
    mu1.Lock();
    mu_a.Lock();
    mu_b.Lock();
    mu_b.Unlock();
    mu_a.Unlock();
    mu1.Unlock();
  }

  void test() {
    mu2.Lock();
    mu2.Unlock();
  }

  void test3() {
    mu3.Lock();
    mu3.Unlock();
  }
};

}  // end namespace AcquiredBeforeAfterTest


namespace ScopedAdoptTest {

class Foo {
  Mutex mu;
  int a GUARDED_BY(mu);
  int b;

  void test1() EXCLUSIVE_UNLOCK_FUNCTION(mu) {
    MutexLock slock(&mu, true);
    a = 0;
  }

  void test2() SHARED_UNLOCK_FUNCTION(mu) {
    ReaderMutexLock slock(&mu, true);
    b = a;
  }

  void test3() EXCLUSIVE_LOCKS_REQUIRED(mu) {  // expected-note {{mutex acquired here}}
    MutexLock slock(&mu, true);
    a = 0;
  }  // expected-warning {{expecting mutex 'mu' to be held at the end of function}}

  void test4() SHARED_LOCKS_REQUIRED(mu) {     // expected-note {{mutex acquired here}}
    ReaderMutexLock slock(&mu, true);
    b = a;
  }  // expected-warning {{expecting mutex 'mu' to be held at the end of function}}

};

}  // end namespace ScopedAdoptTest


namespace TestReferenceNoThreadSafetyAnalysis {

#define TS_UNCHECKED_READ(x) ts_unchecked_read(x)

// Takes a reference to a guarded data member, and returns an unguarded
// reference.
template <class T>
inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
  return v;
}

template <class T>
inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
  return v;
}


class Foo {
public:
  Foo(): a(0) { }

  int a;
};


class Bar {
public:
  Bar() : a(0) { }

  Mutex mu;
  int a   GUARDED_BY(mu);
  Foo foo GUARDED_BY(mu);
};


void test() {
  Bar bar;
  const Bar cbar;

  int a = TS_UNCHECKED_READ(bar.a);       // nowarn
  TS_UNCHECKED_READ(bar.a) = 1;           // nowarn

  int b = TS_UNCHECKED_READ(bar.foo).a;   // nowarn
  TS_UNCHECKED_READ(bar.foo).a = 1;       // nowarn

  int c = TS_UNCHECKED_READ(cbar.a);      // nowarn
}

#undef TS_UNCHECKED_READ

}  // end namespace TestReferenceNoThreadSafetyAnalysis


namespace GlobalAcquiredBeforeAfterTest {

Mutex mu1;
Mutex mu2 ACQUIRED_AFTER(mu1);

void test3() {
  mu2.Lock();
  mu1.Lock();  // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}
  mu1.Unlock();
  mu2.Unlock();
}

}  // end namespace  GlobalAcquiredBeforeAfterTest


namespace LifetimeExtensionText {

struct Holder {
  virtual ~Holder() throw() {}
  int i = 0;
};

void test() {
  // Should not crash.
  const auto &value = Holder().i;
}

} // end namespace LifetimeExtensionTest


namespace LockableUnions {

union LOCKABLE MutexUnion {
  int a;
  char* b;

  void Lock()   EXCLUSIVE_LOCK_FUNCTION();
  void Unlock() UNLOCK_FUNCTION();
};

MutexUnion muun2;
MutexUnion muun1 ACQUIRED_BEFORE(muun2);

void test() {
  muun2.Lock();
  muun1.Lock();  // expected-warning {{mutex 'muun1' must be acquired before 'muun2'}}
  muun1.Unlock();
  muun2.Unlock();
}

}  // end namespace LockableUnions

// This used to crash.
class acquired_before_empty_str {
  void WaitUntilSpaceAvailable() {
    lock_.ReaderLock(); // expected-note {{acquired here}}
  } // expected-warning {{mutex 'lock_' is still held at the end of function}}
  Mutex lock_ ACQUIRED_BEFORE("");
};

namespace PR34800 {
struct A {
  operator int() const;
};
struct B {
  bool g() __attribute__((locks_excluded(h))); // expected-warning {{'locks_excluded' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
  int h;
};
struct C {
  B *operator[](int);
};
C c;
void f() { c[A()]->g(); }
} // namespace PR34800

namespace ReturnScopedLockable {
  template<typename Object> class SCOPED_LOCKABLE ReadLockedPtr {
  public:
    ReadLockedPtr(Object *ptr) SHARED_LOCK_FUNCTION((*this)->mutex);
    ReadLockedPtr(ReadLockedPtr &&) SHARED_LOCK_FUNCTION((*this)->mutex);
    ~ReadLockedPtr() UNLOCK_FUNCTION();

    Object *operator->() const { return object; }

  private:
    Object *object;
  };

  struct Object {
    int f() SHARED_LOCKS_REQUIRED(mutex);
    Mutex mutex;
  };

  ReadLockedPtr<Object> get();
  int use() {
    auto ptr = get();
    return ptr->f();
  }
  void use_constructor() {
    auto ptr = ReadLockedPtr<Object>(nullptr);
    ptr->f();
    auto ptr2 = ReadLockedPtr<Object>{nullptr};
    ptr2->f();
    auto ptr3 = (ReadLockedPtr<Object>{nullptr});
    ptr3->f();
  }
  struct Convertible {
    Convertible();
    operator ReadLockedPtr<Object>();
  };
  void use_conversion() {
    ReadLockedPtr<Object> ptr = Convertible();
    ptr->f();
  }
}

namespace PR38640 {
void f() {
  // Self-referencing assignment previously caused an infinite loop when thread
  // safety analysis was enabled.
  int &i = i; // expected-warning {{reference 'i' is not yet bound to a value when used within its own initialization}}
}
}

namespace Derived_Smart_Pointer {
template <class T>
class SmartPtr_Derived : public SmartPtr<T> {};

class Foo {
public:
  SmartPtr_Derived<Mutex> mu_;
  int a GUARDED_BY(mu_);
  int b GUARDED_BY(mu_.get());
  int c GUARDED_BY(*mu_);

  void Lock()   EXCLUSIVE_LOCK_FUNCTION(mu_);
  void Unlock() UNLOCK_FUNCTION(mu_);

  void test0() {
    a = 1;  // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
    b = 1;  // expected-warning {{writing variable 'b' requires holding mutex 'mu_' exclusively}}
    c = 1;  // expected-warning {{writing variable 'c' requires holding mutex 'mu_' exclusively}}
  }

  void test1() {
    Lock();
    a = 1;
    b = 1;
    c = 1;
    Unlock();
  }
};

class Bar {
  SmartPtr_Derived<Foo> foo;

  void test0() {
    foo->a = 1;        // expected-warning {{writing variable 'a' requires holding mutex 'foo->mu_' exclusively}}
    (*foo).b = 1;      // expected-warning {{writing variable 'b' requires holding mutex 'foo->mu_' exclusively}}
    foo.get()->c = 1;  // expected-warning {{writing variable 'c' requires holding mutex 'foo->mu_' exclusively}}
  }

  void test1() {
    foo->Lock();
    foo->a = 1;
    foo->Unlock();

    foo->mu_->Lock();
    foo->b = 1;
    foo->mu_->Unlock();

    MutexLock lock(foo->mu_.get());
    foo->c = 1;
  }
};

class PointerGuard {
  Mutex mu1;
  Mutex mu2;
  SmartPtr_Derived<int> i GUARDED_BY(mu1) PT_GUARDED_BY(mu2);

  void test0() {
    i.get();  // expected-warning {{reading variable 'i' requires holding mutex 'mu1'}}
    *i = 2;   // expected-warning {{reading variable 'i' requires holding mutex 'mu1'}} \
              // expected-warning {{reading the value pointed to by 'i' requires holding mutex 'mu2'}}

  }

  void test1() {
    mu1.Lock();

    i.get();
    *i = 2;   // expected-warning {{reading the value pointed to by 'i' requires holding mutex 'mu2'}}

    mu1.Unlock();
  }

  void test2() {
    mu2.Lock();

    i.get();  // expected-warning {{reading variable 'i' requires holding mutex 'mu1'}}
    *i = 2;   // expected-warning {{reading variable 'i' requires holding mutex 'mu1'}}

    mu2.Unlock();
  }

  void test3() {
    mu1.Lock();
    mu2.Lock();

    i.get();
    *i = 2;

    mu2.Unlock();
    mu1.Unlock();
  }
};
}