[clang-tidy] Add spuriously-wake-up-functions check

Summary:
According to
https://wiki.sei.cmu.edu/confluence/display/cplusplus/CON54-CPP.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop
and
https://wiki.sei.cmu.edu/confluence/display/c/CON36-C.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop
misc-spuriously-wake-up-functions check is created. The check finds
`cnd_wait` or `wait` function calls in an `IfStmt` and  warns the user to
replace it with a `WhileStmt` or use it with a lambda parameter.

Reviewers: aaron.ballman, alexfh, hokein, jfb, Charusso

Reviewed By: aaron.ballman

Subscribers: sylvestre.ledru, whisperity, Eugene.Zelenko, mgorny, dexonsmith, cfe-commits, gerazo, xazax.hun, steakhal, Charusso

Tags: #clang-tools-extra, #clang

Differential Revision: https://reviews.llvm.org/D70876
This commit is contained in:
abelkocsis 2020-03-21 12:02:00 +01:00
parent c5fd9e3888
commit 0f4c70dd3e
12 changed files with 581 additions and 0 deletions

View File

@ -41,6 +41,7 @@
#include "SignedCharMisuseCheck.h"
#include "SizeofContainerCheck.h"
#include "SizeofExpressionCheck.h"
#include "SpuriouslyWakeUpFunctionsCheck.h"
#include "StringConstructorCheck.h"
#include "StringIntegerAssignmentCheck.h"
#include "StringLiteralWithEmbeddedNulCheck.h"
@ -133,6 +134,8 @@ public:
"bugprone-sizeof-container");
CheckFactories.registerCheck<SizeofExpressionCheck>(
"bugprone-sizeof-expression");
CheckFactories.registerCheck<SpuriouslyWakeUpFunctionsCheck>(
"bugprone-spuriously-wake-up-functions");
CheckFactories.registerCheck<StringConstructorCheck>(
"bugprone-string-constructor");
CheckFactories.registerCheck<StringIntegerAssignmentCheck>(

View File

@ -33,6 +33,7 @@ add_clang_library(clangTidyBugproneModule
SignedCharMisuseCheck.cpp
SizeofContainerCheck.cpp
SizeofExpressionCheck.cpp
SpuriouslyWakeUpFunctionsCheck.cpp
StringConstructorCheck.cpp
StringIntegerAssignmentCheck.cpp
StringLiteralWithEmbeddedNulCheck.cpp

View File

@ -0,0 +1,108 @@
//===--- SpuriouslyWakeUpFunctionsCheck.cpp - clang-tidy ------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "SpuriouslyWakeUpFunctionsCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace bugprone {
void SpuriouslyWakeUpFunctionsCheck::registerMatchers(MatchFinder *Finder) {
auto hasUniqueLock = hasDescendant(declRefExpr(
hasDeclaration(varDecl(hasType(recordDecl(classTemplateSpecializationDecl(
hasName("::std::unique_lock"),
hasTemplateArgument(
0, templateArgument(refersToType(qualType(hasDeclaration(
cxxRecordDecl(hasName("::std::mutex"))))))))))))));
auto hasWaitDescendantCPP = hasDescendant(
cxxMemberCallExpr(
anyOf(
allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
allOf(hasName("::std::condition_variable::wait"),
parameterCountIs(1)))))),
onImplicitObjectArgument(
declRefExpr(to(varDecl(hasType(references(recordDecl(
hasName("::std::condition_variable")))))))),
hasUniqueLock),
allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
allOf(hasName("::std::condition_variable::wait_for"),
parameterCountIs(2)))))),
onImplicitObjectArgument(
declRefExpr(to(varDecl(hasType(references(recordDecl(
hasName("::std::condition_variable")))))))),
hasUniqueLock),
allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
allOf(hasName("::std::condition_variable::wait_until"),
parameterCountIs(2)))))),
onImplicitObjectArgument(
declRefExpr(to(varDecl(hasType(references(recordDecl(
hasName("::std::condition_variable")))))))),
hasUniqueLock)
))
.bind("wait"));
auto hasWaitDescendantC = hasDescendant(
callExpr(callee(functionDecl(
anyOf(hasName("cnd_wait"), hasName("cnd_timedwait")))))
.bind("wait"));
if (getLangOpts().CPlusPlus) {
// Check for `CON54-CPP`
Finder->addMatcher(
ifStmt(
allOf(hasWaitDescendantCPP,
unless(anyOf(hasDescendant(ifStmt(hasWaitDescendantCPP)),
hasDescendant(whileStmt(hasWaitDescendantCPP)),
hasDescendant(forStmt(hasWaitDescendantCPP)),
hasDescendant(doStmt(hasWaitDescendantCPP)))))
),
this);
} else {
// Check for `CON36-C`
Finder->addMatcher(
ifStmt(
allOf(hasWaitDescendantC,
unless(anyOf(hasDescendant(ifStmt(hasWaitDescendantC)),
hasDescendant(whileStmt(hasWaitDescendantC)),
hasDescendant(forStmt(hasWaitDescendantC)),
hasDescendant(doStmt(hasWaitDescendantC)),
hasParent(whileStmt()),
hasParent(compoundStmt(hasParent(whileStmt()))),
hasParent(forStmt()),
hasParent(compoundStmt(hasParent(forStmt()))),
hasParent(doStmt()),
hasParent(compoundStmt(hasParent(doStmt())))))
))
,
this);
}
}
void SpuriouslyWakeUpFunctionsCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *MatchedWait = Result.Nodes.getNodeAs<CallExpr>("wait");
StringRef WaitName = MatchedWait->getDirectCallee()->getName();
diag(MatchedWait->getExprLoc(),
"'%0' should be placed inside a while statement %select{|or used with a "
"conditional parameter}1")
<< WaitName << (WaitName != "cnd_wait" && WaitName != "cnd_timedwait");
}
} // namespace bugprone
} // namespace tidy
} // namespace clang

