diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index 0bb64e8dd2dc6c8bc70fb9aae8ef1a394925e92a..5003d9cad86c28efa6bb8270dc3eb05e551745bb 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -1164,12 +1164,12 @@ 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> +specify that the variable must be accessed while holding lock <tt>l</tt>.</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> +specify that the pointer must be dereferenced while holding lock <tt>l</tt>.</p> <h4 id="ts_acquiredbefore">acquired_before(...)</h4> @@ -1189,67 +1189,62 @@ least one argument.</p> <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> +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> + 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> +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 +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> +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> +declaration to specify that the function returns lock <tt>l</tt> (<tt>l</tt> +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> +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> diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index a300764733725000c2518cdfa21c65a2a2b95660..7c5c217ce392dbd22804958b437896b0ecc4da58 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -274,6 +274,9 @@ def Most : DiagGroup<"most", [ OverloadedVirtual ]>; +// Thread Safety warnings +def : DiagGroup<"thread-safety">; + // -Wall is -Wmost -Wparentheses def : DiagGroup<"all", [Most, Parentheses]>; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 38db5b3ec683c8e2238c7216e69131ea1afbb6de..37409d090035ded8197db6dc08e5a6e38147c3c9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1142,6 +1142,10 @@ def err_attribute_bad_neon_vector_size : Error< "Neon vector size must be 64 or 128 bits">; def err_attribute_argument_not_int : Error< "'%0' attribute requires integer constant">; +def err_attribute_argument_not_class : Error< + "%0 attribute requires arguments that are class type or point to class type">; +def err_attribute_first_argument_not_int_or_bool : Error< + "%0 attribute first argument must be of int or bool type">; def err_attribute_argument_outof_range : Error< "init_priority attribute requires integer constant between " "101 and 65535 inclusive">; @@ -1300,6 +1304,21 @@ def warn_availability_version_ordering : Warning< "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version " "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; " "attribute ignored">; + +// Thread Safety Attributes +// Errors when parsing the attributes +def err_attribute_argument_out_of_range : Error< + "%0 attribute parameter %1 is out of bounds: " + "%plural{0:no parameters to index into|" + "1:can only be 1, since there is one parameter|" + ":must be between 1 and %2}2">; +def err_attribute_argument_not_lockable : Error< + "%0 attribute requires arguments whose type is annotated " + "with 'lockable' attribute">; +def err_attribute_decl_not_lockable : Error< + "%0 attribute can only be applied in a context annotated " + "with 'lockable' attribute">; + def warn_impcast_vector_scalar : Warning< "implicit conversion turns vector to scalar: %0 to %1">, diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index af3f40ec40bdaf9376d5d72eccc60770e815082e..fc5d11cb6a22b3bcee3490cd5b42a7b6633e9dc2 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1691,6 +1691,13 @@ bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, ParsedAttributes &attrs, SourceLocation *endLoc); + bool IsThreadSafetyAttribute(llvm::StringRef AttrName); + void ParseThreadSafetyAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc); + + void ParseTypeofSpecifier(DeclSpec &DS); void ParseDecltypeSpecifier(DeclSpec &DS); void ParseUnderlyingTypeSpecifier(DeclSpec &DS); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 1e318fe66e2aebc27f00913c69a2a6a8eee59569..2a95ecc7c7234d268e35f51f746056acc3cace43 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -19,6 +19,7 @@ #include "clang/Sema/PrettyDeclStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -121,6 +122,10 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, // Availability attributes have their own grammar. if (AttrName->isStr("availability")) ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc); + // Thread safety attributes fit into the FIXME case above, so we + // just parse the arguments as a list of expressions + else if (IsThreadSafetyAttribute(AttrName->getName())) + ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, attrs, endLoc); // check if we have a "parameterized" attribute else if (Tok.is(tok::l_paren)) { ConsumeParen(); // ignore the left paren loc for now @@ -650,6 +655,81 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, UnavailableLoc, false, false); } +/// \brief Wrapper around a case statement checking if AttrName is +/// one of the thread safety attributes +bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){ + return llvm::StringSwitch<bool>(AttrName) + .Case("guarded_by", true) + .Case("guarded_var", true) + .Case("pt_guarded_by", true) + .Case("pt_guarded_var", true) + .Case("lockable", true) + .Case("scoped_lockable", true) + .Case("no_thread_safety_analysis", true) + .Case("acquired_after", true) + .Case("acquired_before", true) + .Case("exclusive_lock_function", true) + .Case("shared_lock_function", true) + .Case("exclusive_trylock_function", true) + .Case("shared_trylock_function", true) + .Case("unlock_function", true) + .Case("lock_returned", true) + .Case("locks_excluded", true) + .Case("exclusive_locks_required", true) + .Case("shared_locks_required", true) + .Default(false); +} + +/// \brief Parse the contents of thread safety attributes. These +/// should always be parsed as an expression list. +/// +/// We need to special case the parsing due to the fact that if the first token +/// of the first argument is an identifier, the main parse loop will store +/// that token as a "parameter" and the rest of +/// the arguments will be added to a list of "arguments". However, +/// subsequent tokens in the first argument are lost. We instead parse each +/// argument as an expression and add all arguments to the list of "arguments". +/// In future, we will take advantage of this special case to also +/// deal with some argument scoping issues here (for example, referring to a +/// function parameter in the attribute on that function). +void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc) { + + if (Tok.is(tok::l_paren)) { + SourceLocation LeftParenLoc = Tok.getLocation(); + ConsumeParen(); // ignore the left paren loc for now + + ExprVector ArgExprs(Actions); + bool ArgExprsOk = true; + + // now parse the list of expressions + while (1) { + ExprResult ArgExpr(ParseAssignmentExpression()); + if (ArgExpr.isInvalid()) { + ArgExprsOk = false; + MatchRHSPunctuation(tok::r_paren, LeftParenLoc); + break; + } else { + ArgExprs.push_back(ArgExpr.release()); + } + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument + } + // Match the ')'. + if (ArgExprsOk && Tok.is(tok::r_paren)) { + ConsumeParen(); // ignore the right paren loc for now + Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), + ArgExprs.take(), ArgExprs.size()); + } + } else { + Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); + } +} + void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 9fbd73f4b63b948137ba2f2e07fd5a8d3a21ea89..0644103b44e118996dcabbe4320b506be55a6847 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -15,6 +15,7 @@ #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" @@ -27,7 +28,7 @@ using namespace sema; /// 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, @@ -195,6 +196,8 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { 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) { @@ -205,31 +208,16 @@ 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) { +/// \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; } @@ -246,6 +234,12 @@ static bool mayBeSharedVariable(const Decl *D) { 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. @@ -265,6 +259,71 @@ static bool checkIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) { 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 //===----------------------------------------------------------------------===// @@ -283,7 +342,7 @@ static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr, // 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; } @@ -297,22 +356,26 @@ static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr, } 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 @@ -346,7 +409,7 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D, 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; @@ -360,16 +423,32 @@ static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr, 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 @@ -377,17 +456,22 @@ static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr, } 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)); @@ -397,93 +481,118 @@ static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, } 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)); } diff --git a/test/SemaCXX/warn-thread-safety.cpp b/test/SemaCXX/warn-thread-safety.cpp index 4958d2ed0fa0205f6d31dcb75dd571fa312ba9b5..c5523e2a1315fc50ca04c2dcb672002a2adadc99 100644 --- a/test/SemaCXX/warn-thread-safety.cpp +++ b/test/SemaCXX/warn-thread-safety.cpp @@ -1,19 +1,48 @@ -// 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. @@ -53,9 +82,9 @@ void noanal_fun_params(int lvar __attribute__((no_thread_safety_analysis))); // 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" @@ -89,9 +118,9 @@ int gv_testfn(int y){ return x; } -/*********************************** - * Pt Guarded Var Attribute (pgv) - ***********************************/ +//-----------------------------------------// +// Pt Guarded Var Attribute (pgv) +//-----------------------------------------// //FIXME: add support for boost::scoped_ptr<int> fancyptr and references @@ -133,9 +162,9 @@ void pgv_testfn(int y){ delete x; } -/*********************************** - * Lockable Attribute (l) - ***********************************/ +//-----------------------------------------// +// Lockable Attribute (l) +//-----------------------------------------// //FIXME: In future we may want to add support for structs, ObjC classes, etc. @@ -175,9 +204,9 @@ void l_function_params(int lvar __attribute__((lockable))); // \ 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" @@ -215,11 +244,11 @@ void sl_function_params(int lvar __attribute__((scoped_lockable))); // \ 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" @@ -258,24 +287,36 @@ int gb_testfn(int y){ 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" @@ -317,12 +358,35 @@ void pgb_testfn(int y){ 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" @@ -355,13 +419,34 @@ void aa_testfn(int y){ 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" @@ -397,9 +482,35 @@ void ab_testfn(int y){ // 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" @@ -436,11 +547,42 @@ class __attribute__((exclusive_lock_function)) ElfTestClass { // \ 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" @@ -477,10 +619,42 @@ class __attribute__((shared_lock_function)) SlfTestClass { // \ 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" @@ -521,11 +695,39 @@ class __attribute__((exclusive_trylock_function(1))) EtfTestClass { // \ 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" @@ -567,10 +769,39 @@ class __attribute__((shared_trylock_function(1))) StfTestClass { // \ 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" @@ -607,10 +838,42 @@ class __attribute__((no_thread_safety_analysis)) UfTestClass { // \ 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" @@ -651,9 +914,34 @@ class __attribute__((lock_returned(mu1))) LrTestClass { // \ 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" @@ -693,10 +981,34 @@ class __attribute__((locks_excluded(mu1))) LeTestClass { // \ 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" @@ -736,9 +1048,35 @@ class __attribute__((exclusive_locks_required(mu1))) ElrTestClass { // \ 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" @@ -777,3 +1115,27 @@ class SlrFoo { 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}} +