[cfe-commits] r149669 - in /cfe/trunk: include/clang/Analysis/Analyses/ThreadSafety.h include/clang/Basic/DiagnosticSemaKinds.td lib/Analysis/ThreadSafety.cpp lib/Sema/AnalysisBasedWarnings.cpp test/SemaCXX/warn-thread-safety-analysis.cpp

Richard Smith richard-llvm at metafoo.co.uk
Thu Feb 2 20:45:26 PST 2012


Author: rsmith
Date: Thu Feb  2 22:45:26 2012
New Revision: 149669

URL: http://llvm.org/viewvc/llvm-project?rev=149669&view=rev
Log:
Thread safety analysis:
 * When we detect that a CFG block has inconsistent lock sets, point the
   diagnostic at the location where we found the inconsistency, and point a note
   at somewhere the inconsistently-locked mutex was locked.
 * Fix the wording of the normal (non-loop, non-end-of-function) case of this
   diagnostic to not suggest that the mutex is going out of scope.
 * Fix the diagnostic emission code to keep a warning and its note together when
   sorting the diagnostics into source location order.

Modified:
    cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Analysis/ThreadSafety.cpp
    cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
    cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h?rev=149669&r1=149668&r2=149669&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h Thu Feb  2 22:45:26 2012
@@ -93,10 +93,14 @@
   /// 3. or when a mutex is locked but not unlocked inside a function.
   /// \param LockName -- A StringRef name for the lock expression, to be printed
   /// in the error message.
-  /// \param Loc -- The location of the lock expression where the mutex is
+  /// \param LocLocked -- The location of the lock expression where the mutex is
   ///               locked
+  /// \param LocEndOfScope -- The location of the end of the scope where the
+  ///               mutex is no longer held
   /// \param LEK -- which of the three above cases we should warn for
-  virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
+  virtual void handleMutexHeldEndOfScope(Name LockName,
+                                         SourceLocation LocLocked,
+                                         SourceLocation LocEndOfScope,
                                          LockErrorKind LEK){}
 
   /// Warn when a mutex is held exclusively and shared at the same point. For

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=149669&r1=149668&r2=149669&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb  2 22:45:26 2012
@@ -1642,12 +1642,13 @@
   "mutex '%0' is still locked at the end of function">,
   InGroup<ThreadSafety>, DefaultIgnore;
 // FIXME: improve the error message about locks not in scope
-def warn_lock_at_end_of_scope : Warning<
-  "mutex '%0' is still locked at the end of its scope">,
+def warn_lock_some_predecessors : Warning<
+  "mutex '%0' is not locked on every path through here">,
   InGroup<ThreadSafety>, DefaultIgnore;
 def warn_expecting_lock_held_on_loop : Warning<
   "expecting mutex '%0' to be locked at start of each loop">,
   InGroup<ThreadSafety>, DefaultIgnore;
+def note_locked_here : Note<"mutex acquired here">;
 def warn_lock_exclusive_and_shared : Warning<
   "mutex '%0' is locked exclusively and shared in the same scope">,
   InGroup<ThreadSafety>, DefaultIgnore;

Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=149669&r1=149668&r2=149669&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Thu Feb  2 22:45:26 2012
@@ -290,6 +290,8 @@
 
 class LocalVariableMap;
 
+/// A side (entry or exit) of a CFG node.
+enum CFGBlockSide { CBS_Entry, CBS_Exit };
 
 /// CFGBlockInfo is a struct which contains all the information that is
 /// maintained for each block in the CFG.  See LocalVariableMap for more
@@ -299,8 +301,17 @@
   Lockset ExitSet;              // Lockset held at exit from block
   LocalVarContext EntryContext; // Context held at entry to block
   LocalVarContext ExitContext;  // Context held at exit from block
+  SourceLocation EntryLoc;      // Location of first statement in block
+  SourceLocation ExitLoc;       // Location of last statement in block.
   unsigned EntryIndex;          // Used to replay contexts later
 
