<div class="gmail_extra"><div class="gmail_quote">On Fri, Sep 7, 2012 at 1:34 PM, DeLesley Hutchins <span dir="ltr"><<a href="mailto:delesley@google.com" target="_blank" class="cremed">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: Fri Sep Â 7 12:34:53 2012<br>
New Revision: 163397<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=163397&view=rev" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project?rev=163397&view=rev</a><br>
Log:<br>
Thread-safety analysis: Â Add support for selectively turning off warnings<br>
within part of a particular method.<br></blockquote><div><br></div><div>This is a pretty big new feature in the thread safety annotations and analysis. I think we should probably discuss it on cfe-dev and make sure the design is right and there aren't any serious problems with the proposal.</div>
<div><br></div><div>Currently, I don't really understand the use cases that make this solution (as opposed to other techniques for turning off thread safety analysis) the best solution. I suspect others may have similar questions.</div>
<div><br></div><div>Also, whatever the final design for this is should get documented carefully so that we have something to refer people to when using these types of features.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<br>
Modified:<br>
  Â  cfe/trunk/lib/Analysis/ThreadSafety.cpp<br>
  Â  cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>
  Â  cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp<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=163397&r1=163396&r2=163397&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=163397&r1=163396&r2=163397&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Fri Sep Â 7 12:34:53 2012<br>
@@ -70,18 +70,19 @@<br>
 class SExpr {<br>
 private:<br>
  Â enum ExprOp {<br>
- Â  Â EOP_Nop, Â  Â  Â ///< No-op<br>
- Â  Â EOP_Wildcard, ///< Matches anything.<br>
- Â  Â EOP_This, Â  Â  ///< This keyword.<br>
- Â  Â EOP_NVar, Â  Â  ///< Named variable.<br>
- Â  Â EOP_LVar, Â  Â  ///< Local variable.<br>
- Â  Â EOP_Dot, Â  Â  Â ///< Field access<br>
- Â  Â EOP_Call, Â  Â  ///< Function call<br>
- Â  Â EOP_MCall, Â  Â ///< Method call<br>
- Â  Â EOP_Index, Â  Â ///< Array index<br>
- Â  Â EOP_Unary, Â  Â ///< Unary operation<br>
- Â  Â EOP_Binary, Â  ///< Binary operation<br>
- Â  Â EOP_Unknown Â  ///< Catchall for everything else<br>
+ Â  Â EOP_Nop, Â  Â  Â  ///< No-op<br>
+ Â  Â EOP_Wildcard, Â ///< Matches anything.<br>
+ Â  Â EOP_Universal, ///< Universal lock.<br>
+ Â  Â EOP_This, Â  Â  Â ///< This keyword.<br>
+ Â  Â EOP_NVar, Â  Â  Â ///< Named variable.<br>
+ Â  Â EOP_LVar, Â  Â  Â ///< Local variable.<br>
+ Â  Â EOP_Dot, Â  Â  Â  ///< Field access<br>
+ Â  Â EOP_Call, Â  Â  Â ///< Function call<br>
+ Â  Â EOP_MCall, Â  Â  ///< Method call<br>
+ Â  Â EOP_Index, Â  Â  ///< Array index<br>
+ Â  Â EOP_Unary, Â  Â  ///< Unary operation<br>
+ Â  Â EOP_Binary, Â  Â ///< Binary operation<br>
+ Â  Â EOP_Unknown Â  Â ///< Catchall for everything else<br>
  Â };<br>
<br>
<br>
@@ -118,18 +119,19 @@<br>
<br>
  Â  Â unsigned arity() const {<br>
  Â  Â  Â switch (Op) {<br>
- Â  Â  Â  Â case EOP_Nop: Â  Â  Â return 0;<br>
- Â  Â  Â  Â case EOP_Wildcard: return 0;<br>
- Â  Â  Â  Â case EOP_NVar: Â  Â  return 0;<br>
- Â  Â  Â  Â case EOP_LVar: Â  Â  return 0;<br>
- Â  Â  Â  Â case EOP_This: Â  Â  return 0;<br>
- Â  Â  Â  Â case EOP_Dot: Â  Â  Â return 1;<br>
- Â  Â  Â  Â case EOP_Call: Â  Â  return Flags+1; Â // First arg is function.<br>
- Â  Â  Â  Â case EOP_MCall: Â  Â return Flags+1; Â // First arg is implicit obj.<br>
- Â  Â  Â  Â case EOP_Index: Â  Â return 2;<br>
- Â  Â  Â  Â case EOP_Unary: Â  Â return 1;<br>
- Â  Â  Â  Â case EOP_Binary: Â  return 2;<br>
- Â  Â  Â  Â case EOP_Unknown: Â return Flags;<br>
+ Â  Â  Â  Â case EOP_Nop: Â  Â  Â  return 0;<br>
+ Â  Â  Â  Â case EOP_Wildcard: Â return 0;<br>
+ Â  Â  Â  Â case EOP_Universal: return 0;<br>
+ Â  Â  Â  Â case EOP_NVar: Â  Â  Â return 0;<br>
+ Â  Â  Â  Â case EOP_LVar: Â  Â  Â return 0;<br>
+ Â  Â  Â  Â case EOP_This: Â  Â  Â return 0;<br>
+ Â  Â  Â  Â case EOP_Dot: Â  Â  Â  return 1;<br>
+ Â  Â  Â  Â case EOP_Call: Â  Â  Â return Flags+1; Â // First arg is function.<br>
+ Â  Â  Â  Â case EOP_MCall: Â  Â  return Flags+1; Â // First arg is implicit obj.<br>
+ Â  Â  Â  Â case EOP_Index: Â  Â  return 2;<br>
+ Â  Â  Â  Â case EOP_Unary: Â  Â  return 1;<br>
+ Â  Â  Â  Â case EOP_Binary: Â  Â return 2;<br>
+ Â  Â  Â  Â case EOP_Unknown: Â  return Flags;<br>
  Â  Â  Â }<br>
  Â  Â  Â return 0;<br>
  Â  Â }<br>
@@ -194,6 +196,11 @@<br>
  Â  Â return NodeVec.size()-1;<br>
  Â }<br>
