================ @@ -3171,6 +3171,372 @@ void lockUnlock() EXCLUSIVE_LOCKS_REQUIRED(mu) { } // end namespace ScopedUnlock +namespace PassingScope { + +class SCOPED_LOCKABLE RelockableScope { +public: + RelockableScope(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu); + void Release() UNLOCK_FUNCTION(); + void Acquire() EXCLUSIVE_LOCK_FUNCTION(); + ~RelockableScope() EXCLUSIVE_UNLOCK_FUNCTION(); +}; + +class SCOPED_LOCKABLE ReaderRelockableScope { +public: + ReaderRelockableScope(Mutex *mu) SHARED_LOCK_FUNCTION(mu); + void Release() UNLOCK_FUNCTION(); + void Acquire() SHARED_LOCK_FUNCTION(); + ~ReaderRelockableScope() UNLOCK_FUNCTION(); +}; + +Mutex mu; +Mutex mu1; +Mutex mu2; +int x GUARDED_BY(mu); +int y GUARDED_BY(mu) GUARDED_BY(mu2); +void print(int); + +// Analysis inside the function with annotated parameters + +void sharedRequired(ReleasableMutexLock& scope SHARED_LOCKS_REQUIRED(mu)) { + print(x); // OK. +} + +void sharedAcquire(ReaderRelockableScope& scope SHARED_LOCK_FUNCTION(mu)) { + scope.Acquire(); + print(x); +} + +void sharedRelease(RelockableScope& scope SHARED_UNLOCK_FUNCTION(mu)) { + print(x); + scope.Release(); + print(x); // expected-warning{{reading variable 'x' requires holding mutex 'mu'}} +} + +void requiredLock(ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)) { + x = 1; // OK. +} + +void reacquireRequiredLock(RelockableScope& scope EXCLUSIVE_LOCKS_REQUIRED(mu)) { + scope.Release(); + scope.Acquire(); + x = 2; // OK. +} + +void releaseSingleMutex(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)) { + x = 1; // OK. + scope.Release(); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void releaseMultipleMutexes(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu, mu2)) { + y = 1; // OK. + scope.Release(); + y = 2; // expected-warning{{writing variable 'y' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{writing variable 'y' requires holding mutex 'mu2' exclusively}} +} + +void acquireLock(RelockableScope& scope EXCLUSIVE_LOCK_FUNCTION(mu)) { + x = 1; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} + scope.Acquire(); + x = 2; // OK. +} + +void acquireMultipleLocks(RelockableScope& scope EXCLUSIVE_LOCK_FUNCTION(mu, mu2)) { + y = 1; // expected-warning{{writing variable 'y' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{writing variable 'y' requires holding mutex 'mu2' exclusively}} + scope.Acquire(); + y = 2; // OK. +} + +void excludedLock(ReleasableMutexLock& scope LOCKS_EXCLUDED(mu)) { + x = 1; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void acquireAndReleaseExcludedLocks(RelockableScope& scope LOCKS_EXCLUDED(mu)) { + scope.Acquire(); + scope.Release(); +} + +// expected-note@+1{{mutex acquired here}} +void unreleasedMutex(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)) { + x = 1; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void acquireAlreadyHeldMutex(RelockableScope& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)) { + scope.Acquire(); // expected-warning{{acquiring mutex 'mu' that is already held}} + scope.Release(); +} + +void reacquireMutex(RelockableScope& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)) { + scope.Release(); + scope.Acquire(); // expected-note{{mutex acquired here}} + x = 2; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void requireSingleMutex(ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)) { + x = 1; // OK. + scope.Release(); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +// expected-note@+1 2{{mutex acquired here}} +void requireMultipleMutexes(ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu, mu2)) { + y = 1; // OK. + scope.Release(); + y = 2; // expected-warning{{writing variable 'y' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{writing variable 'y' requires holding mutex 'mu2' exclusively}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + // expected-warning@-1{{expecting mutex 'mu2' to be held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void acquireAlreadyHeldLock(RelockableScope& scope EXCLUSIVE_LOCKS_REQUIRED(mu)) { + scope.Acquire(); // expected-warning{{acquiring mutex 'mu' that is already held}} +} + +// expected-note@+1 {{mutex acquired here}} +void releaseWithoutHoldingLock(ReleasableMutexLock& scope EXCLUSIVE_LOCK_FUNCTION(mu)) { + scope.Release(); // expected-warning{{releasing mutex 'mu' that was not held}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +// expected-note@+1 {{mutex acquired here}} +void endWithReleasedMutex(RelockableScope& scope EXCLUSIVE_LOCK_FUNCTION(mu)) { + scope.Acquire(); + scope.Release(); +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +void acquireExcludedLock(RelockableScope& scope LOCKS_EXCLUDED(mu)) { + x = 1; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} + scope.Acquire(); // expected-note {{mutex acquired here}} + x = 2; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + +void acquireMultipleExcludedLocks(RelockableScope& scope LOCKS_EXCLUDED(mu, mu2)) { + y = 1; // expected-warning{{writing variable 'y' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{writing variable 'y' requires holding mutex 'mu2' exclusively}} + scope.Acquire(); // expected-note 2{{mutex acquired here}} + y = 2; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + // expected-warning@-1{{mutex 'mu2' is still held at the end of function}} + +void reacquireExcludedLocks(RelockableScope& scope LOCKS_EXCLUDED(mu)) { + scope.Release(); // expected-warning{{releasing mutex 'mu' that was not held}} + scope.Acquire(); // expected-note {{mutex acquired here}} + x = 2; // OK. +} // expected-warning{{mutex 'mu' is still held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void sharedRequired2(ReleasableMutexLock& scope SHARED_LOCKS_REQUIRED(mu)) { + print(x); // OK. + scope.Release(); + print(x); // expected-warning{{reading variable 'x' requires holding mutex 'mu'}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +// expected-note@+1{{mutex acquired here}} +void sharedAcquire2(RelockableScope& scope SHARED_LOCK_FUNCTION(mu)) { + print(x); // expected-warning{{reading variable 'x' requires holding mutex 'mu'}} + scope.Release(); // expected-warning{{releasing mutex 'mu' that was not held}} +} // expected-warning{{expecting mutex 'mu' to be held at the end of function}} + +// expected-note@+1 2{{mutex acquired here}} +void sharedRelease2(RelockableScope& scope SHARED_UNLOCK_FUNCTION(mu)) { + scope.Acquire(); //expected-warning{{acquiring mutex 'mu' that is already held}} +} //expected-warning{{mutex 'mu' is still held at the end of function}} + +// Handling the call of the function with annotated parameters + +// expected-note@+1{{see attribute on parameter here}} +void release(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)); +// expected-note@+1{{see attribute on parameter here}} +void release_DoubleMutexLock(DoubleMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu)); +// expected-note@+1 2{{see attribute on parameter here}} +void release_two(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu, mu2)); +// expected-note@+1{{see attribute on parameter here}} +void release_double(DoubleMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu, mu2)); +void require(ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)); +void acquire(RelockableScope& scope EXCLUSIVE_LOCK_FUNCTION(mu)); +void exclude(RelockableScope& scope LOCKS_EXCLUDED(mu)); + +void release_shared(ReaderRelockableScope& scope SHARED_UNLOCK_FUNCTION(mu)); +void require_shared(ReleasableMutexLock& scope SHARED_LOCKS_REQUIRED(mu)); +void acquire_shared(ReaderRelockableScope& scope SHARED_LOCK_FUNCTION(mu)); + +void unlockCall() { + ReleasableMutexLock scope(&mu); + x = 1; // OK. + release(scope); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void unlockSharedCall() { + ReaderRelockableScope scope(&mu); + print(x); // OK. + release_shared(scope); + print(x); // expected-warning{{reading variable 'x' requires holding mutex 'mu'}} +} + +void requireCall() { + ReleasableMutexLock scope(&mu); + x = 1; // OK. + require(scope); + x = 2; // Ok. +} + +void requireSharedCall() { + ReleasableMutexLock scope(&mu); + print(x); // OK. + require_shared(scope); + print(x); // Ok. +} + +void acquireCall() { + RelockableScope scope(&mu); + scope.Release(); + acquire(scope); + x = 2; // Ok. +} + +void acquireSharedCall() { + ReaderRelockableScope scope(&mu); + scope.Release(); + acquire_shared(scope); + print(x); // Ok. +} + +void writeAfterExcludeCall() { + RelockableScope scope(&mu); + scope.Release(); + exclude(scope); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void unlockCallAfterExplicitRelease() { + ReleasableMutexLock scope(&mu); + x = 1; // OK. + scope.Release(); // expected-note{{mutex released here}} + release(scope); // expected-warning{{releasing mutex 'mu' that was not held}} + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void unmatchedMutexes() { + ReleasableMutexLock scope(&mu2); + release(scope); // expected-warning{{mutex managed by 'scope' is 'mu2' instead of 'mu'}} + // expected-warning@-1{{releasing mutex 'mu' that was not held}} +} + +void wrongOrder() { + DoubleMutexLock scope(&mu2, &mu); + release_double(scope); // expected-warning{{mutex managed by 'scope' is 'mu2' instead of 'mu'}} +} + +void differentNumberOfMutexes() { + ReleasableMutexLock scope(&mu); + release_two(scope); // expected-warning{{mutex 'mu2' not managed by 'scope'}} + // expected-warning@-1{{releasing mutex 'mu2' that was not held}} +} + +void differentNumberOfMutexes2() { + ReleasableMutexLock scope(&mu2); + release_two(scope); // expected-warning{{mutex managed by 'scope' is 'mu2' instead of 'mu'}} + // expected-warning@-1{{releasing mutex 'mu' that was not held}} +} + +void differentNumberOfMutexes3() { + DoubleMutexLock scope(&mu, &mu2); + release_DoubleMutexLock(scope); // expected-warning{{did not expect mutex 'mu2' to be managed by 'scope'}} +} + +void releaseDefault(ReleasableMutexLock& scope EXCLUSIVE_UNLOCK_FUNCTION(mu), int = 0); + +void unlockFunctionDefault() { + ReleasableMutexLock scope(&mu); + x = 1; // OK. + releaseDefault(scope); + x = 2; // expected-warning{{writing variable 'x' requires holding mutex 'mu' exclusively}} +} + +void requireCallWithReleasedLock() { + ReleasableMutexLock scope(&mu); + scope.Release(); + require(scope); // expected-warning{{calling function 'require' requires holding mutex 'mu' exclusively}} +} + +void acquireCallWithAlreadyHeldLock() { + RelockableScope scope(&mu); // expected-note{{mutex acquired here}} + acquire(scope); // expected-warning{{acquiring mutex 'mu' that is already held}} + x = 1; +} + +void excludeCallWithAlreadyHeldLock() { + RelockableScope scope(&mu); + exclude(scope);// expected-warning{{cannot call function 'exclude' while mutex 'mu' is held}} + x = 2; // OK. +} + +// Passing a scope by value +RelockableScope lock() EXCLUSIVE_LOCK_FUNCTION(mu); +void destruct(RelockableScope scope) {} +void passScopeByValue() { + destruct(lock()); +} + +void requireConst(const ReleasableMutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)); +void requireConstCall() { + requireConst(ReleasableMutexLock(&mu)); +} + +void passScopeUndeclared(ReleasableMutexLock &scope) { + release(scope); // expected-warning{{calling function 'release' requires holding mutex 'scope' exclusively}} + // expected-warning@-1{{releasing mutex 'mu' that was not held}} +} + +class SCOPED_LOCKABLE ScopedWithoutLock { +public: + ScopedWithoutLock(); + + ~ScopedWithoutLock() EXCLUSIVE_UNLOCK_FUNCTION(); +}; + +void require(ScopedWithoutLock &scope EXCLUSIVE_LOCKS_REQUIRED(mu)); + +void constructWithoutLock() { + ScopedWithoutLock scope; + require(scope); // expected-warning{{calling function 'require' requires holding mutex 'mu' exclusively}} + // expected-warning@-1{{calling function 'require' requires holding mutex 'scope' exclusively}} +} // expected-warning {{releasing mutex 'scope' that was not held}} + +void requireConst(const ScopedWithoutLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu)); + +void requireCallWithReleasedLock2() { + requireConst(ScopedWithoutLock()); + // expected-warning@-1{{calling function 'requireConst' requires holding mutex '#undefined' exclusively}} + // expected-warning@-2{{calling function 'requireConst' requires holding mutex 'mu' exclusively}} +} + +void requireDecl(RelockableScope &scope EXCLUSIVE_LOCKS_REQUIRED(mu)); +void requireDecl(RelockableScope &scope){ ---------------- aaronpuchert wrote:
```suggestion void requireDecl(RelockableScope &scope) { ``` Same below. https://github.com/llvm/llvm-project/pull/110523 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits