<div dir="ltr">I ended up reverting this in r228020, and also helped Delesley repro the problems.</div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Feb 3, 2015 at 10:17 AM, DeLesley Hutchins <span dir="ltr"><<a href="mailto:delesley@google.com" target="_blank">delesley@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: delesley<br>
Date: Tue Feb  3 12:17:48 2015<br>
New Revision: 227997<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=227997&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=227997&view=rev</a><br>
Log:<br>
Thread Safety Analysis: add support for before/after annotations on mutexes.<br>
These checks detect potential deadlocks caused by inconsistent lock<br>
ordering.  The checks are implemented under the -Wthread-safety-beta flag.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h<br>
    cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h<br>
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
    cfe/trunk/include/clang/Sema/Sema.h<br>
    cfe/trunk/lib/Analysis/ThreadSafety.cpp<br>
    cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp<br>
    cfe/trunk/lib/Sema/Sema.cpp<br>
    cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h?rev=227997&r1=227996&r2=227997&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h?rev=227997&r1=227996&r2=227997&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h (original)<br>
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h Tue Feb  3 12:17:48 2015<br>
@@ -26,6 +26,8 @@<br>
 namespace clang {<br>
 namespace threadSafety {<br>
<br>
+class BeforeSet;<br>
+<br>
 /// This enum distinguishes between different kinds of operations that may<br>
 /// need to be protected by locks. We use this enum in error handling.<br>
 enum ProtectedOperationKind {<br>
@@ -183,6 +185,14 @@ public:<br>
   virtual void handleFunExcludesLock(StringRef Kind, Name FunName,<br>
                                      Name LockName, SourceLocation Loc) {}<br>
<br>
+<br>
+  /// Warn that L1 cannot be acquired before L2.<br>
+  virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name,<br>
+                                        Name L2Name, SourceLocation Loc) {}<br>
+<br>
+  /// Warn that there is a cycle in acquired_before/after dependencies.<br>
+  virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {}<br>
+<br>
   /// Called by the analysis when starting analysis of a function.<br>
   /// Used to issue suggestions for changes to annotations.<br>
   virtual void enterFunction(const FunctionDecl *FD) {}<br>
@@ -203,7 +213,8 @@ private:<br>
 /// at the end of each block, and issue warnings for thread safety violations.<br>
 /// Each block in the CFG is traversed exactly once.<br>
 void runThreadSafetyAnalysis(AnalysisDeclContext &AC,<br>
-                             ThreadSafetyHandler &Handler);<br>
+                             ThreadSafetyHandler &Handler,<br>
+                             BeforeSet **Bset);<br>
<br>
 /// \brief Helper function that returns a LockKind required for the given level<br>
 /// of access.<br>
<br>
Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=227997&r1=227996&r2=227997&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=227997&r1=227996&r2=227997&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)<br>
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Tue Feb  3 12:17:48 2015<br>
@@ -286,6 +286,14 @@ public:<br>
             sx::partiallyMatches(CapExpr, other.CapExpr);<br>
   }<br>
