r310403 - Thread Safety Analysis: warn on nonsensical attributes.
NAKAMURA Takumi via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 11 00:36:19 PDT 2017
It causes failure in check-libcxx with just-built clang.
http://bb.pgr.jp/builders/bootstrap-clang-libcxx-lld-i686-linux/builds/758
On Wed, Aug 9, 2017 at 4:45 AM Josh Gao via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: jmgao
> Date: Tue Aug 8 12:44:35 2017
> New Revision: 310403
>
> URL: http://llvm.org/viewvc/llvm-project?rev=310403&view=rev
> Log:
> Thread Safety Analysis: warn on nonsensical attributes.
>
> Add warnings in cases where an implicit `this` argument is expected to
> attributes because either `this` doesn't exist because the attribute is
> on a free function, or because `this` is on a type that doesn't have a
> corresponding capability/lockable/scoped_lockable attribute.
>
> Reviewers: delesley, aaron.ballman
>
> Differential Revision: https://reviews.llvm.org/D36237
>
> Modified:
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> cfe/trunk/test/Sema/attr-capabilities.c
> cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=310403&r1=310402&r2=310403&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Aug 8
> 12:44:35 2017
> @@ -2932,6 +2932,16 @@ def warn_thread_attribute_decl_not_locka
> "%0 attribute can only be applied in a context annotated "
> "with 'capability(\"mutex\")' attribute">,
> InGroup<ThreadSafetyAttributes>, DefaultIgnore;
> +def warn_thread_attribute_noargs_not_lockable : Warning<
> + "%0 attribute requires type annotated with 'capability' attribute; "
> + "type here is %1">,
> + InGroup<ThreadSafetyAttributes>, DefaultIgnore;
> +def warn_thread_attribute_noargs_not_method : Warning<
> + "%0 attribute without arguments can only be applied to a method of a
> class">,
> + InGroup<ThreadSafetyAttributes>, DefaultIgnore;
> +def warn_thread_attribute_noargs_static_method : Warning<
> + "%0 attribute without arguments cannot be applied to a static method">,
> + InGroup<ThreadSafetyAttributes>, DefaultIgnore;
> def warn_thread_attribute_decl_not_pointer : Warning<
> "%0 only applies to pointer types; type here is %1">,
> InGroup<ThreadSafetyAttributes>, DefaultIgnore;
>
> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=310403&r1=310402&r2=310403&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Aug 8 12:44:35 2017
> @@ -480,7 +480,7 @@ static const RecordType *getRecordType(Q
> return nullptr;
> }
>
> -static bool checkRecordTypeForCapability(Sema &S, QualType Ty) {
> +template <typename T> static bool checkRecordTypeForAttr(Sema &S,
> QualType Ty) {
> const RecordType *RT = getRecordType(Ty);
>
> if (!RT)
> @@ -497,7 +497,7 @@ static bool checkRecordTypeForCapability
>
> // Check if the record itself has a capability.
> RecordDecl *RD = RT->getDecl();
> - if (RD->hasAttr<CapabilityAttr>())
> + if (RD->hasAttr<T>())
> return true;
>
> // Else check if any base classes have a capability.
> @@ -505,14 +505,14 @@ static bool checkRecordTypeForCapability
> CXXBasePaths BPaths(false, false);
> if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &) {
> const auto *Type = BS->getType()->getAs<RecordType>();
> - return Type->getDecl()->hasAttr<CapabilityAttr>();
> + return Type->getDecl()->hasAttr<T>();
> }, BPaths))
> return true;
> }
> return false;
> }
>
> -static bool checkTypedefTypeForCapability(QualType Ty) {
> +template <typename T> static bool checkTypedefTypeForAttr(QualType Ty) {
> const auto *TD = Ty->getAs<TypedefType>();
> if (!TD)
> return false;
> @@ -521,19 +521,27 @@ static bool checkTypedefTypeForCapabilit
> if (!TN)
> return false;
>
> - return TN->hasAttr<CapabilityAttr>();
> + return TN->hasAttr<T>();
> }
>
> -static bool typeHasCapability(Sema &S, QualType Ty) {
> - if (checkTypedefTypeForCapability(Ty))
> +template <typename T> static bool typeHasAttr(Sema &S, QualType Ty) {
> + if (checkTypedefTypeForAttr<T>(Ty))
> return true;
>
> - if (checkRecordTypeForCapability(S, Ty))
> + if (checkRecordTypeForAttr<T>(S, Ty))
> return true;
>
> return false;
> }
>
> +static bool typeHasCapability(Sema &S, QualType Ty) {
> + return typeHasAttr<CapabilityAttr>(S, Ty);
> +}
> +
> +static bool typeHasScopedLockable(Sema &S, QualType Ty) {
> + return typeHasAttr<ScopedLockableAttr>(S, Ty);
> +}
> +
> static bool isCapabilityExpr(Sema &S, const Expr *Ex) {
> // Capability expressions are simple expressions involving the boolean
> logic
> // operators &&, || or !, a simple DeclRefExpr, CastExpr or a
> ParenExpr. Once
> @@ -570,6 +578,8 @@ static void checkAttrArgsAreCapabilityOb
> SmallVectorImpl<Expr *> &Args,
> int Sidx = 0,
> bool ParamIdxOk = false) {
> + bool TriedParam = false;
> +
> for (unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
> Expr *ArgExp = Attr.getArgAsExpr(Idx);
>
> @@ -610,15 +620,18 @@ static void checkAttrArgsAreCapabilityOb
> const RecordType *RT = getRecordType(ArgTy);
>
> // Now check if we index into a record type function param.
> - if(!RT && ParamIdxOk) {
> + if (!RT && ParamIdxOk) {
> FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
> IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp);
> - if(FD && IL) {
> + if (FD && IL) {
> + // Don't emit free function warnings if an index was given.
> + TriedParam = true;
> +
> unsigned int NumParams = FD->getNumParams();
> llvm::APInt ArgValue = IL->getValue();
> uint64_t ParamIdxFromOne = ArgValue.getZExtValue();
> uint64_t ParamIdxFromZero = ParamIdxFromOne - 1;
> - if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams)
> {
> + if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne >
> NumParams) {
> S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range)
> << Attr.getName() << Idx + 1 << NumParams;
> continue;
> @@ -637,6 +650,28 @@ static void checkAttrArgsAreCapabilityOb
>
> Args.push_back(ArgExp);
> }
> +
> + // If we don't have any lockable arguments, verify that we're an
> instance
> + // method on a lockable type.
> + if (Args.empty() && !TriedParam) {
> + if (auto *MD = dyn_cast<CXXMethodDecl>(D)) {
> + if (MD->isStatic()) {
> + S.Diag(Attr.getLoc(),
> diag::warn_thread_attribute_noargs_static_method)
> + << Attr.getName();
> + return;
> + }
> +
> + QualType ThisType = MD->getThisType(MD->getASTContext());
> + if (!typeHasCapability(S, ThisType) &&
> + !typeHasScopedLockable(S, ThisType)) {
> + S.Diag(Attr.getLoc(),
> diag::warn_thread_attribute_noargs_not_lockable)
> + << Attr.getName() << ThisType;
> + }
> + } else {
> + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_noargs_not_method)
> + << Attr.getName();
> + }
> + }
> }
>
>
> //===----------------------------------------------------------------------===//
>
> Modified: cfe/trunk/test/Sema/attr-capabilities.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-capabilities.c?rev=310403&r1=310402&r2=310403&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Sema/attr-capabilities.c (original)
> +++ cfe/trunk/test/Sema/attr-capabilities.c Tue Aug 8 12:44:35 2017
> @@ -37,15 +37,25 @@ void Func6(void) __attribute__((requires
> void Func7(void) __attribute__((assert_capability(GUI))) {}
> void Func8(void) __attribute__((assert_shared_capability(GUI))) {}
>
> +void Func9(void) __attribute__((assert_capability())) {} //
> expected-warning {{'assert_capability' attribute without arguments can only
> be applied to a method of a class}}
> +void Func10(void) __attribute__((assert_shared_capability())) {} //
> expected-warning {{'assert_shared_capability' attribute without arguments
> can only be applied to a method of a class}}
> +
> void Func11(void) __attribute__((acquire_capability(GUI))) {}
> void Func12(void) __attribute__((acquire_shared_capability(GUI))) {}
>
> +void Func13(void) __attribute__((acquire_capability())) {} //
> expected-warning {{'acquire_capability' attribute without arguments can
> only be applied to a method of a class}}
> +void Func14(void) __attribute__((acquire_shared_capability())) {} //
> expected-warning {{'acquire_shared_capability' attribute without arguments
> can only be applied to a method of a class}}
> +
> void Func15(void) __attribute__((release_capability(GUI))) {}
> void Func16(void) __attribute__((release_shared_capability(GUI))) {}
> void Func17(void) __attribute__((release_generic_capability(GUI))) {}
>
> -void Func21(void) __attribute__((try_acquire_capability(1))) {}
> -void Func22(void) __attribute__((try_acquire_shared_capability(1))) {}
> +void Func18(void) __attribute__((release_capability())) {} //
> expected-warning {{'release_capability' attribute without arguments can
> only be applied to a method of a class}}
> +void Func19(void) __attribute__((release_shared_capability())) {} //
> expected-warning {{'release_shared_capability' attribute without arguments
> can only be applied to a method of a class}}
> +void Func20(void) __attribute__((release_generic_capability())) {} //
> expected-warning {{'release_generic_capability' attribute without arguments
> can only be applied to a method of a class}}
> +
> +void Func21(void) __attribute__((try_acquire_capability(1))) {} //
> expected-warning {{'try_acquire_capability' attribute without arguments can
> only be applied to a method of a class}}
> +void Func22(void) __attribute__((try_acquire_shared_capability(1))) {} //
> expected-warning {{'try_acquire_shared_capability' attribute without
> arguments can only be applied to a method of a class}}
>
> void Func23(void) __attribute__((try_acquire_capability(1, GUI))) {}
> void Func24(void) __attribute__((try_acquire_shared_capability(1, GUI)))
> {}
>
> Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp?rev=310403&r1=310402&r2=310403&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp (original)
> +++ cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp Tue Aug 8
> 12:44:35 2017
> @@ -571,11 +571,11 @@ UnlockableMu ab_var_arg_bad_5 ACQUIRED_B
>
> // takes zero or more arguments, all locks (vars/fields)
>
> -void elf_function() EXCLUSIVE_LOCK_FUNCTION();
> +void elf_function() EXCLUSIVE_LOCK_FUNCTION(); // expected-warning
> {{'exclusive_lock_function' attribute without arguments can only be applied
> to a method of a class}}
>
> void elf_function_args() EXCLUSIVE_LOCK_FUNCTION(mu1, mu2);
>
> -int elf_testfn(int y) EXCLUSIVE_LOCK_FUNCTION();
> +int elf_testfn(int y) EXCLUSIVE_LOCK_FUNCTION(); // expected-warning
> {{'exclusive_lock_function' attribute without arguments can only be applied
> to a method of a class}}
>
> int elf_testfn(int y) {
> int x EXCLUSIVE_LOCK_FUNCTION() = y; // \
> @@ -590,7 +590,7 @@ class ElfFoo {
> private:
> int test_field EXCLUSIVE_LOCK_FUNCTION(); // \
> // expected-warning {{'exclusive_lock_function' attribute only
> applies to functions}}
> - void test_method() EXCLUSIVE_LOCK_FUNCTION();
> + void test_method() EXCLUSIVE_LOCK_FUNCTION(); // expected-warning
> {{'exclusive_lock_function' attribute requires type annotated with
> 'capability' attribute; type here is 'ElfFoo *'}}
> };
>
> class EXCLUSIVE_LOCK_FUNCTION() ElfTestClass { // \
> @@ -643,11 +643,11 @@ int elf_function_bad_7() EXCLUSIVE_LOCK_
>
> // takes zero or more arguments, all locks (vars/fields)
>
> -void slf_function() SHARED_LOCK_FUNCTION();
> +void slf_function() SHARED_LOCK_FUNCTION(); // expected-warning
> {{'shared_lock_function' attribute without arguments can only be applied to
> a method of a class}}
>
> void slf_function_args() SHARED_LOCK_FUNCTION(mu1, mu2);
>
> -int slf_testfn(int y) SHARED_LOCK_FUNCTION();
> +int slf_testfn(int y) SHARED_LOCK_FUNCTION(); // expected-warning
> {{'shared_lock_function' attribute without arguments can only be applied to
> a method of a class}}
>
> int slf_testfn(int y) {
> int x SHARED_LOCK_FUNCTION() = y; // \
> @@ -665,7 +665,8 @@ class SlfFoo {
> private:
> int test_field SHARED_LOCK_FUNCTION(); // \
> // expected-warning {{'shared_lock_function' attribute only applies
> to functions}}
> - void test_method() SHARED_LOCK_FUNCTION();
> + void test_method() SHARED_LOCK_FUNCTION(); // \
> + // expected-warning {{'shared_lock_function' attribute requires type
> annotated with 'capability' attribute; type here is 'SlfFoo *'}}
> };
>
> class SHARED_LOCK_FUNCTION() SlfTestClass { // \
> @@ -716,14 +717,16 @@ int slf_function_bad_7() SHARED_LOCK_FUN
> // takes a mandatory boolean or integer argument specifying the retval
> // plus an optional list of locks (vars/fields)
>
> -void etf_function() __attribute__((exclusive_trylock_function)); // \
> - // expected-error {{'exclusive_trylock_function' attribute takes at
> least 1 argument}}
> +void etf_function() __attribute__((exclusive_trylock_function)); // \
> + // expected-error {{'exclusive_trylock_function' attribute takes at
> least 1 argument}} \
>
> void etf_function_args() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu2);
>
> -void etf_function_arg() EXCLUSIVE_TRYLOCK_FUNCTION(1);
> +void etf_function_arg() EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
> + // expected-warning {{'exclusive_trylock_function' attribute without
> arguments can only be applied to a method of a class}}
>
> -int etf_testfn(int y) EXCLUSIVE_TRYLOCK_FUNCTION(1);
> +int etf_testfn(int y) EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
> + // expected-warning {{'exclusive_trylock_function' attribute without
> arguments can only be applied to a method of a class}}
>
> int etf_testfn(int y) {
> int x EXCLUSIVE_TRYLOCK_FUNCTION(1) = y; // \
> @@ -732,13 +735,14 @@ int etf_testfn(int y) {
> };
>
> int etf_test_var EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
> - // expected-warning {{'exclusive_trylock_function' attribute only
> applies to functions}}
> + // expected-warning {{'exclusive_trylock_function' attribute only
> applies to functions}} \
>
> class EtfFoo {
> private:
> int test_field EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
> // expected-warning {{'exclusive_trylock_function' attribute only
> applies to functions}}
> - void test_method() EXCLUSIVE_TRYLOCK_FUNCTION(1);
> + void test_method() EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
> + // expected-warning {{'exclusive_trylock_function' attribute requires
> type annotated with 'capability' attribute; type here is 'EtfFoo *'}}
> };
>
> class EXCLUSIVE_TRYLOCK_FUNCTION(1) EtfTestClass { // \
> @@ -759,7 +763,8 @@ int etf_function_5() EXCLUSIVE_TRYLOCK_F
> int etf_function_6() EXCLUSIVE_TRYLOCK_FUNCTION(1, muRef);
> int etf_function_7() EXCLUSIVE_TRYLOCK_FUNCTION(1,
> muDoubleWrapper.getWrapper()->getMu());
> int etf_functetfn_8() EXCLUSIVE_TRYLOCK_FUNCTION(1, muPointer);
> -int etf_function_9() EXCLUSIVE_TRYLOCK_FUNCTION(true);
> +int etf_function_9() EXCLUSIVE_TRYLOCK_FUNCTION(true); // \
> + // expected-warning {{'exclusive_trylock_function' attribute without
> arguments can only be applied to a method of a class}}
>
>
> // illegal attribute arguments
> @@ -794,9 +799,11 @@ void stf_function() __attribute__((share
>
> void stf_function_args() SHARED_TRYLOCK_FUNCTION(1, mu2);
>
> -void stf_function_arg() SHARED_TRYLOCK_FUNCTION(1);
> +void stf_function_arg() SHARED_TRYLOCK_FUNCTION(1); // \
> + // expected-warning {{'shared_trylock_function' attribute without
> arguments can only be applied to a method of a class}}
>
> -int stf_testfn(int y) SHARED_TRYLOCK_FUNCTION(1);
> +int stf_testfn(int y) SHARED_TRYLOCK_FUNCTION(1); // \
> + // expected-warning {{'shared_trylock_function' attribute without
> arguments can only be applied to a method of a class}}
>
> int stf_testfn(int y) {
> int x SHARED_TRYLOCK_FUNCTION(1) = y; // \
> @@ -815,7 +822,8 @@ class StfFoo {
> private:
> int test_field SHARED_TRYLOCK_FUNCTION(1); // \
> // expected-warning {{'shared_trylock_function' attribute only
> applies to functions}}
> - void test_method() SHARED_TRYLOCK_FUNCTION(1);
> + void test_method() SHARED_TRYLOCK_FUNCTION(1); // \
> + // expected-warning {{'shared_trylock_function' attribute requires
> type annotated with 'capability' attribute; type here is 'StfFoo *'}}
> };
>
> class SHARED_TRYLOCK_FUNCTION(1) StfTestClass { // \
> @@ -833,7 +841,8 @@ int stf_function_5() SHARED_TRYLOCK_FUNC
> int stf_function_6() SHARED_TRYLOCK_FUNCTION(1, muRef);
> int stf_function_7() SHARED_TRYLOCK_FUNCTION(1,
> muDoubleWrapper.getWrapper()->getMu());
> int stf_function_8() SHARED_TRYLOCK_FUNCTION(1, muPointer);
> -int stf_function_9() SHARED_TRYLOCK_FUNCTION(true);
> +int stf_function_9() SHARED_TRYLOCK_FUNCTION(true); // \
> + // expected-warning {{'shared_trylock_function' attribute without
> arguments can only be applied to a method of a class}}
>
>
> // illegal attribute arguments
> @@ -862,11 +871,14 @@ int stf_function_bad_6() SHARED_TRYLOCK_
>
> // takes zero or more arguments, all locks (vars/fields)
>
> -void uf_function() UNLOCK_FUNCTION();
> +void uf_function() UNLOCK_FUNCTION(); // \
> + // expected-warning {{'unlock_function' attribute without arguments can
> only be applied to a method of a class}}
> +
>
> void uf_function_args() UNLOCK_FUNCTION(mu1, mu2);
>
> -int uf_testfn(int y) UNLOCK_FUNCTION();
> +int uf_testfn(int y) UNLOCK_FUNCTION(); //\
> + // expected-warning {{'unlock_function' attribute without arguments can
> only be applied to a method of a class}}
>
> int uf_testfn(int y) {
> int x UNLOCK_FUNCTION() = y; // \
> @@ -881,7 +893,8 @@ class UfFoo {
> private:
> int test_field UNLOCK_FUNCTION(); // \
> // expected-warning {{'unlock_function' attribute only applies to
> functions}}
> - void test_method() UNLOCK_FUNCTION();
> + void test_method() UNLOCK_FUNCTION(); // \
> + // expected-warning {{'unlock_function' attribute requires type
> annotated with 'capability' attribute; type here is 'UfFoo *'}}
> };
>
> class NO_THREAD_SAFETY_ANALYSIS UfTestClass { // \
> @@ -1524,4 +1537,4 @@ namespace CRASH_POST_R301735 {
> Mutex mu_;
> };
> }
> -#endif
> \ No newline at end of file
> +#endif
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170811/599ec691/attachment-0001.html>
More information about the cfe-commits
mailing list