+  const Lockset &getSet(CFGBlockSide Side) const {
+    return Side == CBS_Entry ? EntrySet : ExitSet;
+  }
+  SourceLocation getLocation(CFGBlockSide Side) const {
+    return Side == CBS_Entry ? EntryLoc : ExitLoc;
+  }
+
 private:
   CFGBlockInfo(Lockset EmptySet, LocalVarContext EmptyCtx)
     : EntrySet(EmptySet), ExitSet(EmptySet),
@@ -760,6 +771,51 @@
   saveContext(0, BlockInfo[exitID].ExitContext);
 }
 
+/// Find the appropriate source locations to use when producing diagnostics for
+/// each block in the CFG.
+static void findBlockLocations(CFG *CFGraph,
+                               PostOrderCFGView *SortedGraph,
+                               std::vector<CFGBlockInfo> &BlockInfo) {
+  for (PostOrderCFGView::iterator I = SortedGraph->begin(),
+       E = SortedGraph->end(); I!= E; ++I) {
+    const CFGBlock *CurrBlock = *I;
+    CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()];
+
+    // Find the source location of the last statement in the block, if the
+    // block is not empty.
+    if (const Stmt *S = CurrBlock->getTerminator()) {
+      CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = S->getLocStart();
+    } else {
+      for (CFGBlock::const_reverse_iterator BI = CurrBlock->rbegin(),
+           BE = CurrBlock->rend(); BI != BE; ++BI) {
+        // FIXME: Handle other CFGElement kinds.
+        if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) {
+          CurrBlockInfo->ExitLoc = CS->getStmt()->getLocStart();
+          break;
+        }
+      }
+    }
+
+    if (!CurrBlockInfo->ExitLoc.isInvalid()) {
+      // This block contains at least one statement. Find the source location
+      // of the first statement in the block.
+      for (CFGBlock::const_iterator BI = CurrBlock->begin(),
+           BE = CurrBlock->end(); BI != BE; ++BI) {
+        // FIXME: Handle other CFGElement kinds.
+        if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) {
+          CurrBlockInfo->EntryLoc = CS->getStmt()->getLocStart();
+          break;
+        }
+      }
+    } else if (CurrBlock->pred_size() == 1 && *CurrBlock->pred_begin() &&
+               CurrBlock != &CFGraph->getExit()) {
+      // The block is empty, and has a single predecessor. Use its exit
+      // location.
+      CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc =
+          BlockInfo[(*CurrBlock->pred_begin())->getBlockID()].ExitLoc;
+    }
+  }
+}
 
 /// \brief Class which implements the core thread safety analysis routines.
 class ThreadSafetyAnalyzer {
@@ -772,7 +828,8 @@
 public:
   ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {}
 
-  Lockset intersectAndWarn(const Lockset LSet1, const Lockset LSet2,
+  Lockset intersectAndWarn(const CFGBlockInfo &Block1, CFGBlockSide Side1,
+                           const CFGBlockInfo &Block2, CFGBlockSide Side2,
                            LockErrorKind LEK);
 
   Lockset addLock(Lockset &LSet, Expr *MutexExp, const NamedDecl *D,
@@ -1304,9 +1361,14 @@
 /// A; if () then B; else C; D; we need to check that the lockset after B and C
 /// are the same. In the event of a difference, we use the intersection of these
 /// two locksets at the start of D.
-Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset LSet1,
-                                               const Lockset LSet2,
+Lockset ThreadSafetyAnalyzer::intersectAndWarn(const CFGBlockInfo &Block1,
+                                               CFGBlockSide Side1,
+                                               const CFGBlockInfo &Block2,
+                                               CFGBlockSide Side2,
                                                LockErrorKind LEK) {
+  Lockset LSet1 = Block1.getSet(Side1);
+  Lockset LSet2 = Block2.getSet(Side2);
+
   Lockset Intersection = LSet1;
   for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) {
     const MutexID &LSet2Mutex = I.getKey();
@@ -1322,7 +1384,8 @@
       }
     } else {
       Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
-                                        LSet2LockData.AcquireLoc, LEK);
+                                        LSet2LockData.AcquireLoc,
+                                        Block1.getLocation(Side1), LEK);
     }
   }
 
@@ -1331,7 +1394,8 @@
       const MutexID &Mutex = I.getKey();
       const LockData &MissingLock = I.getData();
       Handler.handleMutexHeldEndOfScope(Mutex.getName(),
-                                        MissingLock.AcquireLoc, LEK);
+                                        MissingLock.AcquireLoc,
+                                        Block2.getLocation(Side2), LEK);
       Intersection = LocksetFactory.remove(Intersection, Mutex);
     }
   }
@@ -1377,6 +1441,9 @@
   // Compute SSA names for local variables
   LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
 
+  // Fill in source locations for all CFGBlocks.
+  findBlockLocations(CFGraph, SortedGraph, BlockInfo);
+
   // Add locks from exclusive_locks_required and shared_locks_required
   // to initial lockset.
   if (!SortedGraph->empty() && D->hasAttrs()) {
@@ -1456,7 +1523,8 @@
         LocksetInitialized = true;
       } else {
         CurrBlockInfo->EntrySet =
-          intersectAndWarn(CurrBlockInfo->EntrySet, PrevBlockInfo->ExitSet,
+          intersectAndWarn(*CurrBlockInfo, CBS_Entry,
+                           *PrevBlockInfo, CBS_Exit,
                            LEK_LockedSomePredecessors);
       }
     }
@@ -1482,7 +1550,7 @@
         bool IsLoop = Terminator && isa<ContinueStmt>(Terminator);
 
         // Do not update EntrySet.
-        intersectAndWarn(CurrBlockInfo->EntrySet, PrevBlockInfo->ExitSet,
+        intersectAndWarn(*CurrBlockInfo, CBS_Entry, *PrevBlockInfo, CBS_Exit,
                          IsLoop ? LEK_LockedSomeLoopIterations
                                 : LEK_LockedSomePredecessors);
       }
@@ -1541,17 +1609,19 @@
         continue;
 
       CFGBlock *FirstLoopBlock = *SI;
-      Lockset PreLoop = BlockInfo[FirstLoopBlock->getBlockID()].EntrySet;
-      Lockset LoopEnd = BlockInfo[CurrBlockID].ExitSet;
-      intersectAndWarn(LoopEnd, PreLoop, LEK_LockedSomeLoopIterations);
+      CFGBlockInfo &PreLoop = BlockInfo[FirstLoopBlock->getBlockID()];
+      CFGBlockInfo &LoopEnd = BlockInfo[CurrBlockID];
+      intersectAndWarn(LoopEnd, CBS_Exit, PreLoop, CBS_Entry,
+                       LEK_LockedSomeLoopIterations);
     }
   }
 
-  Lockset InitialLockset = BlockInfo[CFGraph->getEntry().getBlockID()].EntrySet;
-  Lockset FinalLockset = BlockInfo[CFGraph->getExit().getBlockID()].ExitSet;
+  CFGBlockInfo &Initial = BlockInfo[CFGraph->getEntry().getBlockID()];
+  CFGBlockInfo &Final = BlockInfo[CFGraph->getExit().getBlockID()];
 
   // FIXME: Should we call this function for all blocks which exit the function?
-  intersectAndWarn(InitialLockset, FinalLockset, LEK_LockedAtEndOfFunction);
+  intersectAndWarn(Initial, CBS_Entry, Final, CBS_Exit,
+                   LEK_LockedAtEndOfFunction);
 }
 
 } // end anonymous namespace

Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=149669&r1=149668&r2=149669&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Thu Feb  2 22:45:26 2012
@@ -592,7 +592,8 @@
 //===----------------------------------------------------------------------===//
 namespace clang {
 namespace thread_safety {
-typedef std::pair<SourceLocation, PartialDiagnostic> DelayedDiag;
+typedef llvm::SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
+typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
 typedef llvm::SmallVector<DelayedDiag, 4> DiagList;
 
 struct SortDiagBySourceLocation {
@@ -602,8 +603,8 @@
   bool operator()(const DelayedDiag &left, const DelayedDiag &right) {
     // Although this call will be slow, this is only called when outputting
     // multiple warnings.
-    return S.getSourceManager().isBeforeInTranslationUnit(left.first,
-                                                          right.first);
+    return S.getSourceManager().isBeforeInTranslationUnit(left.first.first,
+                                                          right.first.first);
   }
 };
 
@@ -611,7 +612,7 @@
 class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
   Sema &S;
   DiagList Warnings;
-  SourceLocation FunLocation;
+  SourceLocation FunLocation, FunEndLocation;
 
   // Helper functions
   void warnLockMismatch(unsigned DiagID, Name LockName, SourceLocation Loc) {
@@ -619,13 +620,13 @@
     // precise source location.
     if (!Loc.isValid())
       Loc = FunLocation;
-    PartialDiagnostic Warning = S.PDiag(DiagID) << LockName;
-    Warnings.push_back(DelayedDiag(Loc, Warning));
+    PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << LockName);
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
   }
 
  public:
-  ThreadSafetyReporter(Sema &S, SourceLocation FL)
-    : S(S), FunLocation(FL) {}
+  ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
+    : S(S), FunLocation(FL), FunEndLocation(FEL) {}
 
   /// \brief Emit all buffered diagnostics in order of sourcelocation.
   /// We need to output diagnostics produced while iterating through
@@ -635,13 +636,18 @@
     SortDiagBySourceLocation SortDiagBySL(S);
     sort(Warnings.begin(), Warnings.end(), SortDiagBySL);
     for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
-         I != E; ++I)
-      S.Diag(I->first, I->second);
+         I != E; ++I) {
+      S.Diag(I->first.first, I->first.second);
+      const OptionalNotes &Notes = I->second;
+      for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN; ++NoteI)
+        S.Diag(Notes[NoteI].first, Notes[NoteI].second);
+    }
   }
 
   void handleInvalidLockExp(SourceLocation Loc) {
-    PartialDiagnostic Warning = S.PDiag(diag::warn_cannot_resolve_lock) << Loc;
-    Warnings.push_back(DelayedDiag(Loc, Warning));
+    PartialDiagnosticAt Warning(Loc,
+                                S.PDiag(diag::warn_cannot_resolve_lock) << Loc);
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
   }
   void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) {
     warnLockMismatch(diag::warn_unlock_but_no_lock, LockName, Loc);
@@ -651,12 +657,13 @@
     warnLockMismatch(diag::warn_double_lock, LockName, Loc);
   }
 
-  void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
+  void handleMutexHeldEndOfScope(Name LockName, SourceLocation LocLocked,
+                                 SourceLocation LocEndOfScope,
                                  LockErrorKind LEK){
     unsigned DiagID = 0;
     switch (LEK) {
       case LEK_LockedSomePredecessors:
-        DiagID = diag::warn_lock_at_end_of_scope;
+        DiagID = diag::warn_lock_some_predecessors;
         break;
       case LEK_LockedSomeLoopIterations:
         DiagID = diag::warn_expecting_lock_held_on_loop;
@@ -665,18 +672,22 @@
         DiagID = diag::warn_no_unlock;
         break;
     }
-    warnLockMismatch(DiagID, LockName, Loc);
+    if (LocEndOfScope.isInvalid())
+      LocEndOfScope = FunEndLocation;
+
+    PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << LockName);
+    PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here));
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
   }
 
 
   void handleExclusiveAndShared(Name LockName, SourceLocation Loc1,
                                 SourceLocation Loc2) {
-    PartialDiagnostic Warning =
-      S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName;
-    PartialDiagnostic Note =
-      S.PDiag(diag::note_lock_exclusive_and_shared) << LockName;
-    Warnings.push_back(DelayedDiag(Loc1, Warning));
-    Warnings.push_back(DelayedDiag(Loc2, Note));
+    PartialDiagnosticAt Warning(
+      Loc1, S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName);
+    PartialDiagnosticAt Note(
+      Loc2, S.PDiag(diag::note_lock_exclusive_and_shared) << LockName);
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
   }
 
   void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
@@ -686,9 +697,9 @@
     unsigned DiagID = POK == POK_VarAccess?
                         diag::warn_variable_requires_any_lock:
                         diag::warn_var_deref_requires_any_lock;
-    PartialDiagnostic Warning = S.PDiag(DiagID)
-      << D->getName() << getLockKindFromAccessKind(AK);
-    Warnings.push_back(DelayedDiag(Loc, Warning));
+    PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+      << D->getName() << getLockKindFromAccessKind(AK));
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
   }
 
   void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK,