<br>
+  const ValueDecl* valueDecl() const {<br>
+    if (Negated)<br>
+      return nullptr;<br>
+    if (auto *P = dyn_cast<til::Project>(CapExpr))<br>
+      return P->clangDecl();<br>
+    return nullptr;<br>
+  }<br>
+<br>
   std::string toString() const {<br>
     if (Negated)<br>
       return "!" + sx::toString(CapExpr);<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=227997&r1=227996&r2=227997&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=227997&r1=227996&r2=227997&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb  3 12:17:48 2015<br>
@@ -2394,6 +2394,13 @@ def warn_fun_excludes_mutex : Warning<<br>
 def warn_cannot_resolve_lock : Warning<<br>
   "cannot resolve lock expression">,<br>
   InGroup<ThreadSafetyAnalysis>, DefaultIgnore;<br>
+def warn_acquired_before : Warning<<br>
+  "%0 '%1' must be acquired before '%2'">,<br>
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;<br>
+def warn_acquired_before_after_cycle : Warning<<br>
+  "Cycle in acquired_before/after dependencies, starting with '%0'">,<br>
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;<br>
+<br>
<br>
 // Thread safety warnings negative capabilities<br>
 def warn_acquire_requires_negative_cap : Warning<<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=227997&r1=227996&r2=227997&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=227997&r1=227996&r2=227997&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb  3 12:17:48 2015<br>
@@ -199,6 +199,11 @@ namespace sema {<br>
   class TemplateDeductionInfo;<br>
 }<br>
<br>
+namespace threadSafety {<br>
+  class BeforeSet;<br>
+  void threadSafetyCleanup(BeforeSet* Cache);<br>
+}<br>
+<br>
 // FIXME: No way to easily map from TemplateTypeParmTypes to<br>
 // TemplateTypeParmDecls, so we have this horrible PointerUnion.<br>
 typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,<br>
@@ -6708,6 +6713,7 @@ public:<br>
<br>
   /// \brief Worker object for performing CFG-based warnings.<br>
   sema::AnalysisBasedWarnings AnalysisWarnings;<br>
+  threadSafety::BeforeSet *ThreadSafetyDeclCache;<br>
<br>
   /// \brief An entity for which implicit template instantiation is required.<br>
   ///<br>
<br>
Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=227997&r1=227996&r2=227997&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=227997&r1=227996&r2=227997&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Tue Feb  3 12:17:48 2015<br>
@@ -101,17 +101,22 @@ private:<br>
   LockKind          LKind;            ///<  exclusive or shared<br>
   SourceLocation    AcquireLoc;       ///<  where it was acquired.<br>
   bool              Asserted;         ///<  true if the lock was asserted<br>
+  bool              Declared;         ///<  true if the lock was declared<br>
<br>
 public:<br>
   FactEntry(const CapabilityExpr &CE, LockKind LK, SourceLocation Loc,<br>
-            bool Asrt)<br>
-      : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt) {}<br>
+            bool Asrt, bool Declrd = false)<br>
+      : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt),<br>
+        Declared(Declrd) {}<br>
<br>
   virtual ~FactEntry() {}<br>
<br>
-  LockKind          kind()       const { return LKind;    }<br>
+  LockKind          kind()       const { return LKind;      }<br>
   SourceLocation    loc()        const { return AcquireLoc; }<br>
   bool              asserted()   const { return Asserted; }<br>
+  bool              declared()   const { return Declared; }<br>
+<br>
+  void setDeclared(bool D) { Declared = D; }<br>
<br>
   virtual void<br>
   handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan,<br>
@@ -231,14 +236,56 @@ public:<br>
<br>
   FactEntry *findPartialMatch(FactManager &FM,<br>
                               const CapabilityExpr &CapE) const {<br>
-    auto I = std::find_if(begin(), end(), [&](FactID ID) {<br>
+    auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool {<br>
       return FM[ID].partiallyMatches(CapE);<br>
     });<br>
     return I != end() ? &FM[*I] : nullptr;<br>
   }<br>
+<br>
+  bool containsMutexDecl(FactManager &FM, const ValueDecl* Vd) const {<br>
+    auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool {<br>
+      return FM[ID].valueDecl() == Vd;<br>
+    });<br>
+    return I != end();<br>
+  }<br>
+};<br>
+<br>
+<br>
+class ThreadSafetyAnalyzer;<br>
+<br>
+<br>
+class BeforeSet {<br>
+private:<br>
+  typedef SmallVector<const ValueDecl*, 4>  BeforeVect;<br>
+<br>
+  struct BeforeInfo {<br>
+    BeforeInfo() : Vect(nullptr), Visited(false) { }<br>
+<br>
+    std::unique_ptr<BeforeVect> Vect;<br>
+    int                         Visited;<br>
+  };<br>
+<br>
+  typedef llvm::DenseMap<const ValueDecl*, BeforeInfo>  BeforeMap;<br>
+  typedef llvm::DenseMap<const ValueDecl*, bool>        CycleMap;<br>
+<br>
+public:<br>
+  BeforeSet() { }<br>
+<br>
+  BeforeInfo* insertAttrExprs(const ValueDecl* Vd,<br>
+                              ThreadSafetyAnalyzer& Analyzer);<br>
+<br>
+  void checkBeforeAfter(const ValueDecl* Vd,<br>
+                        const FactSet& FSet,<br>
+                        ThreadSafetyAnalyzer& Analyzer,<br>
+                        SourceLocation Loc, StringRef CapKind);<br>
+<br>
+private:<br>
+  BeforeMap BMap;<br>
+  CycleMap  CycMap;<br>
 };<br>
