#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/SourceManager.h"
/// These constants match the enumerated choices of
/// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type.
-enum AttributeDeclType {
+enum AttributeDeclKind {
ExpectedFunction,
ExpectedUnion,
ExpectedVariableOrFunction,
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
}
+/// \brief Check if the attribute has exactly as many args as Num. May
+/// output an error.
static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
unsigned int Num) {
if (Attr.getNumArgs() != Num) {
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) {
+/// \brief Check if the attribute has at least as many args as Num. May
+/// output an error.
+static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr,
+ unsigned int Num) {
+ if (Attr.getNumArgs() < 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;
}
return false;
}
+/// \brief Check if the passed-in expression is of type int or bool.
+static bool isIntOrBool(Expr *Exp) {
+ QualType QT = Exp->getType();
+ return QT->isBooleanType() || QT->isIntegerType();
+}
+
///
/// \brief Check if passed in Decl is a pointer type.
/// Note that this function may produce an error message.
return false;
}
+/// \brief Checks that the passed in QualType either is of RecordType or points
+/// to RecordType. Returns the relevant RecordType, null if it does not exit.
+const RecordType *getRecordType(QualType QT) {
+ const RecordType *RT = QT->getAs<RecordType>();
+ // now check if we point to record type
+ if(!RT && QT->isPointerType()){
+ QualType PT = QT->getAs<PointerType>()->getPointeeType();
+ RT = PT->getAs<RecordType>();
+ }
+ return RT;
+}
+
+/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
+/// from Sidx, resolve to a lockable object. May flag an error.
+static bool checkAttrArgsAreLockableObjs(Sema & S, Decl *D,
+ const AttributeList & Attr,
+ int Sidx = 0,
+ bool ParamIdxOk = false) {
+ for(unsigned int Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
+ Expr *ArgExp = Attr.getArg(Idx);
+ if (ArgExp->isTypeDependent())
+ continue;
+
+ QualType Arg_QT = ArgExp->getType();
+
+ // Get record type.
+ // first see if we can just cast to record type, or point to record type
+ const RecordType *RT = getRecordType(Arg_QT);
+
+ // now check if we idx into a record type function param
+ if (!RT && ParamIdxOk) {
+ FunctionDecl *FD = dyn_cast <FunctionDecl>(D);
+ IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp);
+ if(FD && IL) {
+ unsigned int NumParams = FD->getNumParams();
+ llvm::APInt ArgValue = IL->getValue();
+ uint64_t ParamIdx_from1 = ArgValue.getZExtValue();
+ uint64_t ParamIdx_from0 = ParamIdx_from1 - 1;
+ if(!ArgValue.isStrictlyPositive() || ParamIdx_from1 > NumParams) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range)
+ << Attr.getName() << Idx + 1 << NumParams;
+ return false;
+ }
+ Arg_QT = FD->getParamDecl(ParamIdx_from0)->getType();
+ RT = getRecordType(Arg_QT);
+ }
+ }
+
+ // Flag error if could not get record type for this argument
+ if (!RT) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_class)
+ << Attr.getName();
+ return false;
+ }
+
+ // Flag error if the type is not lockable
+ if (!RT->getDecl()->getAttr<LockableAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_lockable)
+ << Attr.getName();
+ return false;
+ }
+ }
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Attribute Implementations
//===----------------------------------------------------------------------===//
// 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*/;
+ << Attr.getName() << ExpectedFieldOrGlobalVar;
return;
}
}
static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool pointer = false) {
+ bool pointer = false) {
assert(!Attr.isInvalid());
- if (!checkAttributeNumArgsPlusParams(S, Attr, 1))
+ if (!checkAttributeNumArgs(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*/;
+ << Attr.getName() << ExpectedFieldOrGlobalVar;
return;
}
if (pointer && !checkIsPointer(S, D, Attr))
return;
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+ return;
+
if (pointer)
D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getLoc(), S.Context));
else
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- if (!isFunction(D)) {
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
bool before) {
assert(!Attr.isInvalid());
- if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
// D must be either a member field or global (potentially shared) variable.
- if (!mayBeSharedVariable(D)) {
+ ValueDecl *VD = dyn_cast<ValueDecl>(D);
+ if (!VD || !mayBeSharedVariable(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 15; /*fields and global vars*/;
+ << Attr.getName() << ExpectedFieldOrGlobalVar;
return;
}
+ // Check that this attribute only applies to lockable types
+ QualType QT = VD->getType();
+ if (!QT->isDependentType()) {
+ const RecordType *RT = getRecordType(QT);
+ if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_decl_not_lockable)
+ << Attr.getName();
+ return;
+ }
+ }
+
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+ return;
+
if (before)
D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getLoc(), S.Context));
else
}
static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+ bool exclusive = false) {
assert(!Attr.isInvalid());
// zero or more arguments ok
- if (!isFunction(D)) {
+ // check that the attribute is applied to a function
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, 0, /*ParamIdxOk=*/true))
+ return;
+
if (exclusive)
D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getLoc(),
S.Context));
}
static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+ bool exclusive = false) {
assert(!Attr.isInvalid());
- if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
- if (!isFunction(D)) {
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
+ if (!isIntOrBool(Attr.getArg(0))) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool)
+ << Attr.getName();
+ return;
+ }
+
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, 1))
+ return;
+
if (exclusive)
D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getLoc(),
- S.Context));
+ S.Context));
else
D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getLoc(),
- S.Context));
-
+ S.Context));
}
static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr,
- bool exclusive = false) {
+ bool exclusive = false) {
assert(!Attr.isInvalid());
- if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
- if (!isFunction(D)) {
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+ return;
+
if (exclusive)
D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getLoc(),
- S.Context));
+ S.Context));
else
D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getLoc(),
- S.Context));
+ S.Context));
}
-
static void handleUnlockFunAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
// zero or more arguments ok
- if (!isFunction(D)) {
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr, 0, /*ParamIdxOk=*/true))
+ return;
+
D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getLoc(), S.Context));
}
static void handleLockReturnedAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
- if (!checkAttributeNumArgsPlusParams(S, Attr, 1))
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
- if (!isFunction(D)) {
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+ return;
+
D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getLoc(), S.Context));
}
static void handleLocksExcludedAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
- if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
- if (!isFunction(D)) {
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
+ // check that all arguments are lockable objects
+ if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+ return;
+
D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getLoc(), S.Context));
}
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
-/**
- * Helper fields
- */
+//-----------------------------------------//
+// Helper fields
+//-----------------------------------------//
class __attribute__((lockable)) Mu {
};
+class UnlockableMu{
+};
+
+class MuWrapper {
+ public:
+ Mu mu;
+ Mu getMu() {
+ return mu;
+ }
+ Mu * getMuPointer() {
+ return μ
+ }
+};
+
+
+class MuDoubleWrapper {
+ public:
+ MuWrapper* muWrapper;
+ MuWrapper* getWrapper() {
+ return muWrapper;
+ }
+};
+
Mu mu1;
+UnlockableMu umu;
Mu mu2;
+MuWrapper muWrapper;
+MuDoubleWrapper muDoubleWrapper;
+Mu* muPointer;
+Mu ** muDoublePointer = & muPointer;
+Mu& muRef = mu1;
-/***********************************
- * No Thread Safety Analysis (noanal)
- ***********************************/
+//-----------------------------------------//
+// No Thread Safety Analysis (noanal) //
+//-----------------------------------------//
// FIXME: Right now we cannot parse attributes put on function definitions
// We would like to patch this at some point.
expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
-/***********************************
- * Guarded Var Attribute (gv)
- ***********************************/
+//-----------------------------------------//
+// Guarded Var Attribute (gv)
+//-----------------------------------------//
#if !__has_attribute(guarded_var)
#error "Should support guarded_var attribute"
return x;
}
-/***********************************
- * Pt Guarded Var Attribute (pgv)
- ***********************************/
+//-----------------------------------------//
+// Pt Guarded Var Attribute (pgv)
+//-----------------------------------------//
//FIXME: add support for boost::scoped_ptr<int> fancyptr and references
delete x;
}
-/***********************************
- * Lockable Attribute (l)
- ***********************************/
+//-----------------------------------------//
+// Lockable Attribute (l)
+//-----------------------------------------//
//FIXME: In future we may want to add support for structs, ObjC classes, etc.
expected-warning {{'lockable' attribute only applies to classes}}
-/***********************************
- * Scoped Lockable Attribute (sl)
- ***********************************/
+//-----------------------------------------//
+// Scoped Lockable Attribute (sl)
+//-----------------------------------------//
#if !__has_attribute(scoped_lockable)
#error "Should support scoped_lockable attribute"
expected-warning {{'scoped_lockable' attribute only applies to classes}}
-/***********************************
- * Guarded By Attribute (gb)
- ***********************************/
+//-----------------------------------------//
+// Guarded By Attribute (gb)
+//-----------------------------------------//
-// FIXME: Would we like this attribute to take more than 1 arg?
+// FIXME: Eventually, would we like this attribute to take more than 1 arg?
#if !__has_attribute(guarded_by)
#error "Should support guarded_by attribute"
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
+//2. Check argument parsing.
+
+// legal attribute arguments
+int gb_var_arg_1 __attribute__((guarded_by(muWrapper.mu)));
+int gb_var_arg_2 __attribute__((guarded_by(muDoubleWrapper.muWrapper->mu)));
+int gb_var_arg_3 __attribute__((guarded_by(muWrapper.getMu())));
+int gb_var_arg_4 __attribute__((guarded_by(*muWrapper.getMuPointer())));
+int gb_var_arg_5 __attribute__((guarded_by(&mu1)));
+int gb_var_arg_6 __attribute__((guarded_by(muRef)));
+int gb_var_arg_7 __attribute__((guarded_by(muDoubleWrapper.getWrapper()->getMu())));
+int gb_var_arg_8 __attribute__((guarded_by(muPointer)));
+
+
+// illegal attribute arguments
+int gb_var_arg_bad_1 __attribute__((guarded_by(1))); // \
+ expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_2 __attribute__((guarded_by("mu"))); // \
+ expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_3 __attribute__((guarded_by(muDoublePointer))); // \
+ expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_4 __attribute__((guarded_by(umu))); // \
+ expected-error {{'guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
//3.
// Thread Safety analysis tests
-/***********************************
- * Pt Guarded By Attribute (pgb)
- ***********************************/
+//-----------------------------------------//
+// Pt Guarded By Attribute (pgb)
+//-----------------------------------------//
#if !__has_attribute(pt_guarded_by)
#error "Should support pt_guarded_by attribute"
delete x;
}
-/***********************************
- * Acquired After (aa)
- ***********************************/
+//2. Check argument parsing.
+
+// legal attribute arguments
+int * pgb_var_arg_1 __attribute__((pt_guarded_by(muWrapper.mu)));
+int * pgb_var_arg_2 __attribute__((pt_guarded_by(muDoubleWrapper.muWrapper->mu)));
+int * pgb_var_arg_3 __attribute__((pt_guarded_by(muWrapper.getMu())));
+int * pgb_var_arg_4 __attribute__((pt_guarded_by(*muWrapper.getMuPointer())));
+int * pgb_var_arg_5 __attribute__((pt_guarded_by(&mu1)));
+int * pgb_var_arg_6 __attribute__((pt_guarded_by(muRef)));
+int * pgb_var_arg_7 __attribute__((pt_guarded_by(muDoubleWrapper.getWrapper()->getMu())));
+int * pgb_var_arg_8 __attribute__((pt_guarded_by(muPointer)));
+
+
+// illegal attribute arguments
+int * pgb_var_arg_bad_1 __attribute__((pt_guarded_by(1))); // \
+ expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+int * pgb_var_arg_bad_2 __attribute__((pt_guarded_by("mu"))); // \
+ expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+int * pgb_var_arg_bad_3 __attribute__((pt_guarded_by(muDoublePointer))); // \
+ expected-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+int * pgb_var_arg_bad_4 __attribute__((pt_guarded_by(umu))); // \
+ expected-error {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+// 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"
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)
- ***********************************/
+//Check argument parsing.
+
+// legal attribute arguments
+Mu aa_var_arg_1 __attribute__((acquired_after(muWrapper.mu)));
+Mu aa_var_arg_2 __attribute__((acquired_after(muDoubleWrapper.muWrapper->mu)));
+Mu aa_var_arg_3 __attribute__((acquired_after(muWrapper.getMu())));
+Mu aa_var_arg_4 __attribute__((acquired_after(*muWrapper.getMuPointer())));
+Mu aa_var_arg_5 __attribute__((acquired_after(&mu1)));
+Mu aa_var_arg_6 __attribute__((acquired_after(muRef)));
+Mu aa_var_arg_7 __attribute__((acquired_after(muDoubleWrapper.getWrapper()->getMu())));
+Mu aa_var_arg_8 __attribute__((acquired_after(muPointer)));
+
+
+// illegal attribute arguments
+Mu aa_var_arg_bad_1 __attribute__((acquired_after(1))); // \
+ expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+Mu aa_var_arg_bad_2 __attribute__((acquired_after("mu"))); // \
+ expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+Mu aa_var_arg_bad_3 __attribute__((acquired_after(muDoublePointer))); // \
+ expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+Mu aa_var_arg_bad_4 __attribute__((acquired_after(umu))); // \
+ expected-error {{'acquired_after' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+UnlockableMu aa_var_arg_bad_5 __attribute__((acquired_after(mu_aa))); // \
+ expected-error {{'acquired_after' attribute can only be applied in a context annotated with 'lockable' attribute}}
+
+//-----------------------------------------//
+// Acquired Before (ab)
+//-----------------------------------------//
#if !__has_attribute(acquired_before)
#error "Should support acquired_before attribute"
// 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)
- ***********************************/
+//Check argument parsing.
+
+// legal attribute arguments
+Mu ab_var_arg_1 __attribute__((acquired_before(muWrapper.mu)));
+Mu ab_var_arg_2 __attribute__((acquired_before(muDoubleWrapper.muWrapper->mu)));
+Mu ab_var_arg_3 __attribute__((acquired_before(muWrapper.getMu())));
+Mu ab_var_arg_4 __attribute__((acquired_before(*muWrapper.getMuPointer())));
+Mu ab_var_arg_5 __attribute__((acquired_before(&mu1)));
+Mu ab_var_arg_6 __attribute__((acquired_before(muRef)));
+Mu ab_var_arg_7 __attribute__((acquired_before(muDoubleWrapper.getWrapper()->getMu())));
+Mu ab_var_arg_8 __attribute__((acquired_before(muPointer)));
+
+
+// illegal attribute arguments
+Mu ab_var_arg_bad_1 __attribute__((acquired_before(1))); // \
+ expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+Mu ab_var_arg_bad_2 __attribute__((acquired_before("mu"))); // \
+ expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+Mu ab_var_arg_bad_3 __attribute__((acquired_before(muDoublePointer))); // \
+ expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+Mu ab_var_arg_bad_4 __attribute__((acquired_before(umu))); // \
+ expected-error {{'acquired_before' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+UnlockableMu ab_var_arg_bad_5 __attribute__((acquired_before(mu_ab))); // \
+ expected-error {{'acquired_before' attribute can only be applied in a context annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+// Exclusive Lock Function (elf)
+//-----------------------------------------//
#if !__has_attribute(exclusive_lock_function)
#error "Should support exclusive_lock_function attribute"
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)
- ***********************************/
+// Check argument parsing.
+
+// legal attribute arguments
+int elf_function_1() __attribute__((exclusive_lock_function(muWrapper.mu)));
+int elf_function_2() __attribute__((exclusive_lock_function(muDoubleWrapper.muWrapper->mu)));
+int elf_function_3() __attribute__((exclusive_lock_function(muWrapper.getMu())));
+int elf_function_4() __attribute__((exclusive_lock_function(*muWrapper.getMuPointer())));
+int elf_function_5() __attribute__((exclusive_lock_function(&mu1)));
+int elf_function_6() __attribute__((exclusive_lock_function(muRef)));
+int elf_function_7() __attribute__((exclusive_lock_function(muDoubleWrapper.getWrapper()->getMu())));
+int elf_function_8() __attribute__((exclusive_lock_function(muPointer)));
+int elf_function_9(Mu x) __attribute__((exclusive_lock_function(1)));
+int elf_function_9(Mu x, Mu y) __attribute__((exclusive_lock_function(1,2)));
+
+
+// illegal attribute arguments
+int elf_function_bad_2() __attribute__((exclusive_lock_function("mu"))); // \
+ expected-error {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
+int elf_function_bad_3() __attribute__((exclusive_lock_function(muDoublePointer))); // \
+ expected-error {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
+int elf_function_bad_4() __attribute__((exclusive_lock_function(umu))); // \
+ expected-error {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int elf_function_bad_1() __attribute__((exclusive_lock_function(1))); // \
+ expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int elf_function_bad_5(Mu x) __attribute__((exclusive_lock_function(0))); // \
+ expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int elf_function_bad_6(Mu x, Mu y) __attribute__((exclusive_lock_function(0))); // \
+ expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int elf_function_bad_7() __attribute__((exclusive_lock_function(0))); // \
+ expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+// Shared Lock Function (slf)
+//-----------------------------------------//
#if !__has_attribute(shared_lock_function)
#error "Should support shared_lock_function attribute"
expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
};
-
-/***********************************
- * Exclusive TryLock Function (etf)
- ***********************************/
+// Check argument parsing.
+
+// legal attribute arguments
+int slf_function_1() __attribute__((shared_lock_function(muWrapper.mu)));
+int slf_function_2() __attribute__((shared_lock_function(muDoubleWrapper.muWrapper->mu)));
+int slf_function_3() __attribute__((shared_lock_function(muWrapper.getMu())));
+int slf_function_4() __attribute__((shared_lock_function(*muWrapper.getMuPointer())));
+int slf_function_5() __attribute__((shared_lock_function(&mu1)));
+int slf_function_6() __attribute__((shared_lock_function(muRef)));
+int slf_function_7() __attribute__((shared_lock_function(muDoubleWrapper.getWrapper()->getMu())));
+int slf_function_8() __attribute__((shared_lock_function(muPointer)));
+int slf_function_9(Mu x) __attribute__((shared_lock_function(1)));
+int slf_function_9(Mu x, Mu y) __attribute__((shared_lock_function(1,2)));
+
+
+// illegal attribute arguments
+int slf_function_bad_2() __attribute__((shared_lock_function("mu"))); // \
+ expected-error {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
+int slf_function_bad_3() __attribute__((shared_lock_function(muDoublePointer))); // \
+ expected-error {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
+int slf_function_bad_4() __attribute__((shared_lock_function(umu))); // \
+ expected-error {{'shared_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int slf_function_bad_1() __attribute__((shared_lock_function(1))); // \
+ expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int slf_function_bad_5(Mu x) __attribute__((shared_lock_function(0))); // \
+ expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int slf_function_bad_6(Mu x, Mu y) __attribute__((shared_lock_function(0))); // \
+ expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int slf_function_bad_7() __attribute__((shared_lock_function(0))); // \
+ expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+// Exclusive TryLock Function (etf)
+//-----------------------------------------//
#if !__has_attribute(exclusive_trylock_function)
#error "Should support exclusive_trylock_function attribute"
void etf_fun_params(int lvar __attribute__((exclusive_trylock_function(1)))); // \
expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+// Check argument parsing.
+
+// legal attribute arguments
+int etf_function_1() __attribute__((exclusive_trylock_function(1, muWrapper.mu)));
+int etf_function_2() __attribute__((exclusive_trylock_function(1, muDoubleWrapper.muWrapper->mu)));
+int etf_function_3() __attribute__((exclusive_trylock_function(1, muWrapper.getMu())));
+int etf_function_4() __attribute__((exclusive_trylock_function(1, *muWrapper.getMuPointer())));
+int etf_function_5() __attribute__((exclusive_trylock_function(1, &mu1)));
+int etf_function_6() __attribute__((exclusive_trylock_function(1, muRef)));
+int etf_function_7() __attribute__((exclusive_trylock_function(1, muDoubleWrapper.getWrapper()->getMu())));
+int etf_functetfn_8() __attribute__((exclusive_trylock_function(1, muPointer)));
+int etf_function_9() __attribute__((exclusive_trylock_function(true)));
+
+
+// illegal attribute arguments
+int etf_function_bad_1() __attribute__((exclusive_trylock_function(mu1))); // \
+ expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+int etf_function_bad_2() __attribute__((exclusive_trylock_function("mu"))); // \
+ expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+int etf_function_bad_3() __attribute__((exclusive_trylock_function(muDoublePointer))); // \
+ expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+int etf_function_bad_4() __attribute__((exclusive_trylock_function(1, "mu"))); // \
+ expected-error {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
+int etf_function_bad_5() __attribute__((exclusive_trylock_function(1, muDoublePointer))); // \
+ expected-error {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
+int etf_function_bad_6() __attribute__((exclusive_trylock_function(1, umu))); // \
+ expected-error {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
-/***********************************
- * Shared TryLock Function (stf)
- ***********************************/
+
+//-----------------------------------------//
+// Shared TryLock Function (stf)
+//-----------------------------------------//
#if !__has_attribute(shared_trylock_function)
#error "Should support shared_trylock_function attribute"
expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
};
+// Check argument parsing.
+
+// legal attribute arguments
+int stf_function_1() __attribute__((shared_trylock_function(1, muWrapper.mu)));
+int stf_function_2() __attribute__((shared_trylock_function(1, muDoubleWrapper.muWrapper->mu)));
+int stf_function_3() __attribute__((shared_trylock_function(1, muWrapper.getMu())));
+int stf_function_4() __attribute__((shared_trylock_function(1, *muWrapper.getMuPointer())));
+int stf_function_5() __attribute__((shared_trylock_function(1, &mu1)));
+int stf_function_6() __attribute__((shared_trylock_function(1, muRef)));
+int stf_function_7() __attribute__((shared_trylock_function(1, muDoubleWrapper.getWrapper()->getMu())));
+int stf_function_8() __attribute__((shared_trylock_function(1, muPointer)));
+int stf_function_9() __attribute__((shared_trylock_function(true)));
+
+
+// illegal attribute arguments
+int stf_function_bad_1() __attribute__((shared_trylock_function(mu1))); // \
+ expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+int stf_function_bad_2() __attribute__((shared_trylock_function("mu"))); // \
+ expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+int stf_function_bad_3() __attribute__((shared_trylock_function(muDoublePointer))); // \
+ expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
-/***********************************
- * Unlock Function (uf)
- ***********************************/
+int stf_function_bad_4() __attribute__((shared_trylock_function(1, "mu"))); // \
+ expected-error {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
+int stf_function_bad_5() __attribute__((shared_trylock_function(1, muDoublePointer))); // \
+ expected-error {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
+int stf_function_bad_6() __attribute__((shared_trylock_function(1, umu))); // \
+ expected-error {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+// Unlock Function (uf)
+//-----------------------------------------//
#if !__has_attribute(unlock_function)
#error "Should support unlock_function attribute"
void uf_fun_params(int lvar __attribute__((unlock_function))); // \
expected-warning {{'unlock_function' attribute only applies to functions and methods}}
-
-/***********************************
- * Lock Returned (lr)
- ***********************************/
+// Check argument parsing.
+
+// legal attribute arguments
+int uf_function_1() __attribute__((unlock_function(muWrapper.mu)));
+int uf_function_2() __attribute__((unlock_function(muDoubleWrapper.muWrapper->mu)));
+int uf_function_3() __attribute__((unlock_function(muWrapper.getMu())));
+int uf_function_4() __attribute__((unlock_function(*muWrapper.getMuPointer())));
+int uf_function_5() __attribute__((unlock_function(&mu1)));
+int uf_function_6() __attribute__((unlock_function(muRef)));
+int uf_function_7() __attribute__((unlock_function(muDoubleWrapper.getWrapper()->getMu())));
+int uf_function_8() __attribute__((unlock_function(muPointer)));
+int uf_function_9(Mu x) __attribute__((unlock_function(1)));
+int uf_function_9(Mu x, Mu y) __attribute__((unlock_function(1,2)));
+
+
+// illegal attribute arguments
+int uf_function_bad_2() __attribute__((unlock_function("mu"))); // \
+ expected-error {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+int uf_function_bad_3() __attribute__((unlock_function(muDoublePointer))); // \
+expected-error {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+int uf_function_bad_4() __attribute__((unlock_function(umu))); // \
+ expected-error {{'unlock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int uf_function_bad_1() __attribute__((unlock_function(1))); // \
+ expected-error {{'unlock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int uf_function_bad_5(Mu x) __attribute__((unlock_function(0))); // \
+ expected-error {{'unlock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int uf_function_bad_6(Mu x, Mu y) __attribute__((unlock_function(0))); // \
+ expected-error {{'unlock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int uf_function_bad_7() __attribute__((unlock_function(0))); // \
+ expected-error {{'unlock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+// Lock Returned (lr)
+//-----------------------------------------//
#if !__has_attribute(lock_returned)
#error "Should support lock_returned attribute"
expected-warning {{'lock_returned' attribute only applies to functions and methods}}
};
-/***********************************
- * Locks Excluded (le)
- ***********************************/
+// Check argument parsing.
+
+// legal attribute arguments
+int lr_function_1() __attribute__((lock_returned(muWrapper.mu)));
+int lr_function_2() __attribute__((lock_returned(muDoubleWrapper.muWrapper->mu)));
+int lr_function_3() __attribute__((lock_returned(muWrapper.getMu())));
+int lr_function_4() __attribute__((lock_returned(*muWrapper.getMuPointer())));
+int lr_function_5() __attribute__((lock_returned(&mu1)));
+int lr_function_6() __attribute__((lock_returned(muRef)));
+int lr_function_7() __attribute__((lock_returned(muDoubleWrapper.getWrapper()->getMu())));
+int lr_function_8() __attribute__((lock_returned(muPointer)));
+
+
+// illegal attribute arguments
+int lr_function_bad_1() __attribute__((lock_returned(1))); // \
+ expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_2() __attribute__((lock_returned("mu"))); // \
+ expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_3() __attribute__((lock_returned(muDoublePointer))); // \
+ expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_4() __attribute__((lock_returned(umu))); // \
+ expected-error {{'lock_returned' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+//-----------------------------------------//
+// Locks Excluded (le)
+//-----------------------------------------//
#if !__has_attribute(locks_excluded)
#error "Should support locks_excluded attribute"
expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
};
+// Check argument parsing.
+
+// legal attribute arguments
+int le_function_1() __attribute__((locks_excluded(muWrapper.mu)));
+int le_function_2() __attribute__((locks_excluded(muDoubleWrapper.muWrapper->mu)));
+int le_function_3() __attribute__((locks_excluded(muWrapper.getMu())));
+int le_function_4() __attribute__((locks_excluded(*muWrapper.getMuPointer())));
+int le_function_5() __attribute__((locks_excluded(&mu1)));
+int le_function_6() __attribute__((locks_excluded(muRef)));
+int le_function_7() __attribute__((locks_excluded(muDoubleWrapper.getWrapper()->getMu())));
+int le_function_8() __attribute__((locks_excluded(muPointer)));
-/***********************************
- * Exclusive Locks Required (elr)
- ***********************************/
+
+// illegal attribute arguments
+int le_function_bad_1() __attribute__((locks_excluded(1))); // \
+ expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_2() __attribute__((locks_excluded("mu"))); // \
+ expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_3() __attribute__((locks_excluded(muDoublePointer))); // \
+ expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_4() __attribute__((locks_excluded(umu))); // \
+ expected-error {{'locks_excluded' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+//-----------------------------------------//
+// Exclusive Locks Required (elr)
+//-----------------------------------------//
#if !__has_attribute(exclusive_locks_required)
#error "Should support exclusive_locks_required attribute"
expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
};
-/***********************************
- * Shared Locks Required (slr)
- ***********************************/
+// Check argument parsing.
+
+// legal attribute arguments
+int elr_function_1() __attribute__((exclusive_locks_required(muWrapper.mu)));
+int elr_function_2() __attribute__((exclusive_locks_required(muDoubleWrapper.muWrapper->mu)));
+int elr_function_3() __attribute__((exclusive_locks_required(muWrapper.getMu())));
+int elr_function_4() __attribute__((exclusive_locks_required(*muWrapper.getMuPointer())));
+int elr_function_5() __attribute__((exclusive_locks_required(&mu1)));
+int elr_function_6() __attribute__((exclusive_locks_required(muRef)));
+int elr_function_7() __attribute__((exclusive_locks_required(muDoubleWrapper.getWrapper()->getMu())));
+int elr_function_8() __attribute__((exclusive_locks_required(muPointer)));
+
+
+// illegal attribute arguments
+int elr_function_bad_1() __attribute__((exclusive_locks_required(1))); // \
+ expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+int elr_function_bad_2() __attribute__((exclusive_locks_required("mu"))); // \
+ expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+int elr_function_bad_3() __attribute__((exclusive_locks_required(muDoublePointer))); // \
+ expected-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+int elr_function_bad_4() __attribute__((exclusive_locks_required(umu))); // \
+ expected-error {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+
+//-----------------------------------------//
+// Shared Locks Required (slr)
+//-----------------------------------------//
#if !__has_attribute(shared_locks_required)
#error "Should support shared_locks_required attribute"
class __attribute__((shared_locks_required(mu1))) SlrTestClass { // \
expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
};
+
+// Check argument parsing.
+
+// legal attribute arguments
+int slr_function_1() __attribute__((shared_locks_required(muWrapper.mu)));
+int slr_function_2() __attribute__((shared_locks_required(muDoubleWrapper.muWrapper->mu)));
+int slr_function_3() __attribute__((shared_locks_required(muWrapper.getMu())));
+int slr_function_4() __attribute__((shared_locks_required(*muWrapper.getMuPointer())));
+int slr_function_5() __attribute__((shared_locks_required(&mu1)));
+int slr_function_6() __attribute__((shared_locks_required(muRef)));
+int slr_function_7() __attribute__((shared_locks_required(muDoubleWrapper.getWrapper()->getMu())));
+int slr_function_8() __attribute__((shared_locks_required(muPointer)));
+
+
+// illegal attribute arguments
+int slr_function_bad_1() __attribute__((shared_locks_required(1))); // \
+ expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+int slr_function_bad_2() __attribute__((shared_locks_required("mu"))); // \
+ expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+int slr_function_bad_3() __attribute__((shared_locks_required(muDoublePointer))); // \
+ expected-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+int slr_function_bad_4() __attribute__((shared_locks_required(umu))); // \
+ expected-error {{'shared_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+