<br>
+ Â unsigned makeUniversal() {<br>
+ Â  Â NodeVec.push_back(SExprNode(EOP_Universal, 0, 0));<br>
+ Â  Â return NodeVec.size()-1;<br>
+ Â }<br>
+<br>
  Â unsigned makeNamedVar(const NamedDecl *D) {<br>
  Â  Â NodeVec.push_back(SExprNode(EOP_NVar, 0, D));<br>
  Â  Â return NodeVec.size()-1;<br>
@@ -447,10 +454,18 @@<br>
  Â void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {<br>
  Â  Â CallingContext CallCtx(D);<br>
<br>
- Â  Â // Ignore string literals<br>
- Â  Â if (MutexExp && isa<StringLiteral>(MutexExp)) {<br>
- Â  Â  Â makeNop();<br>
- Â  Â  Â return;<br>
+<br>
+ Â  Â if (MutexExp) {<br>
+ Â  Â  Â if (StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {<br>
+ Â  Â  Â  Â if (SLit->getString() == StringRef("*"))<br>
+ Â  Â  Â  Â  Â // The "*" expr is a universal lock, which essentially turns off<br>
+ Â  Â  Â  Â  Â // checks until it is removed from the lockset.<br>
+ Â  Â  Â  Â  Â makeUniversal();<br>
+ Â  Â  Â  Â else<br>
+ Â  Â  Â  Â  Â // Ignore other string literals for now.<br>
+ Â  Â  Â  Â  Â makeNop();<br>
+ Â  Â  Â  Â return;<br>
+ Â  Â  Â }<br>
  Â  Â }<br>
<br>
  Â  Â // If we are processing a raw attribute expression, with no substitutions.<br>
@@ -520,6 +535,11 @@<br>
  Â  Â return NodeVec[0].kind() == EOP_Nop;<br>
  Â }<br>
<br>
+ Â bool isUniversal() const {<br>
+ Â  Â assert(NodeVec.size() > 0 && "Invalid Mutex");<br>
+ Â  Â return NodeVec[0].kind() == EOP_Universal;<br>
+ Â }<br>
+<br>
  Â /// Issue a warning about an invalid lock expression<br>
  Â static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â Expr *DeclExp, const NamedDecl* D) {<br>
@@ -567,6 +587,8 @@<br>
  Â  Â  Â  Â return "_";<br>
  Â  Â  Â case EOP_Wildcard:<br>
  Â  Â  Â  Â return "(?)";<br>
+ Â  Â  Â case EOP_Universal:<br>
+ Â  Â  Â  Â return "*";<br>
  Â  Â  Â case EOP_This:<br>
  Â  Â  Â  Â return "this";<br>
  Â  Â  Â case EOP_NVar:<br>
@@ -709,6 +731,10 @@<br>
  Â  Â ID.AddInteger(AcquireLoc.getRawEncoding());<br>
  Â  Â ID.AddInteger(LKind);<br>
  Â }<br>
+<br>
+ Â bool isAtLeast(LockKind LK) {<br>
+ Â  Â return (LK == LK_Shared) || (LKind == LK_Exclusive);<br>
+ Â }<br>
 };<br>
<br>
<br>
@@ -796,7 +822,16 @@<br>
<br>
  Â LockData* findLock(FactManager& FM, const SExpr& M) const {<br>
  Â  Â for (const_iterator I=begin(), E=end(); I != E; ++I) {<br>
- Â  Â  Â if (FM[*I].MutID.matches(M)) return &FM[*I].LDat;<br>
+ Â  Â  Â const SExpr& E = FM[*I].MutID;<br>
+ Â  Â  Â if (E.matches(M)) return &FM[*I].LDat;<br>
+ Â  Â }<br>
+ Â  Â return 0;<br>
+ Â }<br>
+<br>
+ Â LockData* findLockUniv(FactManager& FM, const SExpr& M) const {<br>
+ Â  Â for (const_iterator I=begin(), E=end(); I != E; ++I) {<br>
+ Â  Â  Â const SExpr& E = FM[*I].MutID;<br>
+ Â  Â  Â if (E.matches(M) || E.isUniversal()) return &FM[*I].LDat;<br>
  Â  Â }<br>
  Â  Â return 0;<br>
  Â }<br>
@@ -1654,39 +1689,12 @@<br>
<br>
  Â void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK,<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â Expr *MutexExp, ProtectedOperationKind POK);<br>
