From: DeLesley Hutchins Date: Fri, 4 May 2012 16:28:38 +0000 (+0000) Subject: Thread safety analysis: check for LOCKABLE attribute on base classes. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bbba25fa8e388e82e04f66784c2fc9f89b901abe;p=clang Thread safety analysis: check for LOCKABLE attribute on base classes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156175 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 3706bb8c8c..ba1e69990f 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -14,6 +14,7 @@ #include "clang/Sema/SemaInternal.h" #include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclObjC.h" @@ -298,6 +299,16 @@ static const RecordType *getRecordType(QualType QT) { return 0; } + +bool checkBaseClassIsLockableCallback(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, void *UserData) { + const RecordType *RT = Specifier->getType()->getAs(); + if (RT->getDecl()->getAttr()) + return true; + return false; +} + + /// \brief Thread Safety Analysis: Checks that the passed in RecordType /// resolves to a lockable object. static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr, @@ -320,12 +331,20 @@ static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr, if (threadSafetyCheckIsSmartPointer(S, RT)) return; - // Warn if the type is not lockable. - if (!RT->getDecl()->getAttr()) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) - << Attr.getName() << Ty.getAsString(); + // Check if the type is lockable. + RecordDecl *RD = RT->getDecl(); + if (RD->getAttr()) return; + + // Else check if any base classes are lockable. + if (CXXRecordDecl *CRD = dyn_cast(RD)) { + CXXBasePaths BPaths(false, false); + if (CRD->lookupInBases(checkBaseClassIsLockableCallback, 0, BPaths)) + return; } + + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) + << Attr.getName() << Ty.getAsString(); } /// \brief Thread Safety Analysis: Checks that all attribute arguments, starting diff --git a/test/SemaCXX/warn-thread-safety-parsing.cpp b/test/SemaCXX/warn-thread-safety-parsing.cpp index 62db3afeff..3f8a735908 100644 --- a/test/SemaCXX/warn-thread-safety-parsing.cpp +++ b/test/SemaCXX/warn-thread-safety-parsing.cpp @@ -1319,6 +1319,8 @@ private: Mutex mu_; }; +} // end namespace TestMultiDecl + namespace NestedClassLateDecl { @@ -1393,5 +1395,38 @@ public: } -} // end namespace TestMultiDecl +namespace InheritanceTest { + +class LOCKABLE Base { + public: + void lock() EXCLUSIVE_LOCK_FUNCTION(); + void unlock() UNLOCK_FUNCTION(); +}; + +class Base2 { }; + +class Derived1 : public Base { }; + +class Derived2 : public Base2, public Derived1 { }; + +class Derived3 : public Base2 { }; + +class Foo { + Derived1 mu1_; + Derived2 mu2_; + Derived3 mu3_; + int a GUARDED_BY(mu1_); + int b GUARDED_BY(mu2_); + int c GUARDED_BY(mu3_); // \ + // expected-warning {{'guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute; type here is 'class InheritanceTest::Derived3'}} + + void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1_, mu2_) { + a = 0; + b = 0; + } +}; + +} + +