From 63fa667c68740ef3430bf30876550b770254ad28 Mon Sep 17 00:00:00 2001 From: Caitlin Sadowski Date: Thu, 28 Jul 2011 20:12:35 +0000 Subject: [PATCH] Added basic parsing for all remaining attributes, thread safety analysis. This includes checking that the attributes are applied in the correct contexts and with the correct number of arguments. llvm-svn: 136383 --- clang/docs/LanguageExtensions.html | 149 ++++- clang/include/clang/Basic/Attr.td | 52 ++ .../clang/Basic/DiagnosticSemaKinds.td | 2 + clang/include/clang/Sema/AttributeList.h | 13 + clang/lib/Sema/AttributeList.cpp | 13 + clang/lib/Sema/SemaDeclAttr.cpp | 230 ++++++- clang/test/SemaCXX/warn-thread-safety.cpp | 575 ++++++++++++++++++ 7 files changed, 1015 insertions(+), 19 deletions(-) diff --git a/clang/docs/LanguageExtensions.html b/clang/docs/LanguageExtensions.html index 37ea0396e0e1..804080d32668 100644 --- a/clang/docs/LanguageExtensions.html +++ b/clang/docs/LanguageExtensions.html @@ -89,11 +89,24 @@
  • Static Analysis-Specific Extensions
  • Thread Safety Annotation Checking
  • @@ -1109,15 +1122,12 @@ For more details, see the GCC implementation.

    -

    guarded_var

    +

    no_thread_safety_analysis

    -

    Use __attribute__((guarded_var)) on a variable declaration to -specify that the variable must be accessed while holding some lock.

    - -

    pt_guarded_var

    - -

    Use __attribute__((pt_guarded_var)) on a pointer declaration to -specify that the pointer must be dereferenced while holding some lock.

    +

    Use __attribute__((no_thread_safety_analysis)) on a function +declaration to specify that the thread safety analysis should not be run on that +function. This attribute provides an escape hatch (e.g. for situations when it +is difficult to annotate the locking policy).

    lockable

    @@ -1133,12 +1143,119 @@ the lock upon construction and release it upon going out of scope. This annotation is primarily used to check consistency.

    -

    no_thread_safety_analysis

    +

    guarded_var

    -

    Use __attribute__((no_thread_safety_analysis)) on a function -declaration to specify that the thread safety analysis should not be run on that -function. This attribute provides an escape hatch (e.g. for situations when it -is difficult to annotate the locking policy).

    +

    Use __attribute__((guarded_var)) on a variable declaration to +specify that the variable must be accessed while holding some lock.

    + +

    pt_guarded_var

    + +

    Use __attribute__((pt_guarded_var)) on a pointer declaration to +specify that the pointer must be dereferenced while holding some lock.

    + +

    guarded_by(l)

    + +

    Use __attribute__((guarded_by(l))) on a variable declaration to +specify that the variable must be accessed while holding lock l.

    + +

    pt_guarded_by(l)

    + +

    Use __attribute__((pt_guarded_by(l))) on a pointer declaration to +specify that the pointer must be dereferenced while holding lock l.

    + +

    acquired_before(...)

    + +

    Use __attribute__((acquired_before(...))) on a declaration +of a lockable variable to specify that the lock must be acquired before all +attribute arguments. Arguments must be lockable type, and there must be at +least one argument.

    + +

    acquired_after(...)

    + +

    Use __attribute__((acquired_after(...))) on a declaration +of a lockable variable to specify that the lock must be acquired after all +attribute arguments. Arguments must be lockable type, and there must be at +least one argument.

    + +

    exclusive_lock_function(...)

    + +

    Use __attribute__((exclusive_lock_function(...))) on a function +declaration to specify that the function acquires all listed locks +exclusively. This attribute takes zero or more +arguments: either of lockable type or integers indexing into +function parameters of lockable type. If no arguments are given, the acquired +lock is implicitly this of the enclosing object.

    + +

    shared_lock_function(...)

    + +

    Use __attribute__((shared_lock_function(...))) on a function +declaration to specify that the function acquires all listed locks, although + the locks may be shared (e.g. read locks). +This attribute takes zero or more +arguments: either of lockable type or integers indexing into +function parameters of lockable type. If no arguments are given, the acquired +lock is implicitly this of the enclosing object.

    + +

    exclusive_trylock_function(...)

    + +

    Use __attribute__((exclusive_lock_function(...))) on a function +declaration to specify that the function will try (without blocking) to acquire +all listed locks exclusively. This attribute takes one or more +arguments. The first argument is an integer or boolean value specifying the +return value of a successful lock acquisition. The remaining arugments are +either of lockable type or integers indexing into +function parameters of lockable type. If only one argument is given, the +acquired lock is implicitly this of the enclosing object.

    + +

    shared_trylock_function(...)

    + +

    Use __attribute__((shared_lock_function(...))) on a function +declaration to specify that the function will try (without blocking) to acquire +all listed locks, although + the locks may be shared (e.g. read locks). +This attribute takes one or more +arguments. The first argument is an integer or boolean value specifying the +return value of a successful lock acquisition. The remaining arugments are +either of lockable type or integers indexing into +function parameters of lockable type. If only one argument is given, the +acquired lock is implicitly this of the enclosing object.

    + +

    unlock_function(...)

    + +

    Use __attribute__((unlock_function(...))) on a function +declaration to specify that the function release all listed locks. + This attribute takes zero or more +arguments: either of lockable type or integers indexing into +function parameters of lockable type. If no arguments are given, the acquired +lock is implicitly this of the enclosing object.

    + +

    lock_returned(l)

    + +

    Use __attribute__((lock_returned(l))) on a function +declaration to specify that the function returns lock l (l must be of lockable +type). This annotation is used +to aid in resolving lock expressions.

    + +

    locks_excluded(...)

    + +

    Use __attribute__((locks_excluded(...))) on a function declaration +to specify that the function must not be called with the listed locks. +Arguments must be lockable type, and there must be at +least one argument.

    + +

    exclusive_locks_required(...)

    + +

    Use __attribute__((exclusive_locks_required(...))) on a function +declaration to specify that the function must be called while holding the listed +exclusive locks. Arguments must be lockable type, and there must be at +least one argument.

    + +

    shared_locks_required(...)

    + +

    Use __attribute__((shared_locks_required(...))) on a function +declaration to specify that the function must be called while holding the listed +shared locks. Arguments must be lockable type, and there must be at +least one argument.

    diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 8f52a5b246f3..2b0ed3d66912 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -561,3 +561,55 @@ def ScopedLockable : InheritableAttr { def NoThreadSafetyAnalysis : InheritableAttr { let Spellings = ["no_thread_safety_analysis"]; } + +def GuardedBy : InheritableAttr { + let Spellings = ["guarded_by"]; +} + +def PtGuardedBy : InheritableAttr { + let Spellings = ["pt_guarded_by"]; +} + +def AcquiredAfter : InheritableAttr { + let Spellings = ["acquired_after"]; +} + +def AcquiredBefore : InheritableAttr { + let Spellings = ["acquired_before"]; +} + +def ExclusiveLockFunction : InheritableAttr { + let Spellings = ["exclusive_lock_function"]; +} + +def SharedLockFunction : InheritableAttr { + let Spellings = ["shared_lock_function"]; +} + +def ExclusiveTrylockFunction : InheritableAttr { + let Spellings = ["exclusive_trylock_function"]; +} + +def SharedTrylockFunction : InheritableAttr { + let Spellings = ["shared_trylock_function"]; +} + +def UnlockFunction : InheritableAttr { + let Spellings = ["unlock_function"]; +} + +def LockReturned : InheritableAttr { + let Spellings = ["lock_returned"]; +} + +def LocksExcluded : InheritableAttr { + let Spellings = ["locks_excluded"]; +} + +def ExclusiveLocksRequired : InheritableAttr { + let Spellings = ["exclusive_locks_required"]; +} + +def SharedLocksRequired : InheritableAttr { + let Spellings = ["shared_locks_required"]; +} diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 1bb24a46fc87..660528a2c146 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1128,6 +1128,8 @@ def err_attribute_wrong_number_arguments : Error< ":requires exactly %0 arguments}0">; def err_attribute_too_many_arguments : Error< "attribute takes no more than %0 argument%s0">; +def err_attribute_too_few_arguments : Error< + "attribute takes at least %0 argument%s0">; def err_iboutletcollection_type : Error< "invalid type %0 as argument of iboutletcollection attribute">; def err_iboutletcollection_object_type : Error< diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h index d741e89bc8f4..674e13a3dff7 100644 --- a/clang/include/clang/Sema/AttributeList.h +++ b/clang/include/clang/Sema/AttributeList.h @@ -152,6 +152,8 @@ private: public: enum Kind { // Please keep this list alphabetized. + AT_acquired_after, + AT_acquired_before, AT_address_space, AT_alias, AT_aligned, @@ -178,12 +180,16 @@ public: AT_device, AT_dllexport, AT_dllimport, + AT_exclusive_lock_function, + AT_exclusive_locks_required, + AT_exclusive_trylock_function, AT_ext_vector_type, AT_fastcall, AT_format, AT_format_arg, AT_global, AT_gnu_inline, + AT_guarded_by, AT_guarded_var, AT_host, AT_IBAction, // Clang-specific. @@ -191,7 +197,9 @@ public: AT_IBOutletCollection, // Clang-specific. AT_init_priority, AT_launch_bounds, + AT_lock_returned, AT_lockable, + AT_locks_excluded, AT_malloc, AT_may_alias, AT_mode, @@ -228,6 +236,7 @@ public: AT_packed, AT_pascal, AT_pcs, // ARM specific + AT_pt_guarded_by, AT_pt_guarded_var, AT_pure, AT_regparm, @@ -236,10 +245,14 @@ public: AT_section, AT_sentinel, AT_shared, + AT_shared_lock_function, + AT_shared_locks_required, + AT_shared_trylock_function, AT_stdcall, AT_thiscall, AT_transparent_union, AT_unavailable, + AT_unlock_function, AT_unused, AT_used, AT_uuid, diff --git a/clang/lib/Sema/AttributeList.cpp b/clang/lib/Sema/AttributeList.cpp index babf491b949a..d9f17b42da4b 100644 --- a/clang/lib/Sema/AttributeList.cpp +++ b/clang/lib/Sema/AttributeList.cpp @@ -215,5 +215,18 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("scoped_lockable", AT_scoped_lockable) .Case("lockable", AT_lockable) .Case("no_thread_safety_analysis", AT_no_thread_safety_analysis) + .Case("guarded_by", AT_guarded_by) + .Case("pt_guarded_by", AT_pt_guarded_by) + .Case("acquired_after", AT_acquired_after) + .Case("acquired_before", AT_acquired_before) + .Case("exclusive_lock_function", AT_exclusive_lock_function) + .Case("exclusive_locks_required", AT_exclusive_locks_required) + .Case("exclusive_trylock_function", AT_exclusive_trylock_function) + .Case("lock_returned", AT_lock_returned) + .Case("locks_excluded", AT_locks_excluded) + .Case("shared_lock_function", AT_shared_lock_function) + .Case("shared_locks_required", AT_shared_locks_required) + .Case("shared_trylock_function", AT_shared_trylock_function) + .Case("unlock_function", AT_unlock_function) .Default(UnknownAttribute); } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 694d38b4a1f9..0f02ed31df21 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -27,7 +27,7 @@ using namespace sema; /// These constants match the enumerated choices of /// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type. -enum { +enum AttributeDeclType { ExpectedFunction, ExpectedUnion, ExpectedVariableOrFunction, @@ -42,7 +42,8 @@ enum { ExpectedClassMember, ExpectedVariable, ExpectedMethod, - ExpectedVariableFunctionOrLabel + ExpectedVariableFunctionOrLabel, + ExpectedFieldOrGlobalVar }; //===----------------------------------------------------------------------===// @@ -204,6 +205,34 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, return true; } +/// +/// \brief Check the total number of argumenation, whether parsed by clang +/// as arguments or parameters. Outputs a warning. +/// \return false if the number of argumenation units does not match expectation +/// +static bool checkAttributeNumArgsPlusParams(Sema &S, const AttributeList &Attr, + unsigned int Num, + bool moreok = false) { + unsigned int numArgsPlusParams = 0; + + if (Attr.getParameterName()) + numArgsPlusParams++; + + numArgsPlusParams += Attr.getNumArgs(); + + if (moreok && numArgsPlusParams < Num) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num; + return false; + } + + if (!moreok && numArgsPlusParams != Num) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Num; + return false; + } + + return true; +} + /// /// \brief Check if passed in Decl is a field or potentially shared global var /// \return true if the Decl is a field or potentially shared global variable @@ -225,7 +254,7 @@ static bool mayBeSharedVariable(Decl *D) { bool checkIsPointer(Sema & S, Decl * D, const AttributeList & Attr) { if(ValueDecl * vd = dyn_cast (D)) { QualType QT = vd->getType(); - if(QT->isAnyPointerType()){ + if(QT->isAnyPointerType()) { return true; } S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type) @@ -268,6 +297,30 @@ static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr, D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getLoc(), S.Context)); } +static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool pointer = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgsPlusParams(S, Attr, 1)) + return; + + // D must be either a member field or global (potentially shared) variable. + if (!mayBeSharedVariable(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 15; /*fields and global vars*/; + return; + } + + if (pointer && !checkIsPointer(S, D, Attr)) + return; + + if (pointer) + D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getLoc(), S.Context)); + else + D->addAttr(::new (S.Context) GuardedByAttr(Attr.getLoc(), S.Context)); +} + + static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr, bool scoped = false) { assert(!Attr.isInvalid()); @@ -304,6 +357,138 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D, S.Context)); } +static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool before) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true)) + return; + + // D must be either a member field or global (potentially shared) variable. + if (!mayBeSharedVariable(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 15; /*fields and global vars*/; + return; + } + + if (before) + D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getLoc(), S.Context)); + else + D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getLoc(), S.Context)); +} + +static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + // zero or more arguments ok + + if (!isFunction(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getLoc(), + S.Context)); + else + D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getLoc(), + S.Context)); +} + +static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true)) + return; + + if (!isFunction(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getLoc(), + S.Context)); + else + D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getLoc(), + S.Context)); + +} + +static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true)) + return; + + if (!isFunction(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getLoc(), + S.Context)); + else + D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getLoc(), + S.Context)); +} + + +static void handleUnlockFunAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + // zero or more arguments ok + + if (!isFunction(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getLoc(), S.Context)); +} + +static void handleLockReturnedAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgsPlusParams(S, Attr, 1)) + return; + + if (!isFunction(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getLoc(), S.Context)); +} + +static void handleLocksExcludedAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true)) + return; + + if (!isFunction(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getLoc(), S.Context)); +} + + static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr) { TypedefNameDecl *tDecl = dyn_cast(D); @@ -3180,6 +3365,45 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_lockable: handleLockableAttr(S, D, Attr); break; + case AttributeList::AT_guarded_by: + handleGuardedByAttr(S, D, Attr); + break; + case AttributeList::AT_pt_guarded_by: + handleGuardedByAttr(S, D, Attr, /*pointer = */true); + break; + case AttributeList::AT_exclusive_lock_function: + handleLockFunAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_exclusive_locks_required: + handleLocksRequiredAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_exclusive_trylock_function: + handleTrylockFunAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_lock_returned: + handleLockReturnedAttr(S, D, Attr); + break; + case AttributeList::AT_locks_excluded: + handleLocksExcludedAttr(S, D, Attr); + break; + case AttributeList::AT_shared_lock_function: + handleLockFunAttr(S, D, Attr); + break; + case AttributeList::AT_shared_locks_required: + handleLocksRequiredAttr(S, D, Attr); + break; + case AttributeList::AT_shared_trylock_function: + handleTrylockFunAttr(S, D, Attr); + break; + case AttributeList::AT_unlock_function: + handleUnlockFunAttr(S, D, Attr); + break; + case AttributeList::AT_acquired_before: + handleAcquireOrderAttr(S, D, Attr, /*before = */true); + break; + case AttributeList::AT_acquired_after: + handleAcquireOrderAttr(S, D, Attr, /*before = */false); + break; default: // Ask target about the attribute. diff --git a/clang/test/SemaCXX/warn-thread-safety.cpp b/clang/test/SemaCXX/warn-thread-safety.cpp index 39a3fa2e4de1..4958d2ed0fa0 100644 --- a/clang/test/SemaCXX/warn-thread-safety.cpp +++ b/clang/test/SemaCXX/warn-thread-safety.cpp @@ -1,5 +1,16 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s + +/** + * Helper fields + */ + +class __attribute__((lockable)) Mu { +}; + +Mu mu1; +Mu mu2; + /*********************************** * No Thread Safety Analysis (noanal) ***********************************/ @@ -202,3 +213,567 @@ class SLFoo { void sl_function_params(int lvar __attribute__((scoped_lockable))); // \ expected-warning {{'scoped_lockable' attribute only applies to classes}} + + +/*********************************** + * Guarded By Attribute (gb) + ***********************************/ + +// FIXME: Would we like this attribute to take more than 1 arg? + +#if !__has_attribute(guarded_by) +#error "Should support guarded_by attribute" +#endif + +//1. Check applied to the right types & argument number + +int gb_var_arg __attribute__((guarded_by(mu1))); + +int gb_var_args __attribute__((guarded_by(mu1, mu2))); // \ + expected-error {{attribute takes one argument}} + +int gb_var_noargs __attribute__((guarded_by)); // \ + expected-error {{attribute takes one argument}} + +class GBFoo { + private: + int gb_field_noargs __attribute__((guarded_by)); // \ + expected-error {{attribute takes one argument}} + int gb_field_args __attribute__((guarded_by(mu1))); +}; + +class __attribute__((guarded_by(mu1))) GB { // \ + expected-warning {{'guarded_by' attribute only applies to fields and global variables}} +}; + +void gb_function() __attribute__((guarded_by(mu1))); // \ + expected-warning {{'guarded_by' attribute only applies to fields and global variables}} + +void gb_function_params(int gv_lvar __attribute__((guarded_by(mu1)))); // \ + expected-warning {{'guarded_by' attribute only applies to fields and global variables}} + +int gb_testfn(int y){ + int x __attribute__((guarded_by(mu1))) = y; // \ + expected-warning {{'guarded_by' attribute only applies to fields and global variables}} + return x; +} + +//2.Deal with argument parsing: +// grab token stream parsing from C++0x branch +// possibly create new, more permissive category for gcc attributes + +//foo +//foo.bar +//foo.bar->baz +//foo.bar()->baz()->a +//&foo +//*foo + +//3. +// Thread Safety analysis tests + + +/*********************************** + * Pt Guarded By Attribute (pgb) + ***********************************/ + +#if !__has_attribute(pt_guarded_by) +#error "Should support pt_guarded_by attribute" +#endif + +//1. Check applied to the right types & argument number + +int *pgb_var_noargs __attribute__((pt_guarded_by)); // \ + expected-error {{attribute takes one argument}} + +int *pgb_ptr_var_arg __attribute__((pt_guarded_by(mu1))); + +int *pgb_ptr_var_args __attribute__((guarded_by(mu1, mu2))); // \ + expected-error {{attribute takes one argument}} + +int pgb_var_args __attribute__((pt_guarded_by(mu1))); // \ + expected-warning {{'pt_guarded_by' only applies to pointer types; type here is 'int'}} + +class PGBFoo { + private: + int *pgb_field_noargs __attribute__((pt_guarded_by)); // \ + expected-error {{attribute takes one argument}} + int *pgb_field_args __attribute__((pt_guarded_by(mu1))); +}; + +class __attribute__((pt_guarded_by(mu1))) PGB { // \ + expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}} +}; + +void pgb_function() __attribute__((pt_guarded_by(mu1))); // \ + expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}} + +void pgb_function_params(int gv_lvar __attribute__((pt_guarded_by(mu1)))); // \ + expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}} + +void pgb_testfn(int y){ + int *x __attribute__((pt_guarded_by(mu1))) = new int(0); // \ + expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}} + delete x; +} + +/*********************************** + * Acquired After (aa) + ***********************************/ + +// FIXME: Would we like this attribute to take more than 1 arg? +// FIXME: What about pointers to locks? + +#if !__has_attribute(acquired_after) +#error "Should support acquired_after attribute" +#endif + +Mu mu_aa __attribute__((acquired_after(mu1))); + +Mu aa_var_noargs __attribute__((acquired_after)); // \ + expected-error {{attribute takes at least 1 argument}} + +class AAFoo { + private: + Mu aa_field_noargs __attribute__((acquired_after)); // \ + expected-error {{attribute takes at least 1 argument}} + Mu aa_field_args __attribute__((acquired_after(mu1))); +}; + +class __attribute__((acquired_after(mu1))) AA { // \ + expected-warning {{'acquired_after' attribute only applies to fields and global variables}} +}; + +void aa_function() __attribute__((acquired_after(mu1))); // \ + expected-warning {{'acquired_after' attribute only applies to fields and global variables}} + +void aa_function_params(int gv_lvar __attribute__((acquired_after(mu1)))); // \ + expected-warning {{'acquired_after' attribute only applies to fields and global variables}} + +void aa_testfn(int y){ + Mu x __attribute__((acquired_after(mu1))) = Mu(); // \ + expected-warning {{'acquired_after' attribute only applies to fields and global variables}} +} + +// Note: illegal int aa_int __attribute__((acquired_after(mu1))) will +// be taken care of by warnings that aa__int is not lockable. + + +/*********************************** + * Acquired Before (ab) + ***********************************/ + +#if !__has_attribute(acquired_before) +#error "Should support acquired_before attribute" +#endif + +Mu mu_ab __attribute__((acquired_before(mu1))); + +Mu ab_var_noargs __attribute__((acquired_before)); // \ + expected-error {{attribute takes at least 1 argument}} + +class ABFoo { + private: + Mu ab_field_noargs __attribute__((acquired_before)); // \ + expected-error {{attribute takes at least 1 argument}} + Mu ab_field_args __attribute__((acquired_before(mu1))); +}; + +class __attribute__((acquired_before(mu1))) AB { // \ + expected-warning {{'acquired_before' attribute only applies to fields and global variables}} +}; + +void ab_function() __attribute__((acquired_before(mu1))); // \ + expected-warning {{'acquired_before' attribute only applies to fields and global variables}} + +void ab_function_params(int gv_lvar __attribute__((acquired_before(mu1)))); // \ + expected-warning {{'acquired_before' attribute only applies to fields and global variables}} + +void ab_testfn(int y){ + Mu x __attribute__((acquired_before(mu1))) = Mu(); // \ + expected-warning {{'acquired_before' attribute only applies to fields and global variables}} +} + +// Note: illegal int ab_int __attribute__((acquired_before(mu1))) will +// be taken care of by warnings that ab__int is not lockable. + +/*********************************** + * Exclusive Lock Function (elf) + ***********************************/ + +#if !__has_attribute(exclusive_lock_function) +#error "Should support exclusive_lock_function attribute" +#endif + +// takes zero or more arguments, all locks (vars/fields) + +void elf_function() __attribute__((exclusive_lock_function)); + +void elf_function_args() __attribute__((exclusive_lock_function(mu1, mu2))); + +int elf_testfn(int y) __attribute__((exclusive_lock_function)); + +int elf_testfn(int y) { + int x __attribute__((exclusive_lock_function)) = y; // \ + expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}} + return x; +}; + +int elf_test_var __attribute__((exclusive_lock_function)); // \ + expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}} + +class ElfFoo { + private: + int test_field __attribute__((exclusive_lock_function)); // \ + expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}} + void test_method() __attribute__((exclusive_lock_function)); +}; + +class __attribute__((exclusive_lock_function)) ElfTestClass { // \ + expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}} +}; + +void elf_fun_params(int lvar __attribute__((exclusive_lock_function))); // \ + expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}} + + + +/*********************************** + * Shared Lock Function (slf) + ***********************************/ + +#if !__has_attribute(shared_lock_function) +#error "Should support shared_lock_function attribute" +#endif + +// takes zero or more arguments, all locks (vars/fields) + +void slf_function() __attribute__((shared_lock_function)); + +void slf_function_args() __attribute__((shared_lock_function(mu1, mu2))); + +int slf_testfn(int y) __attribute__((shared_lock_function)); + +int slf_testfn(int y) { + int x __attribute__((shared_lock_function)) = y; // \ + expected-warning {{'shared_lock_function' attribute only applies to functions and methods}} + return x; +}; + +int slf_test_var __attribute__((shared_lock_function)); // \ + expected-warning {{'shared_lock_function' attribute only applies to functions and methods}} + +void slf_fun_params(int lvar __attribute__((shared_lock_function))); // \ + expected-warning {{'shared_lock_function' attribute only applies to functions and methods}} + +class SlfFoo { + private: + int test_field __attribute__((shared_lock_function)); // \ + expected-warning {{'shared_lock_function' attribute only applies to functions and methods}} + void test_method() __attribute__((shared_lock_function)); +}; + +class __attribute__((shared_lock_function)) SlfTestClass { // \ + expected-warning {{'shared_lock_function' attribute only applies to functions and methods}} +}; + + +/*********************************** + * Exclusive TryLock Function (etf) + ***********************************/ + +#if !__has_attribute(exclusive_trylock_function) +#error "Should support exclusive_trylock_function attribute" +#endif + +// 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 {{attribute takes attribute takes at least 1 argument arguments}} + +void etf_function_args() __attribute__((exclusive_trylock_function(1, mu2))); + +void etf_function_arg() __attribute__((exclusive_trylock_function(1))); + +int etf_testfn(int y) __attribute__((exclusive_trylock_function(1))); + +int etf_testfn(int y) { + int x __attribute__((exclusive_trylock_function(1))) = y; // \ + expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}} + return x; +}; + +int etf_test_var __attribute__((exclusive_trylock_function(1))); // \ + expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}} + +class EtfFoo { + private: + int test_field __attribute__((exclusive_trylock_function(1))); // \ + expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}} + void test_method() __attribute__((exclusive_trylock_function(1))); +}; + +class __attribute__((exclusive_trylock_function(1))) EtfTestClass { // \ + expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}} +}; + +void etf_fun_params(int lvar __attribute__((exclusive_trylock_function(1)))); // \ + expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}} + + + +/*********************************** + * Shared TryLock Function (stf) + ***********************************/ + +#if !__has_attribute(shared_trylock_function) +#error "Should support shared_trylock_function attribute" +#endif + +// takes a mandatory boolean or integer argument specifying the retval +// plus an optional list of locks (vars/fields) + +void stf_function() __attribute__((shared_trylock_function)); // \ + expected-error {{attribute takes at least 1 argument}} + +void stf_function_args() __attribute__((shared_trylock_function(1, mu2))); + +void stf_function_arg() __attribute__((shared_trylock_function(1))); + +int stf_testfn(int y) __attribute__((shared_trylock_function(1))); + +int stf_testfn(int y) { + int x __attribute__((shared_trylock_function(1))) = y; // \ + expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}} + return x; +}; + +int stf_test_var __attribute__((shared_trylock_function(1))); // \ + expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}} + +void stf_fun_params(int lvar __attribute__((shared_trylock_function(1)))); // \ + expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}} + + +class StfFoo { + private: + int test_field __attribute__((shared_trylock_function(1))); // \ + expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}} + void test_method() __attribute__((shared_trylock_function(1))); +}; + +class __attribute__((shared_trylock_function(1))) StfTestClass { // \ + expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}} +}; + + +/*********************************** + * Unlock Function (uf) + ***********************************/ + +#if !__has_attribute(unlock_function) +#error "Should support unlock_function attribute" +#endif + +// takes zero or more arguments, all locks (vars/fields) + +void uf_function() __attribute__((unlock_function)); + +void uf_function_args() __attribute__((unlock_function(mu1, mu2))); + +int uf_testfn(int y) __attribute__((unlock_function)); + +int uf_testfn(int y) { + int x __attribute__((unlock_function)) = y; // \ + expected-warning {{'unlock_function' attribute only applies to functions and methods}} + return x; +}; + +int uf_test_var __attribute__((unlock_function)); // \ + expected-warning {{'unlock_function' attribute only applies to functions and methods}} + +class UfFoo { + private: + int test_field __attribute__((unlock_function)); // \ + expected-warning {{'unlock_function' attribute only applies to functions and methods}} + void test_method() __attribute__((unlock_function)); +}; + +class __attribute__((no_thread_safety_analysis)) UfTestClass { // \ + expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}} +}; + +void uf_fun_params(int lvar __attribute__((unlock_function))); // \ + expected-warning {{'unlock_function' attribute only applies to functions and methods}} + + +/*********************************** + * Lock Returned (lr) + ***********************************/ + +#if !__has_attribute(lock_returned) +#error "Should support lock_returned attribute" +#endif + +// Takes exactly one argument, a var/field + +void lr_function() __attribute__((lock_returned)); // \ + expected-error {{attribute takes one argument}} + +void lr_function_arg() __attribute__((lock_returned(mu1))); + +void lr_function_args() __attribute__((lock_returned(mu1, mu2))); // \ + expected-error {{attribute takes one argument}} + +int lr_testfn(int y) __attribute__((lock_returned(mu1))); + +int lr_testfn(int y) { + int x __attribute__((lock_returned(mu1))) = y; // \ + expected-warning {{'lock_returned' attribute only applies to functions and methods}} + return x; +}; + +int lr_test_var __attribute__((lock_returned(mu1))); // \ + expected-warning {{'lock_returned' attribute only applies to functions and methods}} + +void lr_fun_params(int lvar __attribute__((lock_returned(mu1)))); // \ + expected-warning {{'lock_returned' attribute only applies to functions and methods}} + +class LrFoo { + private: + int test_field __attribute__((lock_returned(mu1))); // \ + expected-warning {{'lock_returned' attribute only applies to functions and methods}} + void test_method() __attribute__((lock_returned(mu1))); +}; + +class __attribute__((lock_returned(mu1))) LrTestClass { // \ + expected-warning {{'lock_returned' attribute only applies to functions and methods}} +}; + +/*********************************** + * Locks Excluded (le) + ***********************************/ + +#if !__has_attribute(locks_excluded) +#error "Should support locks_excluded attribute" +#endif + +// takes one or more arguments, all locks (vars/fields) + +void le_function() __attribute__((locks_excluded)); // \ + expected-error {{attribute takes at least 1 argument}} + +void le_function_arg() __attribute__((locks_excluded(mu1))); + +void le_function_args() __attribute__((locks_excluded(mu1, mu2))); + +int le_testfn(int y) __attribute__((locks_excluded(mu1))); + +int le_testfn(int y) { + int x __attribute__((locks_excluded(mu1))) = y; // \ + expected-warning {{'locks_excluded' attribute only applies to functions and methods}} + return x; +}; + +int le_test_var __attribute__((locks_excluded(mu1))); // \ + expected-warning {{'locks_excluded' attribute only applies to functions and methods}} + +void le_fun_params(int lvar __attribute__((locks_excluded(mu1)))); // \ + expected-warning {{'locks_excluded' attribute only applies to functions and methods}} + +class LeFoo { + private: + int test_field __attribute__((locks_excluded(mu1))); // \ + expected-warning {{'locks_excluded' attribute only applies to functions and methods}} + void test_method() __attribute__((locks_excluded(mu1))); +}; + +class __attribute__((locks_excluded(mu1))) LeTestClass { // \ + expected-warning {{'locks_excluded' attribute only applies to functions and methods}} +}; + + +/*********************************** + * Exclusive Locks Required (elr) + ***********************************/ + +#if !__has_attribute(exclusive_locks_required) +#error "Should support exclusive_locks_required attribute" +#endif + +// takes one or more arguments, all locks (vars/fields) + +void elr_function() __attribute__((exclusive_locks_required)); // \ + expected-error {{attribute takes at least 1 argument}} + +void elr_function_arg() __attribute__((exclusive_locks_required(mu1))); + +void elr_function_args() __attribute__((exclusive_locks_required(mu1, mu2))); + +int elr_testfn(int y) __attribute__((exclusive_locks_required(mu1))); + +int elr_testfn(int y) { + int x __attribute__((exclusive_locks_required(mu1))) = y; // \ + expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}} + return x; +}; + +int elr_test_var __attribute__((exclusive_locks_required(mu1))); // \ + expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}} + +void elr_fun_params(int lvar __attribute__((exclusive_locks_required(mu1)))); // \ + expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}} + +class ElrFoo { + private: + int test_field __attribute__((exclusive_locks_required(mu1))); // \ + expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}} + void test_method() __attribute__((exclusive_locks_required(mu1))); +}; + +class __attribute__((exclusive_locks_required(mu1))) ElrTestClass { // \ + expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}} +}; + +/*********************************** + * Shared Locks Required (slr) + ***********************************/ + +#if !__has_attribute(shared_locks_required) +#error "Should support shared_locks_required attribute" +#endif + +// takes one or more arguments, all locks (vars/fields) + +void slr_function() __attribute__((shared_locks_required)); // \ + expected-error {{attribute takes at least 1 argument}} + +void slr_function_arg() __attribute__((shared_locks_required(mu1))); + +void slr_function_args() __attribute__((shared_locks_required(mu1, mu2))); + +int slr_testfn(int y) __attribute__((shared_locks_required(mu1))); + +int slr_testfn(int y) { + int x __attribute__((shared_locks_required(mu1))) = y; // \ + expected-warning {{'shared_locks_required' attribute only applies to functions and methods}} + return x; +}; + +int slr_test_var __attribute__((shared_locks_required(mu1))); // \ + expected-warning {{'shared_locks_required' attribute only applies to functions and methods}} + +void slr_fun_params(int lvar __attribute__((shared_locks_required(mu1)))); // \ + expected-warning {{'shared_locks_required' attribute only applies to functions and methods}} + +class SlrFoo { + private: + int test_field __attribute__((shared_locks_required(mu1))); // \ + expected-warning {{'shared_locks_required' attribute only applies to functions and methods}} + void test_method() __attribute__((shared_locks_required(mu1))); +}; + +class __attribute__((shared_locks_required(mu1))) SlrTestClass { // \ + expected-warning {{'shared_locks_required' attribute only applies to functions and methods}} +};