+ Â void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp);<br>
<br>
  Â void checkAccess(Expr *Exp, AccessKind AK);<br>
  Â void checkDereference(Expr *Exp, AccessKind AK);<br>
  Â void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);<br>
<br>
- Â /// \brief Returns true if the lockset contains a lock, regardless of whether<br>
- Â /// the lock is held exclusively or shared.<br>
- Â bool locksetContains(const SExpr &Mu) const {<br>
- Â  Â return FSet.findLock(Analyzer->FactMan, Mu);<br>
- Â }<br>
-<br>
- Â /// \brief Returns true if the lockset contains a lock with the passed in<br>
- Â /// locktype.<br>
- Â bool locksetContains(const SExpr &Mu, LockKind KindRequested) const {<br>
- Â  Â const LockData *LockHeld = FSet.findLock(Analyzer->FactMan, Mu);<br>
- Â  Â return (LockHeld && KindRequested == LockHeld->LKind);<br>
- Â }<br>
-<br>
- Â /// \brief Returns true if the lockset contains a lock with at least the<br>
- Â /// passed in locktype. So for example, if we pass in LK_Shared, this function<br>
- Â /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in<br>
- Â /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.<br>
- Â bool locksetContainsAtLeast(const SExpr &Lock,<br>
- Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â LockKind KindRequested) const {<br>
- Â  Â switch (KindRequested) {<br>
- Â  Â  Â case LK_Shared:<br>
- Â  Â  Â  Â return locksetContains(Lock);<br>
- Â  Â  Â case LK_Exclusive:<br>
- Â  Â  Â  Â return locksetContains(Lock, KindRequested);<br>
- Â  Â }<br>
- Â  Â llvm_unreachable("Unknown LockKind");<br>
- Â }<br>
-<br>
 public:<br>
  Â BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)<br>
  Â  Â : StmtVisitor<BuildLockset>(),<br>
@@ -1724,15 +1732,35 @@<br>
  Â LockKind LK = getLockKindFromAccessKind(AK);<br>
<br>
  Â SExpr Mutex(MutexExp, Exp, D);<br>
- Â if (!Mutex.isValid())<br>
+ Â if (!Mutex.isValid()) {<br>
  Â  Â SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);<br>
