diff options
author | Caitlin Sadowski <supertri@google.com> | 2011-09-08 18:27:31 +0000 |
---|---|---|
committer | Caitlin Sadowski <supertri@google.com> | 2011-09-08 18:27:31 +0000 |
commit | 978191e0906606e32965cebcf81627d8e8711b13 (patch) | |
tree | 291b97771b819d7b040f5c98b75b165c217d552c /lib/Sema/AnalysisBasedWarnings.cpp | |
parent | a53257c94a4d871e64070f72edb687dcfb08c15d (diff) |
Thread safety: Adding basic support for locks required and excluded attributes
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139308 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index c155a9ed3f..41b9f3b1a8 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -1055,11 +1055,13 @@ void BuildLockset::addLocksToSet(LockKind LK, Attr *Attr, /// \brief When visiting CXXMemberCallExprs we need to examine the attributes on /// the method that is being called and add, remove or check locks in the /// lockset accordingly. -/// +/// /// FIXME: For classes annotated with one of the guarded annotations, we need /// to treat const method calls as reads and non-const method calls as writes, /// and check that the appropriate locks are held. Non-const method calls with /// the same signature as const method calls can be also treated as reads. +/// +/// FIXME: We need to also visit CallExprs to catch/check global functions. void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) { NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl()); @@ -1096,11 +1098,58 @@ void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) { } for (UnlockFunctionAttr::args_iterator I = UFAttr->args_begin(), - E = UFAttr->args_end(); I != E; ++I) + E = UFAttr->args_end(); I != E; ++I) removeLock(ExpLocation, *I); break; } + case attr::ExclusiveLocksRequired: { + // FIXME: Also use this attribute to add required locks to the initial + // lockset when processing a CFG for a function annotated with this + // attribute. + ExclusiveLocksRequiredAttr *ELRAttr = + cast<ExclusiveLocksRequiredAttr>(Attr); + + for (ExclusiveLocksRequiredAttr::args_iterator + I = ELRAttr->args_begin(), E = ELRAttr->args_end(); I != E; ++I) { + LockID Lock(*I); + warnIfLockNotHeld(D, Exp, AK_Written, Lock, + diag::warn_fun_requires_lock); + } + break; + } + + case attr::SharedLocksRequired: { + // FIXME: Also use this attribute to add required locks to the initial + // lockset when processing a CFG for a function annotated with this + // attribute. + SharedLocksRequiredAttr *SLRAttr = cast<SharedLocksRequiredAttr>(Attr); + + for (SharedLocksRequiredAttr::args_iterator I = SLRAttr->args_begin(), + E = SLRAttr->args_end(); I != E; ++I) { + LockID Lock(*I); + warnIfLockNotHeld(D, Exp, AK_Read, Lock, + diag::warn_fun_requires_lock); + } + break; + } + + case attr::LocksExcluded: { + LocksExcludedAttr *LEAttr = cast<LocksExcludedAttr>(Attr); + for (LocksExcludedAttr::args_iterator I = LEAttr->args_begin(), + E = LEAttr->args_end(); I != E; ++I) { + LockID Lock(*I); + if (locksetContains(Lock)) + S.Diag(ExpLocation, diag::warn_fun_excludes_lock) + << D->getName() << Lock.getName(); + } + break; + } + + case attr::LockReturned: + // FIXME: Deal with this attribute. + break; + // Ignore other (non thread-safety) attributes default: break; |