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
This commit is contained in:
Caitlin Sadowski 2011-07-28 20:12:35 +00:00
parent d7ac43eed1
commit 63fa667c68
7 changed files with 1015 additions and 19 deletions

View File

@ -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>
<h4 id="ts_noanal">no_thread_safety_analysis</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>
<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>

View File

@ -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"];
}

View File

@ -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<

View File

@ -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,

View File

@ -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);
}

View File

@ -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 <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.

View File

@ -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}}
};