This patch fixes an error where Annotalysis generates bogus warnings when a shared lock is released in a function that has a "universal lock" -- typically produced when gcc cannot parse a lock expression.
Bootstrapped and passed gcc regression testsuite on x86_64-unknown-linux-gnu. Okay for google/gcc-4_6? -DeLesley Changelog.google-4_6: 2011-10-10 DeLesley Hutchins <deles...@google.com> * tree-threadsafe-analyze.c (remove_lock_from_lockset) testsuite/Changelog.google-4_6: 2011-10-10 DeLesley Hutchins <deles...@google.com> * g++.dg/thread-ann/thread_annot_lock-83.C: New regression test Index: gcc/testsuite/g++.dg/thread-ann/thread_annot_lock-83.C =================================================================== --- gcc/testsuite/g++.dg/thread-ann/thread_annot_lock-83.C (revision 0) +++ gcc/testsuite/g++.dg/thread-ann/thread_annot_lock-83.C (revision 0) @@ -0,0 +1,31 @@ +// Regression test for bugfix, where shared locks are not properly +// removed from locksets if a "universal lock" is present. +// { dg-do compile } +// { dg-options "-Wthread-safety" } + +#include "thread_annot_common.h" + +class Foo; + +class Bar { +public: + Foo* foo; + Mutex mu_; + + // foo->mu_ is not visible at this point in the code. + // so the attribute will become a "universal lock." + void bar() EXCLUSIVE_LOCKS_REQUIRED(foo->mu_); +}; + + +class Foo { +public: + Mutex mu_; + int a; +}; + + +void Bar::bar() { + ReaderMutexLock rlock(&mu_); +} + Index: gcc/tree-threadsafe-analyze.c =================================================================== --- gcc/tree-threadsafe-analyze.c (revision 179771) +++ gcc/tree-threadsafe-analyze.c (working copy) @@ -1830,14 +1830,27 @@ remove_lock_from_lockset (tree lockable, struct po { tree lock_contained; - if ((lock_contained = lock_set_contains(live_excl_locks, lockable, NULL_TREE, - false)) != NULL_TREE) + /* Try to remove the actual lock. */ + if ((lock_contained = lock_set_contains(live_excl_locks, lockable, + NULL_TREE, true)) != NULL_TREE) pointer_set_delete (live_excl_locks, lock_contained); else if ((lock_contained = lock_set_contains(live_shared_locks, lockable, - NULL_TREE, false)) != NULL_TREE) + NULL_TREE, true)) != NULL_TREE) pointer_set_delete (live_shared_locks, lock_contained); - return lock_contained; + if (lock_contained) + return lock_contained; + + /* If either of lock sets contains the universal lock, then pretend that + we've removed it, to avoid a warning about unlocking a lock that was + not acquired. */ + if (pointer_set_contains (live_excl_locks, error_mark_node)) + return lockable; + + if (pointer_set_contains(live_shared_locks, error_mark_node)) + return lockable; + + return NULL_TREE; } /* This function handles function calls that release locks (i.e. the