<br>
<br>
+<br>
 typedef llvm::ImmutableMap<const NamedDecl*, unsigned> LocalVarContext;<br>
 class LocalVariableMap;<br>
<br>
@@ -853,6 +900,7 @@ public:<br>
 /// \brief Class which implements the core thread safety analysis routines.<br>
 class ThreadSafetyAnalyzer {<br>
   friend class BuildLockset;<br>
+  friend class BeforeSet;<br>
<br>
   llvm::BumpPtrAllocator Bpa;<br>
   threadSafety::til::MemRegionRef Arena;<br>
@@ -864,9 +912,11 @@ class ThreadSafetyAnalyzer {<br>
   FactManager               FactMan;<br>
   std::vector<CFGBlockInfo> BlockInfo;<br>
<br>
+  BeforeSet* GlobalBeforeSet;<br>
+<br>
 public:<br>
-  ThreadSafetyAnalyzer(ThreadSafetyHandler &H)<br>
-     : Arena(&Bpa), SxBuilder(Arena), Handler(H) {}<br>
+  ThreadSafetyAnalyzer(ThreadSafetyHandler &H, BeforeSet* Bset)<br>
+     : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {}<br>
<br>
   bool inCurrentScope(const CapabilityExpr &CapE);<br>
<br>
@@ -907,6 +957,136 @@ public:<br>
   void runAnalysis(AnalysisDeclContext &AC);<br>
 };<br>
<br>
+<br>
+<br>
+/// Process acquired_before and acquired_after attributes on Vd.<br>
+BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd,<br>
+    ThreadSafetyAnalyzer& Analyzer) {<br>
+  // Create a new entry for Vd.<br>
+  auto& Entry = BMap.FindAndConstruct(Vd);<br>
+  BeforeInfo* Info = &Entry.second;<br>
+  BeforeVect* Bv = nullptr;<br>
+<br>
+  const AttrVec &ArgAttrs = Vd->getAttrs();<br>
+  for (Attr* At : ArgAttrs) {<br>
+    switch (At->getKind()) {<br>
+      case attr::AcquiredBefore: {<br>
+        auto *A = cast<AcquiredBeforeAttr>(At);<br>
+<br>
+        // Create a new BeforeVect for Vd if necessary.<br>
+        if (!Bv) {<br>
+          Bv = new BeforeVect;<br>
+          Info->Vect.reset(Bv);<br>
+        }<br>
+        // Read exprs from the attribute, and add them to BeforeVect.<br>
+        for (const auto *Arg : A->args()) {<br>
+          CapabilityExpr Cp =<br>
+            Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr);<br>
+          if (const ValueDecl *Cpvd = Cp.valueDecl()) {<br>
+            Bv->push_back(Cpvd);<br>
+            auto It = BMap.find(Cpvd);<br>
+            if (It == BMap.end())<br>
+              insertAttrExprs(Cpvd, Analyzer);<br>
+          }<br>
+        }<br>
+        break;<br>
+      }<br>
+      case attr::AcquiredAfter: {<br>
+        auto *A = cast<AcquiredAfterAttr>(At);<br>
+<br>
+        // Read exprs from the attribute, and add them to BeforeVect.<br>
+        for (const auto *Arg : A->args()) {<br>
+          CapabilityExpr Cp =<br>
+            Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr);<br>
+          if (const ValueDecl *ArgVd = Cp.valueDecl()) {<br>
+            // Get entry for mutex listed in attribute<br>
+            BeforeInfo* ArgInfo;<br>
+            auto It = BMap.find(ArgVd);<br>
+            if (It == BMap.end())<br>
+              ArgInfo = insertAttrExprs(ArgVd, Analyzer);<br>
+            else<br>
+              ArgInfo = &It->second;<br>
+<br>
+            // Create a new BeforeVect if necessary.<br>
+            BeforeVect* ArgBv = ArgInfo->Vect.get();<br>
+            if (!ArgBv) {<br>
+              ArgBv = new BeforeVect;<br>
+              ArgInfo->Vect.reset(ArgBv);<br>
+            }<br>
+            ArgBv->push_back(Vd);<br>
+          }<br>
+        }<br>
+        break;<br>
+      }<br>
+      default:<br>
+        break;<br>
+    }<br>
+  }<br>
+<br>
+  return Info;<br>
+}<br>
+<br>
+<br>
+/// Return true if any mutexes in FSet are in the acquired_before set of Vd.<br>
+void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd,<br>
+                                 const FactSet& FSet,<br>
+                                 ThreadSafetyAnalyzer& Analyzer,<br>
+                                 SourceLocation Loc, StringRef CapKind) {<br>
+  SmallVector<BeforeInfo*, 8> InfoVect;<br>
+<br>
+  // Do a depth-first traversal of Vd.<br>
+  // Return true if there are cycles.<br>
+  std::function<bool (const ValueDecl*)> traverse = [&](const ValueDecl* Vd) {<br>
+    if (!Vd)<br>
+      return false;<br>
+<br>
+    BeforeSet::BeforeInfo* Info;<br>
+    auto It = BMap.find(Vd);<br>
+    if (It == BMap.end())<br>
+      Info = insertAttrExprs(Vd, Analyzer);<br>
+    else<br>
+      Info = &It->second;<br>
+<br>
+    if (Info->Visited == 1)<br>
+      return true;<br>
+<br>
+    if (Info->Visited == 2)<br>
+      return false;<br>
+<br>
+    BeforeVect* Bv = Info->Vect.get();<br>
+    if (!Bv)<br>
+      return false;<br>
+<br>
+    InfoVect.push_back(Info);<br>
+    Info->Visited = 1;<br>
+    for (auto *Vdb : *Bv) {<br>
+      // Exclude mutexes in our immediate before set.<br>
+      if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) {<br>
+        StringRef L1 = StartVd->getName();<br>
+        StringRef L2 = Vdb->getName();<br>
+        Analyzer.Handler.handleLockAcquiredBefore(CapKind, L1, L2, Loc);<br>
+      }<br>
+      // Transitively search other before sets, and warn on cycles.<br>
+      if (traverse(Vdb)) {<br>
+        if (CycMap.find(Vd) == CycMap.end()) {<br>
+          CycMap.insert(std::make_pair(Vd, true));<br>
+          StringRef L1 = Vd->getName();<br>
+          Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->getLocation());<br>
+        }<br>
+      }<br>
+    }<br>
+    Info->Visited = 2;<br>
+    return false;<br>
+  };<br>
+<br>
+  traverse(StartVd);<br>
+<br>
+  for (auto* Info : InfoVect)<br>
+    Info->Visited = 0;<br>
+}<br>
+<br>
+<br>
+<br>
 /// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs.<br>
 static const ValueDecl *getValueDecl(const Expr *Exp) {<br>
   if (const auto *CE = dyn_cast<ImplicitCastExpr>(Exp))<br>
@@ -1020,7 +1200,13 @@ void ThreadSafetyAnalyzer::addLock(FactS<br>
     }<br>
   }<br>
