let Spellings = [GNU<"lockable">];
let Subjects = SubjectList<[Record]>;
let Documentation = [Undocumented];
+ let ASTNode = 0; // Replaced by Capability
}
def ScopedLockable : InheritableAttr {
let Documentation = [Undocumented];
}
+def Capability : InheritableAttr {
+ let Spellings = [GNU<"capability">, CXX11<"clang", "capability">,
+ GNU<"shared_capability">,
+ CXX11<"clang", "shared_capability">];
+ let Subjects = SubjectList<[Struct], ErrorDiag, "ExpectedStruct">;
+ let Args = [StringArgument<"Name">];
+ let Accessors = [Accessor<"isShared",
+ [GNU<"shared_capability">,
+ CXX11<"clang","shared_capability">]>];
+ let Documentation = [Undocumented];
+}
+
+def RequiresCapability : InheritableAttr {
+ let Spellings = [GNU<"requires_capability">,
+ CXX11<"clang", "requires_capability">,
+ GNU<"exclusive_locks_required">,
+ GNU<"requires_shared_capability">,
+ CXX11<"clang", "requires_shared_capability">,
+ GNU<"shared_locks_required">];
+ let Args = [VariadicExprArgument<"Args">];
+ let LateParsed = 1;
+ let TemplateDependent = 1;
+ let ParseArgumentsAsUnevaluated = 1;
+ let DuplicatesAllowedWhileMerging = 1;
+ let Subjects = SubjectList<[Function, FunctionTemplate]>;
+ let Accessors = [Accessor<"isShared", [GNU<"requires_shared_capability">,
+ GNU<"shared_locks_required">,
+ CXX11<"clang","requires_shared_capability">]>];
+ let Documentation = [Undocumented];
+}
+
def NoThreadSafetyAnalysis : InheritableAttr {
let Spellings = [GNU<"no_thread_safety_analysis">];
let Subjects = SubjectList<[Function, FunctionTemplate]>;
let Documentation = [Undocumented];
}
-def ExclusiveLocksRequired : InheritableAttr {
- let Spellings = [GNU<"exclusive_locks_required">];
- let Args = [VariadicExprArgument<"Args">];
- let LateParsed = 1;
- let TemplateDependent = 1;
- let ParseArgumentsAsUnevaluated = 1;
- let DuplicatesAllowedWhileMerging = 1;
- let Subjects = SubjectList<[Function, FunctionTemplate]>;
- let Documentation = [Undocumented];
-}
-
-def SharedLocksRequired : InheritableAttr {
- let Spellings = [GNU<"shared_locks_required">];
- let Args = [VariadicExprArgument<"Args">];
- let LateParsed = 1;
- let TemplateDependent = 1;
- let ParseArgumentsAsUnevaluated = 1;
- let DuplicatesAllowedWhileMerging = 1;
- let Subjects = SubjectList<[Function, FunctionTemplate]>;
- let Documentation = [Undocumented];
-}
-
// C/C++ consumed attributes.
def Consumable : InheritableAttr {
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_argument_not_lockable : Warning<
"%0 attribute requires arguments whose type is annotated "
- "with 'lockable' attribute; type here is %1">,
+ "with 'capability' attribute; type here is %1">,
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_argument_not_class : Warning<
"%0 attribute requires arguments that are class type or point to"
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_decl_not_lockable : Warning<
"%0 attribute can only be applied in a context annotated "
- "with 'lockable' attribute">,
+ "with 'capability(\"mutex\")' attribute">,
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_decl_not_pointer : Warning<
"%0 only applies to pointer types; type here is %1">,
break;
}
- case attr::ExclusiveLocksRequired: {
- ExclusiveLocksRequiredAttr *A = cast<ExclusiveLocksRequiredAttr>(At);
+ case attr::RequiresCapability: {
+ RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
- for (ExclusiveLocksRequiredAttr::args_iterator
- I = A->args_begin(), E = A->args_end(); I != E; ++I)
- warnIfMutexNotHeld(D, Exp, AK_Written, *I, POK_FunctionCall);
- break;
- }
-
- case attr::SharedLocksRequired: {
- SharedLocksRequiredAttr *A = cast<SharedLocksRequiredAttr>(At);
-
- for (SharedLocksRequiredAttr::args_iterator I = A->args_begin(),
+ for (RequiresCapabilityAttr::args_iterator I = A->args_begin(),
E = A->args_end(); I != E; ++I)
- warnIfMutexNotHeld(D, Exp, AK_Read, *I, POK_FunctionCall);
+ warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, *I,
+ POK_FunctionCall);
break;
}
for (unsigned i = 0; i < ArgAttrs.size(); ++i) {
Attr *Attr = ArgAttrs[i];
Loc = Attr->getLocation();
- if (ExclusiveLocksRequiredAttr *A
- = dyn_cast<ExclusiveLocksRequiredAttr>(Attr)) {
- getMutexIDs(ExclusiveLocksToAdd, A, (Expr*) 0, D);
- } else if (SharedLocksRequiredAttr *A
- = dyn_cast<SharedLocksRequiredAttr>(Attr)) {
- getMutexIDs(SharedLocksToAdd, A, (Expr*) 0, D);
+ if (RequiresCapabilityAttr *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
+ getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
+ 0, D);
} else if (UnlockFunctionAttr *A = dyn_cast<UnlockFunctionAttr>(Attr)) {
// UNLOCK_FUNCTION() is used to hide the underlying lock implementation.
// We must ignore such methods.
static bool checkBaseClassIsLockableCallback(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, void *Unused) {
const RecordType *RT = Specifier->getType()->getAs<RecordType>();
- return RT->getDecl()->hasAttr<LockableAttr>();
+ return RT->getDecl()->hasAttr<CapabilityAttr>();
}
// Check if the type is lockable.
RecordDecl *RD = RT->getDecl();
- if (RD->hasAttr<LockableAttr>())
+ if (RD->hasAttr<CapabilityAttr>())
return;
// Else check if any base classes are lockable.
QualType QT = cast<ValueDecl>(D)->getType();
if (!QT->isDependentType()) {
const RecordType *RT = getRecordType(QT);
- if (!RT || !RT->getDecl()->hasAttr<LockableAttr>()) {
+ if (!RT || !RT->getDecl()->hasAttr<CapabilityAttr>()) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable)
<< Attr.getName();
return false;
Attr.getAttributeSpellingListIndex()));
}
-static bool checkLocksRequiredCommon(Sema &S, Decl *D,
- const AttributeList &Attr,
- SmallVectorImpl<Expr *> &Args) {
- if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return false;
-
- // check that all arguments are lockable objects
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
- if (Args.empty())
- return false;
-
- return true;
-}
-
-static void handleExclusiveLocksRequiredAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- SmallVector<Expr*, 1> Args;
- if (!checkLocksRequiredCommon(S, D, Attr, Args))
- return;
-
- Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context)
- ExclusiveLocksRequiredAttr(Attr.getRange(), S.Context,
- StartArg, Args.size(),
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- SmallVector<Expr*, 1> Args;
- if (!checkLocksRequiredCommon(S, D, Attr, Args))
- return;
-
- Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context)
- SharedLocksRequiredAttr(Attr.getRange(), S.Context,
- StartArg, Args.size(),
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleUnlockFunAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
// zero or more arguments ok
MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex);
}
+static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // The capability attributes take a single string parameter for the name of
+ // the capability they represent. The lockable attribute does not take any
+ // parameters. However, semantically, both attributes represent the same
+ // concept, and so they use the same semantic attribute. Eventually, the
+ // lockable attribute will be removed.
+ StringRef N;
+ SourceLocation LiteralLoc;
+ if (Attr.getKind() == AttributeList::AT_Capability &&
+ !S.checkStringLiteralArgumentAttr(Attr, 0, N, &LiteralLoc))
+ return;
+
+ D->addAttr(::new (S.Context) CapabilityAttr(Attr.getRange(), S.Context, N,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ // check that all arguments are lockable objects
+ SmallVector<Expr*, 1> Args;
+ checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ if (Args.empty())
+ return;
+
+ RequiresCapabilityAttr *RCA = ::new (S.Context)
+ RequiresCapabilityAttr(Attr.getRange(), S.Context, Args.data(),
+ Args.size(), Attr.getAttributeSpellingListIndex());
+
+ D->addAttr(RCA);
+}
+
/// Handles semantic checking for features that are common to all attributes,
/// such as checking whether a parameter was properly specified, or the correct
/// number of arguments were passed, etc.
case AttributeList::AT_NoSanitizeMemory:
handleSimpleAttribute<NoSanitizeMemoryAttr>(S, D, Attr);
break;
- case AttributeList::AT_Lockable:
- handleSimpleAttribute<LockableAttr>(S, D, Attr); break;
case AttributeList::AT_GuardedBy:
handleGuardedByAttr(S, D, Attr);
break;
case AttributeList::AT_ExclusiveLockFunction:
handleExclusiveLockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_ExclusiveLocksRequired:
- handleExclusiveLocksRequiredAttr(S, D, Attr);
- break;
case AttributeList::AT_ExclusiveTrylockFunction:
handleExclusiveTrylockFunctionAttr(S, D, Attr);
break;
case AttributeList::AT_SharedLockFunction:
handleSharedLockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_SharedLocksRequired:
- handleSharedLocksRequiredAttr(S, D, Attr);
- break;
case AttributeList::AT_SharedTrylockFunction:
handleSharedTrylockFunctionAttr(S, D, Attr);
break;
handleAcquiredAfterAttr(S, D, Attr);
break;
+ // Capability analysis attributes.
+ case AttributeList::AT_Capability:
+ case AttributeList::AT_Lockable:
+ handleCapabilityAttr(S, D, Attr); break;
+ case AttributeList::AT_RequiresCapability:\r
+ handleRequiresCapabilityAttr(S, D, Attr); break;\r
+
// Consumed analysis attributes.
case AttributeList::AT_Consumable:
handleConsumableAttr(S, D, Attr);
Arg = LR->getArg();
else if (LocksExcludedAttr *LE = dyn_cast<LocksExcludedAttr>(*A))
Args = ArrayRef<Expr *>(LE->args_begin(), LE->args_size());
- else if (ExclusiveLocksRequiredAttr *ELR
- = dyn_cast<ExclusiveLocksRequiredAttr>(*A))
- Args = ArrayRef<Expr *>(ELR->args_begin(), ELR->args_size());
- else if (SharedLocksRequiredAttr *SLR
- = dyn_cast<SharedLocksRequiredAttr>(*A))
- Args = ArrayRef<Expr *>(SLR->args_begin(), SLR->args_size());
+ else if (RequiresCapabilityAttr *RC
+ = dyn_cast<RequiresCapabilityAttr>(*A))
+ Args = ArrayRef<Expr *>(RC->args_begin(), RC->args_size());
if (Arg && !Finder.TraverseStmt(Arg))
return true;
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -Wthread-safety -verify %s\r
+\r
+struct __attribute__((capability("thread role"))) ThreadRole {};\r
+struct __attribute__((shared_capability("mutex"))) Mutex {};\r
+struct NotACapability {};\r
+\r
+int Test1 __attribute__((capability("test1"))); // expected-error {{'capability' attribute only applies to structs}}\r
+int Test2 __attribute__((shared_capability("test2"))); // expected-error {{'shared_capability' attribute only applies to structs}}\r
+\r
+struct __attribute__((capability(12))) Test3 {}; // expected-error {{'capability' attribute requires a string}}\r
+struct __attribute__((shared_capability(Test2))) Test4 {}; // expected-error {{'shared_capability' attribute requires a string}}\r
+\r
+struct __attribute__((capability)) Test5 {}; // expected-error {{'capability' attribute takes one argument}}\r
+struct __attribute__((shared_capability("test1", 12))) Test6 {}; // expected-error {{'shared_capability' attribute takes one argument}}\r
+\r
+struct NotACapability BadCapability;\r
+struct ThreadRole GUI, Worker;\r
+void Func1(void) __attribute__((requires_capability(GUI))) {}\r
+void Func2(void) __attribute__((requires_shared_capability(Worker))) {}\r
+\r
+void Func3(void) __attribute__((requires_capability)) {} // expected-error {{'requires_capability' attribute takes at least 1 argument}}\r
+void Func4(void) __attribute__((requires_shared_capability)) {} // expected-error {{'requires_shared_capability' attribute takes at least 1 argument}}\r
+\r
+void Func5(void) __attribute__((requires_capability(1))) {} // expected-warning {{'requires_capability' attribute requires arguments that are class type or point to class type}}\r
+void Func6(void) __attribute__((requires_shared_capability(BadCapability))) {} // expected-warning {{'requires_shared_capability' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'struct NotACapability'}}\r
int gb_var_arg_bad_3 GUARDED_BY(muDoublePointer); // \
// expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'Mutex **'}}
int gb_var_arg_bad_4 GUARDED_BY(umu); // \
- // expected-warning {{'guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute; type here is 'UnlockableMu'}}
+ // expected-warning {{'guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'UnlockableMu'}}
//3.
// Thread Safety analysis tests
int * pgb_var_arg_bad_3 PT_GUARDED_BY(muDoublePointer); // \
// expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
int * pgb_var_arg_bad_4 PT_GUARDED_BY(umu); // \
- // expected-warning {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute}}
//-----------------------------------------//
Mutex aa_var_arg_bad_3 ACQUIRED_AFTER(muDoublePointer); // \
// expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}}
Mutex aa_var_arg_bad_4 ACQUIRED_AFTER(umu); // \
- // expected-warning {{'acquired_after' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'acquired_after' attribute requires arguments whose type is annotated with 'capability' attribute}}
UnlockableMu aa_var_arg_bad_5 ACQUIRED_AFTER(mu_aa); // \
- // expected-warning {{'acquired_after' attribute can only be applied in a context annotated with 'lockable' attribute}}
+ // expected-warning {{'acquired_after' attribute can only be applied in a context annotated with 'capability("mutex")' attribute}}
//-----------------------------------------//
// Acquired Before (ab)
Mutex ab_var_arg_bad_3 ACQUIRED_BEFORE(muDoublePointer); // \
// expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}}
Mutex ab_var_arg_bad_4 ACQUIRED_BEFORE(umu); // \
- // expected-warning {{'acquired_before' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'acquired_before' attribute requires arguments whose type is annotated with 'capability' attribute}}
UnlockableMu ab_var_arg_bad_5 ACQUIRED_BEFORE(mu_ab); // \
- // expected-warning {{'acquired_before' attribute can only be applied in a context annotated with 'lockable' attribute}}
+ // expected-warning {{'acquired_before' attribute can only be applied in a context annotated with 'capability("mutex")' attribute}}
//-----------------------------------------//
int elf_function_bad_3() EXCLUSIVE_LOCK_FUNCTION(muDoublePointer); // \
// expected-warning {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
int elf_function_bad_4() EXCLUSIVE_LOCK_FUNCTION(umu); // \
- // expected-warning {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
int elf_function_bad_1() EXCLUSIVE_LOCK_FUNCTION(1); // \
// expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
int slf_function_bad_3() SHARED_LOCK_FUNCTION(muDoublePointer); // \
// expected-warning {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
int slf_function_bad_4() SHARED_LOCK_FUNCTION(umu); // \
- // expected-warning {{'shared_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'shared_lock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
int slf_function_bad_1() SHARED_LOCK_FUNCTION(1); // \
// expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
int etf_function_bad_5() EXCLUSIVE_TRYLOCK_FUNCTION(1, muDoublePointer); // \
// expected-warning {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
int etf_function_bad_6() EXCLUSIVE_TRYLOCK_FUNCTION(1, umu); // \
- // expected-warning {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
//-----------------------------------------//
int stf_function_bad_5() SHARED_TRYLOCK_FUNCTION(1, muDoublePointer); // \
// expected-warning {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
int stf_function_bad_6() SHARED_TRYLOCK_FUNCTION(1, umu); // \
- // expected-warning {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
//-----------------------------------------//
int uf_function_bad_3() UNLOCK_FUNCTION(muDoublePointer); // \
// expected-warning {{'unlock_function' attribute requires arguments that are class type or point to class type}}
int uf_function_bad_4() UNLOCK_FUNCTION(umu); // \
- // expected-warning {{'unlock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'unlock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
int uf_function_bad_1() UNLOCK_FUNCTION(1); // \
// expected-error {{'unlock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
int lr_function_bad_3() LOCK_RETURNED(muDoublePointer); // \
// expected-warning {{'lock_returned' attribute requires arguments that are class type or point to class type}}
int lr_function_bad_4() LOCK_RETURNED(umu); // \
- // expected-warning {{'lock_returned' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'lock_returned' attribute requires arguments whose type is annotated with 'capability' attribute}}
int le_function_bad_3() LOCKS_EXCLUDED(muDoublePointer); // \
// expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
int le_function_bad_4() LOCKS_EXCLUDED(umu); // \
- // expected-warning {{'locks_excluded' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'locks_excluded' attribute requires arguments whose type is annotated with 'capability' attribute}}
int elr_function_bad_3() EXCLUSIVE_LOCKS_REQUIRED(muDoublePointer); // \
// expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
int elr_function_bad_4() EXCLUSIVE_LOCKS_REQUIRED(umu); // \
- // expected-warning {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'capability' attribute}}
int slr_function_bad_3() SHARED_LOCKS_REQUIRED(muDoublePointer); // \
// expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
int slr_function_bad_4() SHARED_LOCKS_REQUIRED(umu); // \
- // expected-warning {{'shared_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+ // expected-warning {{'shared_locks_required' attribute requires arguments whose type is annotated with 'capability' attribute}}
//-----------------------------------------//
int a GUARDED_BY(mu1_);
int b GUARDED_BY(mu2_);
int c GUARDED_BY(mu3_); // \
- // expected-warning {{'guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute; type here is 'InheritanceTest::Derived3'}}
+ // expected-warning {{'guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'InheritanceTest::Derived3'}}
void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1_, mu2_) {
a = 0;