diff options
| author | Aaron Puchert <aaronpuchert@alice-dsl.net> | 2018-09-20 00:39:27 +0000 |
|---|---|---|
| committer | Aaron Puchert <aaronpuchert@alice-dsl.net> | 2018-09-20 00:39:27 +0000 |
| commit | 7ba1ab71ecf48538021af43530c45365297580be (patch) | |
| tree | 526dbff23aa5e17e748839a2e3a1bfcfc245dce0 /clang/lib | |
| parent | 69e09116bae2fc94b5f48de2d4aee7ba3e26831a (diff) | |
| download | bcm5719-llvm-7ba1ab71ecf48538021af43530c45365297580be.tar.gz bcm5719-llvm-7ba1ab71ecf48538021af43530c45365297580be.zip | |
Thread Safety Analysis: warnings for attributes without arguments
Summary:
When thread safety annotations are used without capability arguments,
they are assumed to apply to `this` instead. So we warn when either
`this` doesn't exist, or the class is not a capability type.
This is based on earlier work by Josh Gao that was committed in r310403,
but reverted in r310698 because it didn't properly work in template
classes. See also D36237.
The solution is not to go via the QualType of `this`, which is then a
template type, hence the attributes are not known because it could be
specialized. Instead we look directly at the class in which we are
contained.
Additionally I grouped two of the warnings together. There are two
issues here: the existence of `this`, which requires us to be a
non-static member function, and the appropriate annotation on the class
we are contained in. So we don't distinguish between not being in a
class and being static, because in both cases we don't have `this`.
Fixes PR38399.
Reviewers: aaron.ballman, delesley, jmgao, rtrieu
Reviewed By: delesley
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D51901
llvm-svn: 342605
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 60 |
1 files changed, 44 insertions, 16 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index f921d3e7d76..f6df0d0e963 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -476,6 +476,29 @@ static const RecordType *getRecordType(QualType QT) { return nullptr; } +template <typename AttrType> +static bool checkRecordDeclForAttr(const RecordDecl *RD) { + // Check if the record itself has the attribute. + if (RD->hasAttr<AttrType>()) + return true; + + // Else check if any base classes have the attribute. + if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { + CXXBasePaths BPaths(false, false); + if (CRD->lookupInBases( + [](const CXXBaseSpecifier *BS, CXXBasePath &) { + const auto &Ty = *BS->getType(); + // If it's type-dependent, we assume it could have the attribute. + if (Ty.isDependentType()) + return true; + return Ty.getAs<RecordType>()->getDecl()->hasAttr<AttrType>(); + }, + BPaths, true)) + return true; + } + return false; +} + static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { const RecordType *RT = getRecordType(Ty); @@ -491,21 +514,7 @@ static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { if (threadSafetyCheckIsSmartPointer(S, RT)) return true; - // Check if the record itself has a capability. - RecordDecl *RD = RT->getDecl(); - if (RD->hasAttr<CapabilityAttr>()) - return true; - - // Else check if any base classes have a capability. - if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { - CXXBasePaths BPaths(false, false); - if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &) { - const auto *Type = BS->getType()->getAs<RecordType>(); - return Type->getDecl()->hasAttr<CapabilityAttr>(); - }, BPaths)) - return true; - } - return false; + return checkRecordDeclForAttr<CapabilityAttr>(RT->getDecl()); } static bool checkTypedefTypeForCapability(QualType Ty) { @@ -563,8 +572,27 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) { static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args, - int Sidx = 0, + unsigned Sidx = 0, bool ParamIdxOk = false) { + if (Sidx == AL.getNumArgs()) { + // If we don't have any capability arguments, the attribute implicitly + // refers to 'this'. So we need to make sure that 'this' exists, i.e. we're + // a non-static method, and that the class is a (scoped) capability. + const auto *MD = dyn_cast<const CXXMethodDecl>(D); + if (MD && !MD->isStatic()) { + const CXXRecordDecl *RD = MD->getParent(); + // FIXME -- need to check this again on template instantiation + if (!checkRecordDeclForAttr<CapabilityAttr>(RD) && + !checkRecordDeclForAttr<ScopedLockableAttr>(RD)) + S.Diag(AL.getLoc(), + diag::warn_thread_attribute_not_on_capability_member) + << AL << MD->getParent(); + } else { + S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_non_static_member) + << AL; + } + } + for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) { Expr *ArgExp = AL.getArgAsExpr(Idx); |