<br>
-  // FIXME: deal with acquired before/after annotations.<br>
+  // Check before/after constraints<br>
+  if (Handler.issueBetaWarnings() &&<br>
+      !Entry->asserted() && !Entry->declared()) {<br>
+    GlobalBeforeSet->checkBeforeAfter(Entry->valueDecl(), FSet, *this,<br>
+                                      Entry->loc(), DiagKind);<br>
+  }<br>
+<br>
   // FIXME: Don't always warn when we have support for reentrant locks.<br>
   if (FSet.findLock(FactMan, *Entry)) {<br>
     if (!Entry->asserted())<br>
@@ -1979,14 +2165,16 @@ void ThreadSafetyAnalyzer::runAnalysis(A<br>
     }<br>
<br>
     // FIXME -- Loc can be wrong here.<br>
-    for (const auto &Mu : ExclusiveLocksToAdd)<br>
-      addLock(InitialLockset,<br>
-              llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc),<br>
-              CapDiagKind, true);<br>
-    for (const auto &Mu : SharedLocksToAdd)<br>
-      addLock(InitialLockset,<br>
-              llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc),<br>
-              CapDiagKind, true);<br>
+    for (const auto &Mu : ExclusiveLocksToAdd) {<br>
+      auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc);<br>
+      Entry->setDeclared(true);<br>
+      addLock(InitialLockset, std::move(Entry), CapDiagKind, true);<br>
+    }<br>
+    for (const auto &Mu : SharedLocksToAdd) {<br>
+      auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc);<br>
+      Entry->setDeclared(true);<br>
+      addLock(InitialLockset, std::move(Entry), CapDiagKind, true);<br>
+    }<br>
   }<br>
