From: DeLesley Hutchins Date: Fri, 20 Jan 2012 23:24:41 +0000 (+0000) Subject: Handle thread safety attributes on functions with separate definitions and declarations. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e03b2b3ca9032b18fd1c3d0fca7692e4d2551277;p=clang Handle thread safety attributes on functions with separate definitions and declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148599 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index 25f86084cf..6f76f1b947 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -88,38 +88,46 @@ class MutexID { /// Recursive function that terminates on DeclRefExpr. /// Note: this function merely creates a MutexID; it does not check to /// ensure that the original expression is a valid mutex expression. - void buildMutexID(Expr *Exp, Expr *Parent, int NumArgs, - const NamedDecl **FunArgDecls, Expr **FunArgs) { + void buildMutexID(Expr *Exp, const NamedDecl *D, Expr *Parent, + unsigned NumArgs, Expr **FunArgs) { if (!Exp) { DeclSeq.clear(); return; } 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()); + ParmVarDecl *PV = dyn_cast_or_null(ND); + if (PV) { + FunctionDecl *FD = + cast(PV->getDeclContext())->getCanonicalDecl(); + unsigned i = PV->getFunctionScopeIndex(); + + if (FunArgs && FD == D->getCanonicalDecl()) { + // Substitute call arguments for references to function parameters + assert(i < NumArgs); + buildMutexID(FunArgs[i], D, 0, 0, 0); + return; } + // Map the param back to the param of the original function declaration. + DeclSeq.push_back(FD->getParamDecl(i)); + return; } - NamedDecl *ND = cast(DRE->getDecl()->getCanonicalDecl()); + // Not a function parameter -- just store the reference. DeclSeq.push_back(ND); } else if (MemberExpr *ME = dyn_cast(Exp)) { NamedDecl *ND = ME->getMemberDecl(); DeclSeq.push_back(ND); - buildMutexID(ME->getBase(), Parent, NumArgs, FunArgDecls, FunArgs); + buildMutexID(ME->getBase(), D, Parent, NumArgs, FunArgs); } else if (isa(Exp)) { if (Parent) - buildMutexID(Parent, 0, 0, 0, 0); + buildMutexID(Parent, D, 0, 0, 0); else return; // mutexID is still valid in this case } else if (UnaryOperator *UOE = dyn_cast(Exp)) - buildMutexID(UOE->getSubExpr(), Parent, NumArgs, FunArgDecls, FunArgs); + buildMutexID(UOE->getSubExpr(), D, Parent, NumArgs, FunArgs); else if (CastExpr *CE = dyn_cast(Exp)) - buildMutexID(CE->getSubExpr(), Parent, NumArgs, FunArgDecls, FunArgs); + buildMutexID(CE->getSubExpr(), D, Parent, NumArgs, FunArgs); else DeclSeq.clear(); // Mark as invalid lock expression. } @@ -133,11 +141,10 @@ class MutexID { Expr *Parent = 0; unsigned NumArgs = 0; Expr **FunArgs = 0; - SmallVector FunArgDecls; // If we are processing a raw attribute expression, with no substitutions. if (DeclExp == 0) { - buildMutexID(MutexExp, 0, 0, 0, 0); + buildMutexID(MutexExp, D, 0, 0, 0); return; } @@ -163,17 +170,11 @@ class MutexID { // If the attribute has no arguments, then assume the argument is "this". if (MutexExp == 0) { - buildMutexID(Parent, 0, 0, 0, 0); + buildMutexID(Parent, D, 0, 0, 0); return; } - // 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); + buildMutexID(MutexExp, D, Parent, NumArgs, FunArgs); } public: diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp index f992380433..dfec94ca91 100644 --- a/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -1875,3 +1875,29 @@ void testDelayed() { }; // end namespace TestTemplateAttributeInstantiation +namespace FunctionDeclDefTest { + +class Foo { +public: + Mutex mu_; + int a GUARDED_BY(mu_); + + virtual void foo1(Foo *f_declared) EXCLUSIVE_LOCKS_REQUIRED(f_declared->mu_); +}; + +// EXCLUSIVE_LOCKS_REQUIRED should be applied, and rewritten to f_defined->mu_ +void Foo::foo1(Foo *f_defined) { + f_defined->a = 0; +}; + +void test() { + Foo myfoo; + myfoo.foo1(&myfoo); // \ + // expected-warning {{calling function 'foo1' requires exclusive lock on 'mu_'}} + myfoo.mu_.Lock(); + myfoo.foo1(&myfoo); + myfoo.mu_.Unlock(); +} + +}; +