View File

@ -0,0 +1,37 @@
//===--- SpuriouslyWakeUpFunctionsCheck.h - clang-tidy ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H
#include "../ClangTidyCheck.h"
namespace clang {
namespace tidy {
namespace bugprone {
/// Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
/// ``wait_until`` function calls when the function is not invoked from a loop
/// that checks whether a condition predicate holds or the function has a
/// condition parameter.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-spuriously-wake-up-functions.html
class SpuriouslyWakeUpFunctionsCheck : public ClangTidyCheck {
public:
SpuriouslyWakeUpFunctionsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace bugprone
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H

View File

@ -11,6 +11,7 @@
#include "../ClangTidyModuleRegistry.h"
#include "../bugprone/BadSignalToKillThreadCheck.h"
#include "../bugprone/ReservedIdentifierCheck.h"
#include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h"
#include "../bugprone/UnhandledSelfAssignmentCheck.h"
#include "../google/UnnamedNamespaceInHeaderCheck.h"
#include "../misc/NewDeleteOverloadsCheck.h"
@ -42,6 +43,9 @@ class CERTModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
// C++ checkers
// CON
CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
"cert-con54-cpp");
// DCL
CheckFactories.registerCheck<PostfixOperatorCheck>(
"cert-dcl21-cpp");
@ -80,6 +84,9 @@ public:
"cert-oop58-cpp");
// C checkers
// CON
CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
"cert-con36-c");
// DCL
CheckFactories.registerCheck<misc::StaticAssertCheck>("cert-dcl03-c");
CheckFactories.registerCheck<readability::UppercaseLiteralSuffixCheck>(

View File

@ -87,6 +87,14 @@ New checks
result of a memory allocation function (``malloc()``, ``calloc()``,
``realloc()``, ``alloca()``) instead of its argument.
- New :doc:`bugprone-spuriously-wake-up-functions
<clang-tidy/checks/bugprone-spuriously-wake-up-functions>` check.
Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
``wait_until`` function calls when the function is not invoked from a loop
that checks whether a condition predicate holds or the function has a
condition parameter.
- New :doc:`bugprone-reserved-identifier
<clang-tidy/checks/bugprone-reserved-identifier>` check.
@ -124,6 +132,16 @@ New checks
New check aliases
^^^^^^^^^^^^^^^^^
- New alias :doc:`cert-con36-c
<clang-tidy/checks/cert-con36-c>` to
:doc:`bugprone-spuriously-wake-up-functions
<clang-tidy/checks/bugprone-spuriously-wake-up-functions>` was added.
- New alias :doc:`cert-con54-cpp
<clang-tidy/checks/cert-con54-cpp>` to
:doc:`bugprone-spuriously-wake-up-functions
<clang-tidy/checks/bugprone-spuriously-wake-up-functions>` was added.
- New alias :doc:`cert-dcl37-c
<clang-tidy/checks/cert-dcl37-c>` to
:doc:`bugprone-reserved-identifier

View File

@ -0,0 +1,29 @@
.. title:: clang-tidy - bugprone-spuriously-wake-up-functions
bugprone-spuriously-wake-up-functions
=====================================
Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
``wait_until`` function calls when the function is not invoked from a loop
that checks whether a condition predicate holds or the function has a
condition parameter.
.. code-block: c++
if (condition_predicate) {
condition.wait(lk);
}
.. code-block: c
if (condition_predicate) {
if (thrd_success != cnd_wait(&condition, &lock)) {
}
}
This check corresponds to the CERT C++ Coding Standard rule
`CON54-CPP. Wrap functions that can spuriously wake up in a loop
<https://wiki.sei.cmu.edu/confluence/display/cplusplus/CON54-CPP.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop>`_.
and CERT C Coding Standard rule
`CON36-C. Wrap functions that can spuriously wake up in a loop
<https://wiki.sei.cmu.edu/confluence/display/c/CON36-C.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop>`_.

View File

@ -0,0 +1,10 @@
.. title:: clang-tidy - cert-con36-c
.. meta::
:http-equiv=refresh: 5;URL=bugprone-spuriously-wake-up-functions.html
cert-con36-c
============
The cert-con36-c check is an alias, please see
`bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_
for more information.

View File

@ -0,0 +1,10 @@
.. title:: clang-tidy - cert-con54-cpp
.. meta::
:http-equiv=refresh: 5;URL=bugprone-spuriously-wake-up-functions.html
cert-con54-cpp
==============
The cert-con54-cpp check is an alias, please see
`bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_
for more information.

View File

@ -76,6 +76,7 @@ Clang-Tidy Checks
`bugprone-signed-char-misuse <bugprone-signed-char-misuse.html>`_,
`bugprone-sizeof-container <bugprone-sizeof-container.html>`_,
`bugprone-sizeof-expression <bugprone-sizeof-expression.html>`_,
`bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
`bugprone-string-constructor <bugprone-string-constructor.html>`_, "Yes"
`bugprone-string-integer-assignment <bugprone-string-integer-assignment.html>`_, "Yes"
`bugprone-string-literal-with-embedded-nul <bugprone-string-literal-with-embedded-nul.html>`_,
@ -300,6 +301,8 @@ Clang-Tidy Checks
.. csv-table:: Aliases..
:header: "Name", "Redirect", "Offers fixes"
`cert-con36-c <cert-con36-c.html>`_, `bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
`cert-con54-cpp <cert-con54-cpp.html>`_, `bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
`cert-dcl03-c <cert-dcl03-c.html>`_, `misc-static-assert <misc-static-assert.html>`_, "Yes"
`cert-dcl16-c <cert-dcl16-c.html>`_, `readability-uppercase-literal-suffix <readability-uppercase-literal-suffix.html>`_, "Yes"
`cert-dcl37-c <cert-dcl37-c.html>`_, `bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_, "Yes"

View File

@ -0,0 +1,164 @@
// RUN: %check_clang_tidy %s bugprone-spuriously-wake-up-functions %t -- --
#define NULL 0
struct Node1 {
void *Node1;
struct Node1 *next;
};
typedef struct mtx_t {
} mtx_t;
typedef struct cnd_t {
} cnd_t;
struct timespec {};
int cnd_wait(cnd_t *cond, mtx_t *mutex){};
int cnd_timedwait(cnd_t *cond, mtx_t *mutex,
const struct timespec *time_point){};
struct Node1 list_c;
static mtx_t lock;
static cnd_t condition_c;
struct timespec ts;
void consume_list_element(void) {
if (list_c.next == NULL) {
if (0 != cnd_wait(&condition_c, &lock)) {
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
}
}
if (list_c.next == NULL)
if (0 != cnd_wait(&condition_c, &lock))
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
;
if (list_c.next == NULL && 0 != cnd_wait(&condition_c, &lock))
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
;
while (list_c.next == NULL) {
if (0 != cnd_wait(&condition_c, &lock)) {
}
}
while (list_c.next == NULL)
if (0 != cnd_wait(&condition_c, &lock)) {
}
while (list_c.next == NULL)
if (0 != cnd_wait(&condition_c, &lock))
;
if (list_c.next == NULL) {
cnd_wait(&condition_c, &lock);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
}
if (list_c.next == NULL)
cnd_wait(&condition_c, &lock);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
while (list_c.next == NULL) {
cnd_wait(&condition_c, &lock);
}
while (list_c.next == NULL)
cnd_wait(&condition_c, &lock);
do {
if (0 != cnd_wait(&condition_c, &lock)) {
}
} while (list_c.next == NULL);
do
if (0 != cnd_wait(&condition_c, &lock)) {
}
while (list_c.next == NULL);
do
if (0 != cnd_wait(&condition_c, &lock))
;
while (list_c.next == NULL);
do {
cnd_wait(&condition_c, &lock);
} while (list_c.next == NULL);
do
cnd_wait(&condition_c, &lock);
while (list_c.next == NULL);
for (;; list_c.next == NULL) {
if (0 != cnd_wait(&condition_c, &lock)) {
}
}
for (;; list_c.next == NULL)
if (0 != cnd_wait(&condition_c, &lock)) {
}
for (;; list_c.next == NULL)
if (0 != cnd_wait(&condition_c, &lock))
;
for (;; list_c.next == NULL) {
cnd_wait(&condition_c, &lock);
}
for (;; list_c.next == NULL)
cnd_wait(&condition_c, &lock);
if (list_c.next == NULL) {
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
}
}
if (list_c.next == NULL)
if (0 != cnd_timedwait(&condition_c, &lock, &ts))
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
;
if (list_c.next == NULL && 0 != cnd_timedwait(&condition_c, &lock, &ts))
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
;
while (list_c.next == NULL) {
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
}
}
while (list_c.next == NULL)
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
}
while (list_c.next == NULL)
if (0 != cnd_timedwait(&condition_c, &lock, &ts))
;
if (list_c.next == NULL) {
cnd_timedwait(&condition_c, &lock, &ts);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
}
if (list_c.next == NULL)
cnd_timedwait(&condition_c, &lock, &ts);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
while (list_c.next == NULL) {
cnd_timedwait(&condition_c, &lock, &ts);
}
while (list_c.next == NULL)
cnd_timedwait(&condition_c, &lock, &ts);
do {
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
}
} while (list_c.next == NULL);
do
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
}
while (list_c.next == NULL);
do
if (0 != cnd_timedwait(&condition_c, &lock, &ts))
;
while (list_c.next == NULL);
do {
cnd_timedwait(&condition_c, &lock, &ts);
} while (list_c.next == NULL);
do
cnd_timedwait(&condition_c, &lock, &ts);
while (list_c.next == NULL);
for (;; list_c.next == NULL) {
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
}
}
for (;; list_c.next == NULL)
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
}
for (;; list_c.next == NULL)
if (0 != cnd_timedwait(&condition_c, &lock, &ts))
;
for (;; list_c.next == NULL) {
cnd_timedwait(&condition_c, &lock, &ts);
}
for (;; list_c.next == NULL)
cnd_timedwait(&condition_c, &lock, &ts);
}
int main() { return 0; }