<br>
   for (const auto *CurrBlock : *SortedGraph) {<br>
@@ -2180,11 +2368,20 @@ void ThreadSafetyAnalyzer::runAnalysis(A<br>
 /// at the end of each block, and issue warnings for thread safety violations.<br>
 /// Each block in the CFG is traversed exactly once.<br>
 void runThreadSafetyAnalysis(AnalysisDeclContext &AC,<br>
-                             ThreadSafetyHandler &Handler) {<br>
-  ThreadSafetyAnalyzer Analyzer(Handler);<br>
+                             ThreadSafetyHandler &Handler,<br>
+                             BeforeSet **BSet) {<br>
+  if (!*BSet)<br>
+    *BSet = new BeforeSet;<br>
+  ThreadSafetyAnalyzer Analyzer(Handler, *BSet);<br>
   Analyzer.runAnalysis(AC);<br>
 }<br>
<br>
+<br>
+void threadSafetyCleanup(BeforeSet* Cache) {<br>
+  delete Cache;<br>
+}<br>
+<br>
+<br>
 /// \brief Helper function that returns a LockKind required for the given level<br>
 /// of access.<br>
 LockKind getLockKindFromAccessKind(AccessKind AK) {<br>
<br>
Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=227997&r1=227996&r2=227997&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=227997&r1=227996&r2=227997&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)<br>
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Tue Feb  3 12:17:48 2015<br>
@@ -1679,6 +1679,22 @@ class ThreadSafetyReporter : public clan<br>
     Warnings.push_back(DelayedDiag(Warning, getNotes()));<br>
   }<br>
<br>
+<br>
+  virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name,<br>
+                                        Name L2Name, SourceLocation Loc)<br>
+      override {<br>
+    PartialDiagnosticAt Warning(Loc,<br>
+      S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);<br>
+    Warnings.push_back(DelayedDiag(Warning, getNotes()));<br>
+  }<br>
+<br>
+  virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)<br>
+      override {<br>
+    PartialDiagnosticAt Warning(Loc,<br>
+      S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);<br>
+    Warnings.push_back(DelayedDiag(Warning, getNotes()));<br>
+  }<br>
+<br>
   void enterFunction(const FunctionDecl* FD) override {<br>
     CurrentFunction = FD;<br>
   }<br>
@@ -1704,7 +1720,7 @@ class ConsumedWarningsHandler : public C<br>
   DiagList Warnings;<br>
<br>
 public:<br>
-<br>
+<br>
   ConsumedWarningsHandler(Sema &S) : S(S) {}<br>
<br>
   void emitDiagnostics() override {<br>
@@ -1981,7 +1997,8 @@ AnalysisBasedWarnings::IssueWarnings(sem<br>
     if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getLocStart()))<br>
       Reporter.setVerbose(true);<br>
<br>
-    threadSafety::runThreadSafetyAnalysis(AC, Reporter);<br>
+    threadSafety::runThreadSafetyAnalysis(AC, Reporter,<br>
+                                          &S.ThreadSafetyDeclCache);<br>
     Reporter.emitDiagnostics();<br>
   }<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/Sema.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=227997&r1=227996&r2=227997&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=227997&r1=227996&r2=227997&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/Sema.cpp (original)<br>
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Feb  3 12:17:48 2015<br>
@@ -102,7 +102,7 @@ Sema::Sema(Preprocessor &pp, ASTContext<br>
     AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),<br>
     NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),<br>
     CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),<br>
