зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
1d05d424cb
Коммит
db33e14661
|
@ -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_guardedvar"><tt>guarded_var</tt></a></li>
|
||||
<li><a href="#ts_ptguardedvar"><tt>pt_guarded_var</tt></a></li>
|
||||
<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_noanal"><tt>no_thread_safety_analysis</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_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>
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}}
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче