[cfe-commits] r136383 - in /cfe/trunk: docs/LanguageExtensions.html include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/Sema/AttributeList.cpp lib/Sema/SemaDeclAttr.cpp test/SemaCXX/warn-thread-safety.cpp
Caitlin Sadowski
supertri at google.com
Thu Jul 28 13:12:35 PDT 2011
Author: supertri
Date: Thu Jul 28 15:12:35 2011
New Revision: 136383
URL: http://llvm.org/viewvc/llvm-project?rev=136383&view=rev
Log:
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.
Modified:
cfe/trunk/docs/LanguageExtensions.html
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/AttributeList.h
cfe/trunk/lib/Sema/AttributeList.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/test/SemaCXX/warn-thread-safety.cpp
Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Thu Jul 28 15:12:35 2011
@@ -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 @@
<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 @@
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>
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Jul 28 15:12:35 2011
@@ -561,3 +561,55 @@
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"];
+}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 28 15:12:35 2011
@@ -1128,6 +1128,8 @@
":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<
Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Thu Jul 28 15:12:35 2011
@@ -152,6 +152,8 @@
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 @@
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 @@
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 @@
AT_packed,
AT_pascal,
AT_pcs, // ARM specific
+ AT_pt_guarded_by,
AT_pt_guarded_var,
AT_pure,
AT_regparm,
@@ -236,10 +245,14 @@
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,
Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Thu Jul 28 15:12:35 2011
@@ -215,5 +215,18 @@
.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);
}
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jul 28 15:12:35 2011
@@ -27,7 +27,7 @@
/// 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 @@
ExpectedClassMember,
ExpectedVariable,
ExpectedMethod,
- ExpectedVariableFunctionOrLabel
+ ExpectedVariableFunctionOrLabel,
+ ExpectedFieldOrGlobalVar
};
//===----------------------------------------------------------------------===//
@@ -205,6 +206,34 @@
}
///
+/// \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 @@
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 @@
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 @@
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 @@
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.
Modified: cfe/trunk/test/SemaCXX/warn-thread-safety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety.cpp?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety.cpp Thu Jul 28 15:12:35 2011
@@ -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 @@
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}}
+};
More information about the cfe-commits
mailing list