@@ -705,15 +716,15 @@
         DiagID = diag::warn_fun_requires_lock;
         break;
     }
-    PartialDiagnostic Warning = S.PDiag(DiagID)
-      << D->getName() << LockName << LK;
-    Warnings.push_back(DelayedDiag(Loc, Warning));
+    PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
+      << D->getName() << LockName << LK);
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
   }
 
   void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) {
-    PartialDiagnostic Warning =
-      S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName;
-    Warnings.push_back(DelayedDiag(Loc, Warning));
+    PartialDiagnosticAt Warning(Loc,
+      S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName);
+    Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
   }
 };
 }
@@ -897,7 +908,8 @@
   // Check for thread safety violations
   if (P.enableThreadSafetyAnalysis) {
     SourceLocation FL = AC.getDecl()->getLocation();
-    thread_safety::ThreadSafetyReporter Reporter(S, FL);
+    SourceLocation FEL = AC.getDecl()->getLocEnd();
+    thread_safety::ThreadSafetyReporter Reporter(S, FL, FEL);
     thread_safety::runThreadSafetyAnalysis(AC, Reporter);
     Reporter.emitDiagnostics();
   }

Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=149669&r1=149668&r2=149669&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Thu Feb  2 22:45:26 2012
@@ -172,30 +172,29 @@
 }
 
 void sls_fun_bad_3() {
-  sls_mu.Lock(); // \
-    // expected-warning{{mutex 'sls_mu' is still locked at the end of function}}
-}
+  sls_mu.Lock(); // expected-note {{mutex acquired here}}
+} // expected-warning{{mutex 'sls_mu' is still locked at the end of function}}
 
 void sls_fun_bad_4() {
   if (getBool())
     sls_mu.Lock(); // \
-      // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+  expected-warning{{mutex 'sls_mu2' is not locked on every path through here}} \
+  expected-note{{mutex acquired here}}
+
   else
     sls_mu2.Lock(); // \
-      // expected-warning{{mutex 'sls_mu2' is still locked at the end of its scope}}
-}
+  expected-note{{mutex acquired here}}
+} // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
 
 void sls_fun_bad_5() {
-  sls_mu.Lock(); // \
-    // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+  sls_mu.Lock(); // expected-note {{mutex acquired here}}
   if (getBool())
     sls_mu.Unlock();
-}
+} // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
 
 void sls_fun_bad_6() {
   if (getBool()) {
-    sls_mu.Lock(); // \
-      // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+    sls_mu.Lock(); // expected-note {{mutex acquired here}}
   } else {
     if (getBool()) {
       getBool(); // EMPTY
@@ -204,7 +203,8 @@
     }
   }
   sls_mu.Unlock(); // \
-    // expected-warning{{unlocking 'sls_mu' that was not locked}}
+    expected-warning{{mutex 'sls_mu' is not locked on every path through here}}\
+    expected-warning{{unlocking 'sls_mu' that was not locked}}
 }
 
 void sls_fun_bad_7() {
@@ -213,19 +213,20 @@
     sls_mu.Unlock();
     if (getBool()) {
       if (getBool()) {
-        continue;
+        continue; // \
+        expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
       }
     }
-    sls_mu.Lock(); // \
-      // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+    sls_mu.Lock(); // expected-note {{mutex acquired here}}
   }
   sls_mu.Unlock();
 }
 
 void sls_fun_bad_8() {
-  sls_mu.Lock(); // \
-    // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
-  do {
+  sls_mu.Lock(); // expected-note{{mutex acquired here}}
+
+  // FIXME: TERRIBLE SOURCE LOCATION!
+  do { // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
     sls_mu.Unlock();
   } while (getBool());
 }
@@ -233,37 +234,35 @@
 void sls_fun_bad_9() {
   do {
     sls_mu.Lock(); // \
-      // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+      // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}} \
+      // expected-note{{mutex acquired here}}
   } while (getBool());
   sls_mu.Unlock();
 }
 
 void sls_fun_bad_10() {
-  sls_mu.Lock(); // \
-    // expected-warning{{mutex 'sls_mu' is still locked at the end of function}} \
-    // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+  sls_mu.Lock(); // expected-note 2{{mutex acquired here}}
   while(getBool()) {
-    sls_mu.Unlock();
+    sls_mu.Unlock(); // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
   }
-}
+} // expected-warning{{mutex 'sls_mu' is still locked at the end of function}}
 
 void sls_fun_bad_11() {
-  while (getBool()) {
-    sls_mu.Lock(); // \
-      // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+  while (getBool()) { // \
+   expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+    sls_mu.Lock(); // expected-note {{mutex acquired here}}
   }
   sls_mu.Unlock(); // \
     // expected-warning{{unlocking 'sls_mu' that was not locked}}
 }
 
 void sls_fun_bad_12() {
-  sls_mu.Lock(); // \
-    // expected-warning{{mutex 'sls_mu' is still locked at the end of its scope}}
+  sls_mu.Lock(); // expected-note {{mutex acquired here}}
   while (getBool()) {
     sls_mu.Unlock();
     if (getBool()) {
       if (getBool()) {
-        break;
+        break; // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
       }
     }
     sls_mu.Lock();
@@ -303,9 +302,8 @@
 }
 
 void aa_fun_bad_3() {
-  glock.globalLock(); // \
-    // expected-warning{{mutex 'aa_mu' is still locked at the end of function}}
-}
+  glock.globalLock(); // expected-note{{mutex acquired here}}
+} // expected-warning{{mutex 'aa_mu' is still locked at the end of function}}
 
 //--------------------------------------------------//
 // Regression tests for unusual method names
