brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · a6e0cd7 Raw
280 lines · cpp
1// RUN: %check_clang_tidy -std=c++20 %s cppcoreguidelines-no-suspend-with-lock %t -- -- -fno-delayed-template-parsing -fexceptions2 3// NOLINTBEGIN4namespace std {5template <typename T, typename... Args>6struct coroutine_traits {7  using promise_type = typename T::promise_type;8};9template <typename T = void>10struct coroutine_handle;11template <>12struct coroutine_handle<void> {13  coroutine_handle() noexcept;14  coroutine_handle(decltype(nullptr)) noexcept;15  static constexpr coroutine_handle from_address(void*);16};17template <typename T>18struct coroutine_handle {19  coroutine_handle() noexcept;20  coroutine_handle(decltype(nullptr)) noexcept;21  static constexpr coroutine_handle from_address(void*);22  operator coroutine_handle<>() const noexcept;23};24 25template <class Mutex>26class unique_lock {27public:28  unique_lock() noexcept;29  explicit unique_lock(Mutex &m);30  unique_lock& operator=(unique_lock&&);31  void unlock();32  Mutex* release() noexcept;33  Mutex* mutex() const noexcept;34  void swap(unique_lock& other) noexcept;35};36 37class mutex {38public:39  mutex() noexcept;40  ~mutex();41  mutex(const mutex &) = delete;42  mutex &operator=(const mutex &) = delete;43 44  void lock();45  void unlock();46};47} // namespace std48 49class my_own_mutex {50public:51  void lock();52  void unlock();53};54 55struct Awaiter {56  bool await_ready() noexcept;57  void await_suspend(std::coroutine_handle<>) noexcept;58  void await_resume() noexcept;59};60 61struct Coro {62  struct promise_type {63    Awaiter initial_suspend();64    Awaiter final_suspend() noexcept;65    void return_void();66    Coro get_return_object();67    void unhandled_exception();68    Awaiter yield_value(int);69  };70};71// NOLINTEND72 73std::mutex mtx;74std::mutex mtx2;75 76Coro awaits_with_lock() {77  std::unique_lock<std::mutex> lock(mtx);78 79  co_await Awaiter{};80  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]81 82  co_await Awaiter{};83  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]84 85  if (true) {86    co_await Awaiter{};87    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]88  }89 90  if (true) {91    std::unique_lock<std::mutex> lock2;92    lock2.unlock();93    co_await Awaiter{};94    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock2' held [cppcoreguidelines-no-suspend-with-lock]95  }96}97 98Coro awaits_with_lock_in_try() try {99  std::unique_lock<std::mutex> lock(mtx);100  co_await Awaiter{};101  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]102} catch (...) {}103 104Coro lock_possibly_unlocked() {105  // CppCoreGuideline CP.52's enforcement strictly requires flagging106  // code that suspends while any lock guard is not destructed.107 108  {109    std::unique_lock<std::mutex> lock(mtx);110    lock.unlock();111    co_await Awaiter{};112    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]113  }114 115  {116    std::unique_lock<std::mutex> lock(mtx);117    lock.release();118    co_await Awaiter{};119    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]120  }121 122  {123    std::unique_lock<std::mutex> lock(mtx);124    std::unique_lock<std::mutex> lock2;125    lock.swap(lock2);126    co_await Awaiter{};127    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]128  }129 130  {131    std::unique_lock<std::mutex> lock(mtx);132    std::unique_lock<std::mutex> lock2{mtx2};133    lock.swap(lock2);134    co_await Awaiter{};135    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]136  }137 138  {139    std::unique_lock<std::mutex> lock(mtx);140    lock = std::unique_lock<std::mutex>{};141    co_await Awaiter{};142    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]143  }144 145  {146    std::unique_lock<std::mutex> lock(mtx);147    lock = std::unique_lock<std::mutex>{mtx2};148    co_await Awaiter{};149    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]150  }151}152 153Coro await_with_underlying_mutex_unlocked() {154  std::unique_lock<std::mutex> lock(mtx);155 156  // Even though we unlock the mutex here, 'lock' is still active unless157  // there is a call to lock.unlock(). This is a bug in the program since158  // it will result in locking the mutex twice. The check does not track159  // unlock calls on the underlying mutex held by a lock guard object.160  mtx.unlock();161 162  co_await Awaiter{};163  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]164}165 166Coro await_with_empty_lock() {167  std::unique_lock<std::mutex> lock;168  co_await Awaiter{};169  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]170}171 172Coro await_before_lock() {173  co_await Awaiter{};174  std::unique_lock<std::mutex> lock(mtx);175}176 177Coro await_with_lock_different_scope() {178  {179    std::unique_lock<std::mutex> lock(mtx);180  }181  co_await Awaiter{};182}183 184Coro await_with_goto() {185first:186  co_await Awaiter{};187  std::unique_lock<std::mutex> lock(mtx);188  goto first;189}190 191void await_in_lambda() {192  auto f1 = []() -> Coro {193    std::unique_lock<std::mutex> lock(mtx);194    co_await Awaiter{};195    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]196  };197 198  auto f2 = [](auto& m) -> Coro {199    std::unique_lock<decltype(m)> lock(m);200    co_await Awaiter{};201    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]202  };203}204 205void await_in_lambda_without_immediate_mutex() {206  std::unique_lock<std::mutex> lock(mtx);207 208  auto f1 = []() -> Coro {209    co_await Awaiter{};210  };211 212  // The check only finds suspension points where there is a lock held in the213  // immediate callable.214  f1();215}216 217Coro yields_with_lock() {218  std::unique_lock<std::mutex> lock(mtx);219  co_yield 0;220  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]221}222 223template <class Mutex>224Coro awaits_templated_type(Mutex& m) {225  std::unique_lock<Mutex> lock(m);226  co_await Awaiter{};227  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]228}229 230template <class T>231Coro awaits_in_template_function(T) {232  std::unique_lock<std::mutex> lock(mtx);233  co_await Awaiter{};234  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]235}236 237template <class Mutex>238Coro awaits_in_never_instantiated_template_of_mutex(Mutex& m) {239  // Nothing should instantiate this function240  std::unique_lock<Mutex> lock(m);241  co_await Awaiter{};242  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]243}244 245template <class T>246Coro awaits_in_never_instantiated_templated_function(T) {247  // Nothing should instantiate this function248  std::unique_lock<std::mutex> lock(mtx);249  co_await Awaiter{};250  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]251}252 253template <class T>254struct my_container {255 256  Coro push_back() {257    std::unique_lock<std::mutex> lock(mtx_);258    co_await Awaiter{};259    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]260  }261 262  template <class... Args>263  Coro emplace_back(Args&&...) {264    std::unique_lock<std::mutex> lock(mtx_);265    co_await Awaiter{};266    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: coroutine suspended with lock 'lock' held [cppcoreguidelines-no-suspend-with-lock]267  }268 269  std::mutex mtx_;270};271 272void calls_templated_functions() {273  my_own_mutex m2;274  awaits_templated_type(mtx);275  awaits_templated_type(m2);276 277  awaits_in_template_function(1);278  awaits_in_template_function(1.0);279}280