diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index 131170df9976e..56055f1ee6e3e 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -2443,6 +2443,22 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &EntrySet, if (join(FactMan[*EntryIt], ExitFact, JoinLoc, EntryLEK)) *EntryIt = Fact; } else if (!ExitFact.managed() || EntryLEK == LEK_LockedAtEndOfFunction) { + if (EntryLEK == LEK_LockedAtEndOfFunction) { + const til::SExpr *Sexp = ExitFact.sexpr(); + const VarDecl *MutexVar = nullptr; + + if (const auto *Proj = dyn_cast(Sexp)) { + if (const auto *Base = dyn_cast(Proj->record())) + MutexVar = dyn_cast_or_null(Base->clangDecl()); + } else if (const auto *LP = dyn_cast(Sexp)) { + MutexVar = dyn_cast_or_null(LP->clangDecl()); + } + + if (MutexVar && MutexVar->getStorageDuration() == SD_Automatic && + MutexVar->getDeclContext() == CurrentFunction) { + continue; + } + } ExitFact.handleRemovalFromIntersection(ExitSet, FactMan, JoinLoc, EntryLEK, Handler); } diff --git a/clang/test/Analysis/thread-safety-lock-scope.cpp b/clang/test/Analysis/thread-safety-lock-scope.cpp new file mode 100644 index 0000000000000..15a547e345275 --- /dev/null +++ b/clang/test/Analysis/thread-safety-lock-scope.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -include %s -verify -fsyntax-only -Wthread-safety %s + +#ifndef HEADER +#define HEADER + +#define LOCKABLE __attribute__ ((lockable)) +#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__))) + +class LOCKABLE Mutex{}; + +template +struct lock_guard { + lock_guard(T) {} + ~lock_guard() {} +}; +template +struct unique_lock { + unique_lock(T) {} + ~unique_lock() {} +}; + +template +void LockMutexes(T &m, Ts &...ms) EXCLUSIVE_LOCK_FUNCTION(m, ms...); + +#else + +Mutex m0, m1; +void non_local_mutex_held() { + LockMutexes(m0, m1); // expected-note {{mutex acquired here}} \ + // expected-note {{mutex acquired here}} +} // expected-warning{{mutex 'm0' is still held at the end of function}} \ +// expected-warning{{mutex 'm1' is still held at the end of function}} + +void no_local_mutex_held_warning() { + Mutex local_m0; + Mutex local_m1; + LockMutexes(local_m0, local_m1); +} // No warnings expected at end of function scope as the mutexes are function local. + +void no_local_unique_locks_held_warning() { + unique_lock ul0(m0); + unique_lock ul1(m1); + LockMutexes(ul0, ul1); +} // No warnings expected at end of function scope as the unique_locks held are function local. +#endif