diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index a25bd6007d5ed..c8d61534d0441 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -43,6 +43,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TrailingObjects.h" #include "llvm/Support/raw_ostream.h" @@ -2820,6 +2821,12 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { case CFGElement::AutomaticObjectDtor: { CFGAutomaticObjDtor AD = BI.castAs(); const auto *DD = AD.getDestructorDecl(AC.getASTContext()); + // Function parameters as they are constructed in caller's context and + // the CFG does not contain the ctors. Ignore them as their + // capabilities cannot be analysed because of this missing + // information. + if (isa_and_nonnull(AD.getVarDecl())) + break; if (!DD || !DD->hasAttrs()) break; diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp index 0e91639a271c5..7cb416d71569c 100644 --- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -1849,6 +1849,43 @@ struct TestScopedLockable { } }; +namespace test_function_param_lock_unlock { +class A { + public: + A() EXCLUSIVE_LOCK_FUNCTION(mu_) { mu_.Lock(); } + ~A() UNLOCK_FUNCTION(mu_) { mu_.Unlock(); } + private: + Mutex mu_; +}; +int do_something(A a) { return 0; } + +// Unlock in dtor without lock in ctor. +// FIXME: We cannot detect that we are releasing a lock that was never held! +class B { + public: + B() {} + B(int) {} + ~B() UNLOCK_FUNCTION(mu_) { mu_.Unlock(); } + private: + Mutex mu_; +}; +int do_something(B b) { return 0; } + +class SCOPED_LOCKABLE MutexWrapper { +public: + MutexWrapper(Mutex *mu) : mu_(mu) {} + ~MutexWrapper() UNLOCK_FUNCTION(mu_) { mu_->Unlock(); } + void Lock() EXCLUSIVE_LOCK_FUNCTION(mu_) { mu_->Lock(); } + + Mutex *mu_; +}; +// FIXME: This is a false-positive as the lock is released by the dtor. +void do_something(MutexWrapper mw) { + mw.Lock(); // expected-note {{mutex acquired here}} +} // expected-warning {{mutex 'mw.mu_' is still held at the end of function}} + +} // namespace test_function_param_lock_unlock + } // end namespace test_scoped_lockable