aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaitlin Sadowski <supertri@google.com>2011-07-28 20:12:35 +0000
committerCaitlin Sadowski <supertri@google.com>2011-07-28 20:12:35 +0000
commitdb33e14661c7a118a2d9a777ae69c0ecaa036e1e (patch)
tree3219ced3e13e9ecd7fd11db0acde3327bd622bff
parent1d05d424cb2be0e3f369ec27d8fb8be20e9ba5ae (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136383 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/LanguageExtensions.html149
-rw-r--r--include/clang/Basic/Attr.td52
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Sema/AttributeList.h13
-rw-r--r--lib/Sema/AttributeList.cpp13
-rw-r--r--lib/Sema/SemaDeclAttr.cpp230
-rw-r--r--test/SemaCXX/warn-thread-safety.cpp575
7 files changed, 1015 insertions, 19 deletions
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index 37ea0396e0..804080d326 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -89,11 +89,24 @@
<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
<li><a href="#threadsafety">Thread Safety Annotation Checking</a></li>
<ul>
+ <li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>
+ <li><a href="#ts_lockable"><tt>lockable</tt></a></li>
+ <li><a href="#ts_scopedlockable"><tt>scoped_lockable</tt></a></li>
<li><a href="#ts_guardedvar"><tt>guarded_var</tt></a></li>
<li><a href="#ts_ptguardedvar"><tt>pt_guarded_var</tt></a></li>
- <li><a href="#ts_lockable"><tt>lockable</tt></a></li>
- <li><a href="#ts_scopedlockable"><tt>scoped_lockable</tt></a></li>
- <li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>
+ <li><a href="#ts_guardedby"><tt>guarded_by(l)</tt></a></li>
+ <li><a href="#ts_ptguardedby"><tt>pt_guarded_by(l)</tt></a></li>
+ <li><a href="#ts_acquiredbefore"><tt>acquired_before(...)</tt></a></li>
+ <li><a href="#ts_acquiredafter"><tt>acquired_after(...)</tt></a></li>
+ <li><a href="#ts_elf"><tt>exclusive_lock_function(...)</tt></a></li>
+ <li><a href="#ts_slf"><tt>shared_lock_function(...)</tt></a></li>
+ <li><a href="#ts_etf"><tt>exclusive_trylock_function(...)</tt></a></li>
+ <li><a href="#ts_stf"><tt>shared_trylock_function(...)</tt></a></li>
+ <li><a href="#ts_uf"><tt>unlock_function(...)</tt></a></li>
+ <li><a href="#ts_lr"><tt>lock_returned(l)</tt></a></li>
+ <li><a href="#ts_le"><tt>locks_excluded(...)</tt></a></li>
+ <li><a href="#ts_elr"><tt>exclusive_locks_required(...)</tt></a></li>
+ <li><a href="#ts_slr"><tt>shared_locks_required(...)</tt></a></li>
</ul>
</ul>
@@ -1109,15 +1122,12 @@ For more details, see the
<a href="http://gcc.gnu.org/wiki/ThreadSafetyAnnotation">GCC implementation</a>.
</p>
-<h4 id="ts_guardedvar">guarded_var</h4>
-
-<p>Use <tt>__attribute__((guarded_var))</tt> on a variable declaration to
-specify that the variable must be accessed while holding some lock.</p>
-
-<h4 id="ts_ptguardedvar">pt_guarded_var</h4>
+<h4 id="ts_noanal">no_thread_safety_analysis</h4>
-<p>Use <tt>__attribute__((pt_guarded_var))</tt> on a pointer declaration to
-specify that the pointer must be dereferenced while holding some lock.</p>
+<p>Use <tt>__attribute__((no_thread_safety_analysis))</tt> 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). </p>
<h4 id="ts_lockable">lockable</h4>
@@ -1133,12 +1143,119 @@ the lock upon construction and release it upon going out of scope.
This annotation is primarily used to check
consistency.</p>
-<h4 id="ts_noanal">no_thread_safety_analysis</h4>
+<h4 id="ts_guardedvar">guarded_var</h4>
-<p>Use <tt>__attribute__((no_thread_safety_analysis))</tt> 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). </p>
+<p>Use <tt>__attribute__((guarded_var))</tt> on a variable declaration to
+specify that the variable must be accessed while holding some lock.</p>
+
+<h4 id="ts_ptguardedvar">pt_guarded_var</h4>
+
+<p>Use <tt>__attribute__((pt_guarded_var))</tt> on a pointer declaration to
+specify that the pointer must be dereferenced while holding some lock.</p>
+
+<h4 id="ts_guardedby">guarded_by(l)</h4>
+
+<p>Use <tt>__attribute__((guarded_by(l)))</tt> on a variable declaration to
+specify that the variable must be accessed while holding lock l.</p>
+
+<h4 id="ts_ptguardedby">pt_guarded_by(l)</h4>
+
+<p>Use <tt>__attribute__((pt_guarded_by(l)))</tt> on a pointer declaration to
+specify that the pointer must be dereferenced while holding lock l.</p>
+
+<h4 id="ts_acquiredbefore">acquired_before(...)</h4>
+
+<p>Use <tt>__attribute__((acquired_before(...)))</tt> 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.</p>
+
+<h4 id="ts_acquiredafter">acquired_after(...)</h4>
+
+<p>Use <tt>__attribute__((acquired_after(...)))</tt> 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.</p>
+
+<h4 id="ts_elf">exclusive_lock_function(...)</h4>
+
+<p>Use <tt>__attribute__((exclusive_lock_function(...)))</tt> 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 <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_slf">shared_lock_function(...)</h4>
+
+<p>Use <tt>__attribute__((shared_lock_function(...)))</tt> 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 <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_etf">exclusive_trylock_function(...)</h4>
+
+<p>Use <tt>__attribute__((exclusive_lock_function(...)))</tt> 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 <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_stf">shared_trylock_function(...)</h4>
+
+<p>Use <tt>__attribute__((shared_lock_function(...)))</tt> 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 <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_uf">unlock_function(...)</h4>
+
+<p>Use <tt>__attribute__((unlock_function(...)))</tt> 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 <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_lr">lock_returned(l)</h4>
+
+<p>Use <tt>__attribute__((lock_returned(l)))</tt> 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.</p>
+
+<h4 id="ts_le">locks_excluded(...)</h4>
+
+<p>Use <tt>__attribute__((locks_excluded(...)))</tt> 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.</p>
+
+<h4 id="ts_elr">exclusive_locks_required(...)</h4>
+
+<p>Use <tt>__attribute__((exclusive_locks_required(...)))</tt> 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.</p>
+
+<h4 id="ts_slr">shared_locks_required(...)</h4>
+
+<p>Use <tt>__attribute__((shared_locks_required(...)))</tt> 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.</p>
</div>
</body>
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 8f52a5b246..2b0ed3d669 100644
--- a/include/clang/Basic/Attr.td
+++ b/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/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 1bb24a46fc..660528a2c1 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/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/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index d741e89bc8..674e13a3df 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/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/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index babf491b94..d9f17b42da 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/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/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 694d38b4a1..0f02ed31df 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/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
};
//===----------------------------------------------------------------------===//
@@ -205,6 +206,34 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
}
///
+/// \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 <ValueDecl>(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<TypedefNameDecl>(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/test/SemaCXX/warn-thread-safety.cpp b/test/SemaCXX/warn-thread-safety.cpp
index 39a3fa2e4d..4958d2ed0f 100644
--- a/test/SemaCXX/warn-thread-safety.cpp
+++ b/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