View File

@ -0,0 +1,191 @@
// RUN: %check_clang_tidy %s bugprone-spuriously-wake-up-functions %t -- --
#define NULL 0
namespace std {
using intmax_t = int;
template <intmax_t N, intmax_t D = 1>
class ratio {
public:
static constexpr intmax_t num = 0;
static constexpr intmax_t den = 0;
typedef ratio<num, den> type;
};
typedef ratio<1, 1000> milli;
namespace chrono {
template <class Rep, class Period = ratio<1>>
class duration {
public:
using rep = Rep;
using period = Period;
public:
constexpr duration() = default;
template <class Rep2>
constexpr explicit duration(const Rep2 &r);
template <class Rep2, class Period2>
constexpr duration(const duration<Rep2, Period2> &d);
~duration() = default;
duration(const duration &) = default;
};
template <class Clock, class Duration = typename Clock::duration>
class time_point {
public:
using clock = Clock;
using duration = Duration;
public:
constexpr time_point();
constexpr explicit time_point(const duration &d);
template <class Duration2>
constexpr time_point(const time_point<clock, Duration2> &t);
};
using milliseconds = duration<int, milli>;
class system_clock {
public:
typedef milliseconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef chrono::time_point<system_clock> time_point;
static time_point now() noexcept;
};
} // namespace chrono
class mutex;
template <class Mutex>
class unique_lock {
public:
typedef Mutex mutex_type;
unique_lock() noexcept;
explicit unique_lock(mutex_type &m);
};
class mutex {
public:
constexpr mutex() noexcept;
~mutex();
mutex(const mutex &) = delete;
mutex &operator=(const mutex &) = delete;
};
enum class cv_status {
no_timeout,
timeout
};
class condition_variable {
public:
condition_variable();
~condition_variable();
condition_variable(const condition_variable &) = delete;
void wait(unique_lock<mutex> &lock);
template <class Predicate>
void wait(unique_lock<mutex> &lock, Predicate pred);
template <class Clock, class Duration>
cv_status wait_until(unique_lock<mutex> &lock,
const chrono::time_point<Clock, Duration> &abs_time){};
template <class Clock, class Duration, class Predicate>
bool wait_until(unique_lock<mutex> &lock,
const chrono::time_point<Clock, Duration> &abs_time,
Predicate pred){};
template <class Rep, class Period>
cv_status wait_for(unique_lock<mutex> &lock,
const chrono::duration<Rep, Period> &rel_time){};
template <class Rep, class Period, class Predicate>
bool wait_for(unique_lock<mutex> &lock,
const chrono::duration<Rep, Period> &rel_time,
Predicate pred){};
};
} // namespace std
struct Node1 {
void *Node1;
struct Node1 *next;
};
static Node1 list;
static std::mutex m;
static std::condition_variable condition;
void consume_list_element(std::condition_variable &condition) {
std::unique_lock<std::mutex> lk(m);
if (list.next == nullptr) {
condition.wait(lk);
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
}
while (list.next == nullptr) {
condition.wait(lk);
}
do {
condition.wait(lk);
} while (list.next == nullptr);
for (;; list.next == nullptr) {
condition.wait(lk);
}
if (list.next == nullptr) {
while (list.next == nullptr) {
condition.wait(lk);
}
}
if (list.next == nullptr) {
do {
condition.wait(lk);
} while (list.next == nullptr);
}
if (list.next == nullptr) {
for (;; list.next == nullptr) {
condition.wait(lk);
}
}
using durtype = std::chrono::duration<int, std::milli>;
durtype dur = std::chrono::duration<int, std::milli>();
if (list.next == nullptr) {
condition.wait_for(lk, dur);
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait_for' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
}
if (list.next == nullptr) {
condition.wait_for(lk, dur, [] { return 1; });
}
while (list.next == nullptr) {
condition.wait_for(lk, dur);
}
do {
condition.wait_for(lk, dur);
} while (list.next == nullptr);
for (;; list.next == nullptr) {
condition.wait_for(lk, dur);
}
auto now = std::chrono::system_clock::now();
if (list.next == nullptr) {
condition.wait_until(lk, now);
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait_until' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
}
if (list.next == nullptr) {
condition.wait_until(lk, now, [] { return 1; });
}
while (list.next == nullptr) {
condition.wait_until(lk, now);
}
do {
condition.wait_until(lk, now);
} while (list.next == nullptr);
for (;; list.next == nullptr) {
condition.wait_until(lk, now);
}
}