-    TyposCorrected(0), AnalysisWarnings(*this),<br>
+    TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),<br>
     VarDataSharingAttributesStack(nullptr), CurScope(nullptr),<br>
     Ident_super(nullptr), Ident___float128(nullptr)<br>
 {<br>
@@ -243,6 +243,8 @@ Sema::~Sema() {<br>
   if (isMultiplexExternalSource)<br>
     delete ExternalSource;<br>
<br>
+  threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache);<br>
+<br>
   // Destroys data sharing attributes stack for OpenMP<br>
   DestroyDataSharingAttributesStack();<br>
<br>
<br>
Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=227997&r1=227996&r2=227997&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=227997&r1=227996&r2=227997&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Tue Feb  3 12:17:48 2015<br>
@@ -4835,7 +4835,7 @@ public:<br>
     read2(10, *foosp);        // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}<br>
     destroy(mymove(*foosp));  // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}<br>
<br>
-    // TODO -- these requires better smart pointer handling.<br>
+    // TODO -- these require better smart pointer handling.<br>
     copy(*foosp.get());<br>
     write1(*foosp.get());<br>
     write2(10, *foosp.get());<br>
@@ -4848,3 +4848,213 @@ public:<br>
<br>
 }  // end namespace PassByRefTest<br>
<br>
+<br>
+namespace AcquiredBeforeAfterText {<br>
+<br>
+class Foo {<br>
+  Mutex mu1 ACQUIRED_BEFORE(mu2, mu3);<br>
+  Mutex mu2;<br>
+  Mutex mu3;<br>
+<br>
+  void test1() {<br>
+    mu1.Lock();<br>
+    mu2.Lock();<br>
+    mu3.Lock();<br>
+<br>
+    mu3.Unlock();<br>
+    mu2.Unlock();<br>
+    mu1.Unlock();<br>
+  }<br>
+<br>
+  void test2() {<br>
+    mu2.Lock();<br>
+    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}<br>
+    mu1.Unlock();<br>
+    mu2.Unlock();<br>
+  }<br>
+<br>
+  void test3() {<br>
+    mu3.Lock();<br>
+    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}<br>
+    mu1.Unlock();<br>
+    mu3.Unlock();<br>
+  }<br>
+<br>
+  void test4() EXCLUSIVE_LOCKS_REQUIRED(mu1) {<br>
+    mu2.Lock();<br>
+    mu2.Unlock();<br>
+  }<br>
+<br>
+  void test5() EXCLUSIVE_LOCKS_REQUIRED(mu2) {<br>
+    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}<br>
+    mu1.Unlock();<br>
+  }<br>
+<br>
+  void test6() EXCLUSIVE_LOCKS_REQUIRED(mu2) {<br>
+    mu1.AssertHeld();<br>
+  }<br>
+<br>
+  void test7() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2, mu3) { }<br>
+<br>
+  void test8() EXCLUSIVE_LOCKS_REQUIRED(mu3, mu2, mu1) { }<br>
+};<br>
+<br>
+<br>
+class Foo2 {<br>
+  Mutex mu1;<br>
+  Mutex mu2 ACQUIRED_AFTER(mu1);<br>
+  Mutex mu3 ACQUIRED_AFTER(mu1);<br>
+<br>
+  void test1() {<br>
+    mu1.Lock();<br>
+    mu2.Lock();<br>
+    mu3.Lock();<br>
+<br>
+    mu3.Unlock();<br>
+    mu2.Unlock();<br>
+    mu1.Unlock();<br>
+  }<br>
+<br>
+  void test2() {<br>
+    mu2.Lock();<br>
+    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}<br>
+    mu1.Unlock();<br>
+    mu2.Unlock();<br>
+  }<br>
+<br>
+  void test3() {<br>
+    mu3.Lock();<br>
+    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}<br>
+    mu1.Unlock();<br>
+    mu3.Unlock();<br>
+  }<br>
+};<br>
+<br>
+<br>
+class Foo3 {<br>
+  Mutex mu1 ACQUIRED_BEFORE(mu2);<br>
+  Mutex mu2;<br>
+  Mutex mu3 ACQUIRED_AFTER(mu2) ACQUIRED_BEFORE(mu4);<br>
+  Mutex mu4;<br>
+<br>
+  void test1() {<br>
+    mu1.Lock();<br>
+    mu2.Lock();<br>
+    mu3.Lock();<br>
+    mu4.Lock();<br>
+<br>
+    mu4.Unlock();<br>
+    mu3.Unlock();<br>
+    mu2.Unlock();<br>
+    mu1.Unlock();<br>
+  }<br>
+<br>
+  void test2() {<br>
+    mu4.Lock();<br>
+    mu2.Lock();     // expected-warning {{mutex 'mu2' must be acquired before 'mu4'}}<br>
+<br>
+    mu2.Unlock();<br>
+    mu4.Unlock();<br>
+  }<br>
+<br>
+  void test3() {<br>
+    mu4.Lock();<br>
+    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu4'}}<br>
+<br>
+    mu1.Unlock();<br>
+    mu4.Unlock();<br>
+  }<br>
+<br>
+  void test4() {<br>
+    mu3.Lock();<br>
+    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}<br>
+<br>
+    mu1.Unlock();<br>
+    mu3.Unlock();<br>
+  }<br>
+};<br>
+<br>
+<br>
+// Test transitive DAG traversal with AFTER<br>
+class Foo4 {<br>
+  Mutex mu1;<br>
+  Mutex mu2 ACQUIRED_AFTER(mu1);<br>
+  Mutex mu3 ACQUIRED_AFTER(mu1);<br>
+  Mutex mu4 ACQUIRED_AFTER(mu2, mu3);<br>
+  Mutex mu5 ACQUIRED_AFTER(mu4);<br>
+  Mutex mu6 ACQUIRED_AFTER(mu4);<br>
+  Mutex mu7 ACQUIRED_AFTER(mu5, mu6);<br>
+  Mutex mu8 ACQUIRED_AFTER(mu7);<br>
+<br>
+  void test() {<br>
+    mu8.Lock();<br>
+    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu8'}}<br>
+    mu1.Unlock();<br>
+    mu8.Unlock();<br>
+  }<br>
+};<br>
+<br>
+<br>
+// Test transitive DAG traversal with BEFORE<br>
+class Foo5 {<br>
+  Mutex mu1 ACQUIRED_BEFORE(mu2, mu3);<br>
+  Mutex mu2 ACQUIRED_BEFORE(mu4);<br>
+  Mutex mu3 ACQUIRED_BEFORE(mu4);<br>
+  Mutex mu4 ACQUIRED_BEFORE(mu5, mu6);<br>
+  Mutex mu5 ACQUIRED_BEFORE(mu7);<br>
+  Mutex mu6 ACQUIRED_BEFORE(mu7);<br>
+  Mutex mu7 ACQUIRED_BEFORE(mu8);<br>
+  Mutex mu8;<br>
+<br>
+  void test() {<br>
+    mu8.Lock();<br>
+    mu1.Lock();  // expected-warning {{mutex 'mu1' must be acquired before 'mu8'}}<br>
+    mu1.Unlock();<br>
+    mu8.Unlock();<br>
+  }<br>
+};<br>
+<br>
+<br>
+class Foo6 {<br>
+  Mutex mu1 ACQUIRED_AFTER(mu3);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu1'}}<br>
+  Mutex mu2 ACQUIRED_AFTER(mu1);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu2'}}<br>
+  Mutex mu3 ACQUIRED_AFTER(mu2);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu3'}}<br>
+<br>
+  Mutex mu_b ACQUIRED_BEFORE(mu_b);  // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu_b'}}<br>
+  Mutex mu_a ACQUIRED_AFTER(mu_a);   // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu_a'}}<br>
+<br>
+  void test0() {<br>
+    mu_a.Lock();<br>
+    mu_b.Lock();<br>
+    mu_b.Unlock();<br>
+    mu_a.Unlock();<br>
+  }<br>
+<br>
+  void test1a() {<br>
+    mu1.Lock();<br>
+    mu1.Unlock();<br>
+  }<br>
+<br>
+  void test1b() {<br>
+    mu1.Lock();<br>
+    mu_a.Lock();<br>
+    mu_b.Lock();<br>
+    mu_b.Unlock();<br>
+    mu_a.Unlock();<br>
+    mu1.Unlock();<br>
+  }<br>
+<br>
+  void test() {<br>
+    mu2.Lock();<br>
+    mu2.Unlock();<br>
+  }<br>
+<br>
+  void test3() {<br>
+    mu3.Lock();<br>
+    mu3.Unlock();<br>
+  }<br>
+};<br>
+<br>
+<br>
+}  // end namespace AcquiredBeforeAfterTest<br>
+<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>