@@ -316,22 +314,18 @@
 // Test diagnostics for other method names.
 class WeirdMethods {
   WeirdMethods() {
-    wmu.Lock(); // \
-      // expected-warning {{mutex 'wmu' is still locked at the end of function}}
-  }
+    wmu.Lock(); // expected-note {{mutex acquired here}}
+  } // expected-warning {{mutex 'wmu' is still locked at the end of function}}
   ~WeirdMethods() {
-    wmu.Lock(); // \
-      // expected-warning {{mutex 'wmu' is still locked at the end of function}}
-  }
+    wmu.Lock(); // expected-note {{mutex acquired here}}
+  } // expected-warning {{mutex 'wmu' is still locked at the end of function}}
   void operator++() {
-    wmu.Lock(); // \
-      // expected-warning {{mutex 'wmu' is still locked at the end of function}}
-  }
+    wmu.Lock(); // expected-note {{mutex acquired here}}
+  } // expected-warning {{mutex 'wmu' is still locked at the end of function}}
   operator int*() {
-    wmu.Lock(); // \
-      // expected-warning {{mutex 'wmu' is still locked at the end of function}}
+    wmu.Lock(); // expected-note {{mutex acquired here}}
     return 0;
-  }
+  } // expected-warning {{mutex 'wmu' is still locked at the end of function}}
 };
 
 //-----------------------------------------------//
@@ -1484,11 +1478,10 @@
 
     void bar3(MyData* d1, MyData* d2) {
       DataLocker dlr;
-      dlr.lockData(d1);   // \
-        // expected-warning {{mutex 'mu' is still locked at the end of function}}
+      dlr.lockData(d1);   // expected-note {{mutex acquired here}}
       dlr.unlockData(d2); // \
         // expected-warning {{unlocking 'mu' that was not locked}}
-    }
+    } // expected-warning {{mutex 'mu' is still locked at the end of function}}
 
     void bar4(MyData* d1, MyData* d2) {
       DataLocker dlr;
@@ -1914,3 +1907,32 @@
 }
 
 };
+
+namespace GoingNative {
+
+  struct __attribute__((lockable)) mutex {
+    void lock() __attribute__((exclusive_lock_function));
+    void unlock() __attribute__((unlock_function));
+    // ...
+  };
+  bool foo();
+  bool bar();
+  mutex m;
+  void test() {
+    m.lock();
+    while (foo()) {
+      m.unlock();
+      // ...
+      if (bar()) {
+        // ...
+        if (foo())
+          continue; // expected-warning {{expecting mutex 'm' to be locked at start of each loop}}
+        //...
+      }
+      // ...
+      m.lock(); // expected-note {{mutex acquired here}}
+    }
+    m.unlock();
+  }
+
+}





More information about the cfe-commits mailing list