- Â else if (Mutex.shouldIgnore())<br>
- Â  Â return; Â // A Nop is an invalid mutex that we've decided to ignore.<br>
- Â else if (!locksetContainsAtLeast(Mutex, LK))<br>
+ Â  Â return;<br>
+ Â } else if (Mutex.shouldIgnore()) {<br>
+ Â  Â return;<br>
+ Â }<br>
+<br>
+ Â LockData* LDat = FSet.findLockUniv(Analyzer->FactMan, Mutex);<br>
+ Â if (!LDat || !LDat->isAtLeast(LK))<br>
  Â  Â Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Exp->getExprLoc());<br>
 }<br>
<br>
+/// \brief Warn if the LSet contains the given lock.<br>
+void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,<br>
+ Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Expr *MutexExp) {<br>
+ Â SExpr Mutex(MutexExp, Exp, D);<br>
+ Â if (!Mutex.isValid()) {<br>
+ Â  Â SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);<br>
+ Â  Â return;<br>
+ Â }<br>
+<br>
+ Â LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex);<br>
+ Â if (LDat)<br>
+ Â  Â Analyzer->Handler.handleFunExcludesLock(D->getName(), Mutex.toString(),<br>
+ Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â Exp->getExprLoc());<br>
+}<br>
+<br>
+<br>
 /// \brief This method identifies variable dereferences and checks pt_guarded_by<br>
 /// and pt_guarded_var annotations. Note that we only check these annotations<br>
 /// at the time a pointer is dereferenced.<br>
@@ -1841,15 +1869,10 @@<br>
<br>
  Â  Â  Â case attr::LocksExcluded: {<br>
  Â  Â  Â  Â LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);<br>
+<br>
  Â  Â  Â  Â for (LocksExcludedAttr::args_iterator I = A->args_begin(),<br>
  Â  Â  Â  Â  Â  Â E = A->args_end(); I != E; ++I) {<br>
- Â  Â  Â  Â  Â SExpr Mutex(*I, Exp, D);<br>
- Â  Â  Â  Â  Â if (!Mutex.isValid())<br>
- Â  Â  Â  Â  Â  Â SExpr::warnInvalidLock(Analyzer->Handler, *I, Exp, D);<br>
- Â  Â  Â  Â  Â else if (locksetContains(Mutex))<br>
- Â  Â  Â  Â  Â  Â Analyzer->Handler.handleFunExcludesLock(D->getName(),<br>
- Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â Mutex.toString(),<br>
- Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â Exp->getExprLoc());<br>
+ Â  Â  Â  Â  Â warnIfMutexHeld(D, Exp, *I);<br>
  Â  Â  Â  Â }<br>
  Â  Â  Â  Â break;<br>
  Â  Â  Â }<br>
@@ -2037,7 +2060,7 @@<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â JoinLoc, LEK1);<br>
  Â  Â  Â  Â }<br>
  Â  Â  Â }<br>
- Â  Â  Â else if (!LDat2.Managed)<br>
+ Â  Â  Â else if (!LDat2.Managed && !FSet2Mutex.isUniversal())<br>
  Â  Â  Â  Â Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(),<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â LDat2.AcquireLoc,<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â JoinLoc, LEK1);<br>
@@ -2060,7 +2083,7 @@<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â JoinLoc, LEK1);<br>
  Â  Â  Â  Â }<br>
  Â  Â  Â }<br>
- Â  Â  Â else if (!LDat1.Managed)<br>
+ Â  Â  Â else if (!LDat1.Managed && !FSet1Mutex.isUniversal())<br>
  Â  Â  Â  Â Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(),<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â LDat1.AcquireLoc,<br>
  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â  Â JoinLoc, LEK2);<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=163397&r1=163396&r2=163397&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=163397&r1=163396&r2=163397&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Sep Â 7 12:34:53 2012<br>
@@ -415,8 +415,10 @@<br>
  Â  Â }<br>
