From 8121639910129a2b59aa85fc597e47cacad8b978 Mon Sep 17 00:00:00 2001 From: DeLesley Hutchins Date: Mon, 17 Oct 2011 21:38:02 +0000 Subject: [PATCH] Substitute for arguments in method calls -- functionality git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142267 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/ThreadSafety.cpp | 43 +++++++++++---- test/SemaCXX/warn-thread-safety-analysis.cpp | 55 ++++++++++++++++++++ 2 files changed, 87 insertions(+), 11 deletions(-) diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index b01ca51dfe..a03e5a6994 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -156,23 +156,31 @@ class MutexID { /// Build a Decl sequence representing the lock from the given expression. /// Recursive function that bottoms out when the final DeclRefExpr is reached. - // FIXME: Lock expressions that involve array indices or function calls. - // FIXME: Deal with LockReturned attribute. - void buildMutexID(Expr *Exp, Expr *Parent) { + void buildMutexID(Expr *Exp, Expr *Parent, int NumArgs, + const NamedDecl **FunArgDecls, Expr **FunArgs) { if (DeclRefExpr *DRE = dyn_cast(Exp)) { + if (FunArgDecls) { + // Substitute call arguments for references to function parameters + for (int i = 0; i < NumArgs; ++i) { + if (DRE->getDecl() == FunArgDecls[i]) { + buildMutexID(FunArgs[i], 0, 0, 0, 0); + return; + } + } + } NamedDecl *ND = cast(DRE->getDecl()->getCanonicalDecl()); DeclSeq.push_back(ND); } else if (MemberExpr *ME = dyn_cast(Exp)) { NamedDecl *ND = ME->getMemberDecl(); DeclSeq.push_back(ND); - buildMutexID(ME->getBase(), Parent); + buildMutexID(ME->getBase(), Parent, NumArgs, FunArgDecls, FunArgs); } else if (isa(Exp)) { if (Parent) - buildMutexID(Parent, 0); + buildMutexID(Parent, 0, 0, 0, 0); else return; // mutexID is still valid in this case } else if (CastExpr *CE = dyn_cast(Exp)) - buildMutexID(CE->getSubExpr(), Parent); + buildMutexID(CE->getSubExpr(), Parent, NumArgs, FunArgDecls, FunArgs); else DeclSeq.clear(); // Mark as invalid lock expression. } @@ -184,23 +192,36 @@ class MutexID { /// \param D The declaration to which the lock/unlock attribute is attached. void buildMutexIDFromExp(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) { Expr *Parent = 0; + unsigned NumArgs = 0; + Expr **FunArgs = 0; + SmallVector FunArgDecls; if (DeclExp == 0) { - buildMutexID(MutexExp, 0); + buildMutexID(MutexExp, 0, 0, 0, 0); return; } - if (MemberExpr *ME = dyn_cast(DeclExp)) + if (MemberExpr *ME = dyn_cast(DeclExp)) { Parent = ME->getBase(); - else if (CXXMemberCallExpr *CE = dyn_cast(DeclExp)) + } else if (CXXMemberCallExpr *CE = dyn_cast(DeclExp)) { Parent = CE->getImplicitObjectArgument(); + NumArgs = CE->getNumArgs(); + FunArgs = CE->getArgs(); + } // If the attribute has no arguments, then assume the argument is "this". if (MutexExp == 0) { - buildMutexID(Parent, 0); + buildMutexID(Parent, 0, 0, 0, 0); return; } - buildMutexID(MutexExp, Parent); + + // FIXME: handle default arguments + if (const FunctionDecl *FD = dyn_cast_or_null(D)) { + for (unsigned i = 0, ni = FD->getNumParams(); i < ni && i < NumArgs; ++i) { + FunArgDecls.push_back(FD->getParamDecl(i)); + } + } + buildMutexID(MutexExp, Parent, NumArgs, &FunArgDecls.front(), FunArgs); } public: diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp index 90a8933150..efa19fdcf7 100644 --- a/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -740,6 +740,7 @@ void es_bad_7() { sls_mu.Unlock(); } + //-----------------------------------------------// // Unparseable lock expressions // ----------------------------------------------// @@ -1420,3 +1421,57 @@ void main() } // end namespace thread_annot_lock_67_modified +namespace substitution_test { + class MyData { + public: + Mutex mu; + + void lockData() __attribute__((exclusive_lock_function(mu))) { } + void unlockData() __attribute__((unlock_function(mu))) { } + + void doSomething() __attribute__((exclusive_locks_required(mu))) { } + }; + + + class DataLocker { + public: + void lockData (MyData *d) __attribute__((exclusive_lock_function(d->mu))) { } + void unlockData(MyData *d) __attribute__((unlock_function(d->mu))) { } + }; + + + class Foo { + public: + void foo(MyData* d) __attribute__((exclusive_locks_required(d->mu))) { } + + void bar1(MyData* d) { + d->lockData(); + foo(d); + d->unlockData(); + } + + void bar2(MyData* d) { + DataLocker dlr; + dlr.lockData(d); + foo(d); + dlr.unlockData(d); + } + + void bar3(MyData* d1, MyData* d2) { + DataLocker dlr; + dlr.lockData(d1); // \ + // expected-warning {{mutex 'mu' is still locked at the end of function}} + dlr.unlockData(d2); // \ + // expected-warning {{unlocking 'mu' that was not locked}} + } + + void bar4(MyData* d1, MyData* d2) { + DataLocker dlr; + dlr.lockData(d1); + foo(d2); // \ + // expected-warning {{calling function 'foo' requires exclusive lock on 'mu'}} + dlr.unlockData(d1); + } + }; +} // end namespace substituation_test + -- 2.40.0