modernize-use-scoped-lock

Finds uses of std::lock_guard and suggests replacing them with C++17’s alternative std::scoped_lock.

Fix-its are provided for single declarations of std::lock_guard and warning is emitted for multiple declarations of std::lock_guard that can be replaced with a single declaration of std::scoped_lock.

Examples

Single std::lock_guard declaration:

std::mutex M;
std::lock_guard<std::mutex> L(M);

Transforms to:

std::mutex M;
std::scoped_lock L(M);

Single std::lock_guard declaration with std::adopt_lock:

std::mutex M;
std::lock(M);
std::lock_guard<std::mutex> L(M, std::adopt_lock);

Transforms to:

std::mutex M;
std::lock(M);
std::scoped_lock L(std::adopt_lock, M);

Multiple std::lock_guard declarations only emit warnings:

std::mutex M1, M2;
std::lock(M1, M2);
std::lock_guard Lock1(M, std::adopt_lock); // warning: use single 'std::scoped_lock' instead of multiple 'std::lock_guard'
std::lock_guard Lock2(M, std::adopt_lock); // note: additional 'std::lock_guard' declared here

Limitations

The check will not emit warnings if std::lock_guard is used implicitly via template parameter:

template <template <typename> typename Lock>
void TemplatedLock() {
  std::mutex M;
  Lock<std::mutex> L(M); // no warning
}

void instantiate() {
  TemplatedLock<std::lock_guard>();
}

Options

WarnOnSingleLocks

When true, the check will warn on single std::lock_guard declarations. Set this option to false if you want to get warnings only on multiple std::lock_guard declarations that can be replaced with a single std::scoped_lock. Default is true.

WarnOnUsingAndTypedef

When true, the check will emit warnings if std::lock_guard is used in using or typedef context. Default is true.

template <typename T>
using Lock = std::lock_guard<T>; // warning: use 'std::scoped_lock' instead of 'std::lock_guard'

using LockMutex = std::lock_guard<std::mutex>; // warning: use 'std::scoped_lock' instead of 'std::lock_guard'

typedef std::lock_guard<std::mutex> LockDef; // warning: use 'std::scoped_lock' instead of 'std::lock_guard'

using std::lock_guard; // warning: use 'std::scoped_lock' instead of 'std::lock_guard'