<br>
  Â  Â if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) {<br>
- Â  Â  Â if (StrLit->getLength() == 0) {<br>
+ Â  Â  Â if (StrLit->getLength() == 0 ||<br>
+ Â  Â  Â  Â  Â StrLit->getString() == StringRef("*")) {<br>
  Â  Â  Â  Â // Pass empty strings to the analyzer without warnings.<br>
+ Â  Â  Â  Â // Treat "*" as the universal lock.<br>
  Â  Â  Â  Â Args.push_back(ArgExp);<br>
  Â  Â  Â  Â continue;<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=163397&r1=163396&r2=163397&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=163397&r1=163396&r2=163397&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 Fri Sep Â 7 12:34:53 2012<br>
@@ -24,10 +24,6 @@<br>
  Â __attribute__ ((shared_locks_required(__VA_ARGS__)))<br>
 #define NO_THREAD_SAFETY_ANALYSIS Â __attribute__ ((no_thread_safety_analysis))<br>
<br>
-//-----------------------------------------//<br>
-// Â Helper fields<br>
-//-----------------------------------------//<br>
-<br>
<br>
 class Â __attribute__((lockable)) Mutex {<br>
  public:<br>
@@ -60,6 +56,14 @@<br>
 };<br>
<br>
<br>
+// The universal lock, written "*", allows checking to be selectively turned<br>
+// off for a particular piece of code.<br>
+void beginNoWarnOnReads() Â SHARED_LOCK_FUNCTION("*");<br>
+void endNoWarnOnReads() Â  Â UNLOCK_FUNCTION("*");<br>
+void beginNoWarnOnWrites() EXCLUSIVE_LOCK_FUNCTION("*");<br>
+void endNoWarnOnWrites() Â  UNLOCK_FUNCTION("*");<br>
+<br>
+<br>
 template<class T><br>
 class SmartPtr {<br>
 public:<br>
@@ -3217,3 +3221,79 @@<br>
 }<br>
<br>
<br>
+namespace UniversalLock {<br>
+<br>
+class Foo {<br>
+ Â Mutex mu_;<br>
+ Â bool c;<br>
+<br>
+ Â int a Â  Â  Â  Â GUARDED_BY(mu_);<br>
+ Â void r_foo() SHARED_LOCKS_REQUIRED(mu_);<br>
+ Â void w_foo() EXCLUSIVE_LOCKS_REQUIRED(mu_);<br>
+<br>
+ Â void test1() {<br>
+ Â  Â int b;<br>
+<br>
+ Â  Â beginNoWarnOnReads();<br>
+ Â  Â b = a;<br>
+ Â  Â r_foo();<br>
+ Â  Â endNoWarnOnReads();<br>
+<br>
+ Â  Â beginNoWarnOnWrites();<br>
+ Â  Â a = 0;<br>
+ Â  Â w_foo();<br>
+ Â  Â endNoWarnOnWrites();<br>
+ Â }<br>
+<br>
+ Â // don't warn on joins with universal lock<br>
+ Â void test2() {<br>
+ Â  Â if (c) {<br>
+ Â  Â  Â beginNoWarnOnWrites();<br>
+ Â  Â }<br>
+ Â  Â a = 0; // \<br>
+ Â  Â  Â // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}<br>
+ Â  Â endNoWarnOnWrites(); Â // \<br>
+ Â  Â  Â // expected-warning {{unlocking '*' that was not locked}}<br>
+ Â }<br>
+<br>
+<br>
+ Â // make sure the universal lock joins properly<br>
+ Â void test3() {<br>
+ Â  Â if (c) {<br>
+ Â  Â  Â mu_.Lock();<br>
+ Â  Â  Â beginNoWarnOnWrites();<br>
+ Â  Â }<br>
+ Â  Â else {<br>
+ Â  Â  Â beginNoWarnOnWrites();<br>
+ Â  Â  Â mu_.Lock();<br>
+ Â  Â }<br>
+ Â  Â a = 0;<br>
+ Â  Â endNoWarnOnWrites();<br>
+ Â  Â mu_.Unlock();<br>
+ Â }<br>
+<br>
+<br>
+ Â // combine universal lock with other locks<br>
+ Â void test4() {<br>
+ Â  Â beginNoWarnOnWrites();<br>
+ Â  Â mu_.Lock();<br>
+ Â  Â mu_.Unlock();<br>
+ Â  Â endNoWarnOnWrites();<br>
+<br>
+ Â  Â mu_.Lock();<br>
+ Â  Â beginNoWarnOnWrites();<br>
+ Â  Â endNoWarnOnWrites();<br>
+ Â  Â mu_.Unlock();<br>
+<br>
+ Â  Â mu_.Lock();<br>
+ Â  Â beginNoWarnOnWrites();<br>
+ Â  Â mu_.Unlock();<br>
+ Â  Â endNoWarnOnWrites();<br>
+ Â }<br>
+};<br>
+<br>
+}<br>
+<br>
+<br>
+<br>
+<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu" class="cremed">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank" class="cremed">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>