let Spellings = [GNU<"capability">, CXX11<"clang", "capability">,
GNU<"shared_capability">,
CXX11<"clang", "shared_capability">];
- let Subjects = SubjectList<[Struct], ErrorDiag, "ExpectedStruct">;
+ let Subjects = SubjectList<[Struct, TypedefName], ErrorDiag,
+ "ExpectedStructOrTypedef">;
let Args = [StringArgument<"Name">];
let Accessors = [Accessor<"isShared",
[GNU<"shared_capability">,
"struct or union|struct, union or class|types|"
"Objective-C instance methods|init methods of interface or class extension declarations|"
"variables, functions and classes|Objective-C protocols|"
- "functions and global variables}1">,
+ "functions and global variables|structs or typedefs}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
"%0 attribute requires arguments whose type is annotated "
"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"
- " class type; type here is %1">,
- InGroup<ThreadSafetyAttributes>, DefaultIgnore;
def warn_thread_attribute_decl_not_lockable : Warning<
"%0 attribute can only be applied in a context annotated "
"with 'capability(\"mutex\")' attribute">,
ExpectedObjCInterfaceDeclInitMethod,
ExpectedFunctionVariableOrClass,
ExpectedObjectiveCProtocol,
- ExpectedFunctionGlobalVarMethodOrProperty
+ ExpectedFunctionGlobalVarMethodOrProperty,
+ ExpectedStructOrTypedef
};
} // end namespace clang
return 0;
}
-
-static bool checkBaseClassIsLockableCallback(const CXXBaseSpecifier *Specifier,
- CXXBasePath &Path, void *Unused) {
- const RecordType *RT = Specifier->getType()->getAs<RecordType>();
- return RT->getDecl()->hasAttr<CapabilityAttr>();
-}
-
-
-/// \brief Thread Safety Analysis: Checks that the passed in RecordType
-/// resolves to a lockable object.
-static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
- QualType Ty) {
+static bool checkRecordTypeForCapability(Sema &S, const AttributeList &Attr,
+ QualType Ty) {
const RecordType *RT = getRecordType(Ty);
- // Warn if could not get record type for this argument.
- if (!RT) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_class)
- << Attr.getName() << Ty;
- return;
- }
+ if (!RT)
+ return false;
- // Don't check for lockable if the class hasn't been defined yet.
+ // Don't check for the capability if the class hasn't been defined yet.
if (RT->isIncompleteType())
- return;
+ return true;
- // Allow smart pointers to be used as lockable objects.
+ // Allow smart pointers to be used as capability objects.
// FIXME -- Check the type that the smart pointer points to.
if (threadSafetyCheckIsSmartPointer(S, RT))
- return;
+ return true;
- // Check if the type is lockable.
+ // Check if the record itself has a capability.
RecordDecl *RD = RT->getDecl();
if (RD->hasAttr<CapabilityAttr>())
- return;
+ return true;
- // Else check if any base classes are lockable.
+ // Else check if any base classes have a capability.
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
CXXBasePaths BPaths(false, false);
- if (CRD->lookupInBases(checkBaseClassIsLockableCallback, 0, BPaths))
- return;
+ if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &P,
+ void *) {
+ return BS->getType()->getAs<RecordType>()
+ ->getDecl()->hasAttr<CapabilityAttr>();
+ }, 0, BPaths))
+ return true;
}
+ return false;
+}
+
+static bool checkTypedefTypeForCapability(Sema &S, const AttributeList &Attr,
+ QualType Ty) {
+ const auto *TD = Ty->getAs<TypedefType>();
+ if (!TD)
+ return false;
+
+ TypedefNameDecl *TN = TD->getDecl();
+ if (!TN)
+ return false;
+
+ return TN->hasAttr<CapabilityAttr>();
+}
+
+/// \brief Checks that the passed in type is qualified as a capability. This
+/// type can either be a struct, or a typedef to a built-in type (such as int).
+static void checkForCapability(Sema &S, const AttributeList &Attr,
+ QualType Ty) {
+ if (checkTypedefTypeForCapability(S, Attr, Ty))
+ return;
+
+ if (checkRecordTypeForCapability(S, Attr, Ty))
+ return;
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
<< Attr.getName() << Ty;
}
-/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
-/// from Sidx, resolve to a lockable object.
+/// \brief Checks that all attribute arguments, starting from Sidx, resolve to
+/// a capability object.
/// \param Sidx The attribute argument index to start checking with.
/// \param ParamIdxOk Whether an argument can be indexing into a function
/// parameter list.
-static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
- const AttributeList &Attr,
- SmallVectorImpl<Expr*> &Args,
- int Sidx = 0,
- bool ParamIdxOk = false) {
- for(unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
+static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVectorImpl<Expr *> &Args,
+ int Sidx = 0,
+ bool ParamIdxOk = false) {
+ for (unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
Expr *ArgExp = Attr.getArgAsExpr(Idx);
if (ArgExp->isTypeDependent()) {
if (DRE->getDecl()->isCXXInstanceMember())
ArgTy = DRE->getDecl()->getType();
- // First see if we can just cast to record type, or point to record type.
+ // First see if we can just cast to record type, or pointer to record type.
const RecordType *RT = getRecordType(ArgTy);
// Now check if we index into a record type function param.
}
}
- checkForLockableRecord(S, D, Attr, ArgTy);
+ checkForCapability(S, Attr, ArgTy);
Args.push_back(ArgExp);
}
Expr* &Arg) {
SmallVector<Expr*, 1> Args;
// check that all arguments are lockable objects
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
unsigned Size = Args.size();
if (Size != 1)
return false;
}
// Check that all arguments are lockable objects.
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
if (Args.empty())
return false;
SmallVectorImpl<Expr *> &Args) {
// zero or more arguments ok
// check that all arguments are lockable objects
- checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
return true;
}
}
// check that all arguments are lockable objects
- checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 1);
return true;
}
const AttributeList &Attr) {
// check that the argument is lockable object
SmallVector<Expr*, 1> Args;
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
unsigned Size = Args.size();
if (Size == 0)
return;
// check that all arguments are lockable objects
SmallVector<Expr*, 1> Args;
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
unsigned Size = Args.size();
if (Size == 0)
return;
const AttributeList &Attr) {
// Check that all arguments are lockable objects.
SmallVector<Expr *, 1> Args;
- checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, true);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, true);
D->addAttr(::new (S.Context) ReleaseCapabilityAttr(
Attr.getRange(), S.Context, Args.data(), Args.size(),
// check that all arguments are lockable objects
SmallVector<Expr*, 1> Args;
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
if (Args.empty())
return;
// RUN: %clang_cc1 -fsyntax-only -Wthread-safety -verify %s
-struct __attribute__((capability("role"))) ThreadRole {};
+typedef int __attribute__((capability("role"))) ThreadRole;
struct __attribute__((shared_capability("mutex"))) Mutex {};
struct NotACapability {};
// Test an invalid capability name
struct __attribute__((capability("wrong"))) IncorrectName {}; // expected-warning {{invalid capability name 'wrong'; capability name must be 'mutex' or 'role'}}
-int Test1 __attribute__((capability("test1"))); // expected-error {{'capability' attribute only applies to structs}}
-int Test2 __attribute__((shared_capability("test2"))); // expected-error {{'shared_capability' attribute only applies to structs}}
+int Test1 __attribute__((capability("test1"))); // expected-error {{'capability' attribute only applies to structs or typedefs}}
+int Test2 __attribute__((shared_capability("test2"))); // expected-error {{'shared_capability' attribute only applies to structs or typedefs}}
int Test3 __attribute__((acquire_capability("test3"))); // expected-warning {{'acquire_capability' attribute only applies to functions}}
int Test4 __attribute__((try_acquire_capability("test4"))); // expected-error {{'try_acquire_capability' attribute only applies to functions}}
int Test5 __attribute__((release_capability("test5"))); // expected-warning {{'release_capability' attribute only applies to functions}}
struct __attribute__((shared_capability("test1", 12))) Test6 {}; // expected-error {{'shared_capability' attribute takes one argument}}
struct NotACapability BadCapability;
-struct ThreadRole GUI, Worker;
+ThreadRole GUI, Worker;
void Func1(void) __attribute__((requires_capability(GUI))) {}
void Func2(void) __attribute__((requires_shared_capability(Worker))) {}
void Func3(void) __attribute__((requires_capability)) {} // expected-error {{'requires_capability' attribute takes at least 1 argument}}
void Func4(void) __attribute__((requires_shared_capability)) {} // expected-error {{'requires_shared_capability' attribute takes at least 1 argument}}
-void Func5(void) __attribute__((requires_capability(1))) {} // expected-warning {{'requires_capability' attribute requires arguments that are class type or point to class type}}
+void Func5(void) __attribute__((requires_capability(1))) {} // expected-warning {{'requires_capability' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
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'}}
void Func7(void) __attribute__((assert_capability(GUI))) {}
// illegal attribute arguments
int gb_var_arg_bad_1 GUARDED_BY(1); // \
- // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'int'}}
+ // expected-warning {{'guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
int gb_var_arg_bad_2 GUARDED_BY("mu"); // \
// expected-warning {{ignoring 'guarded_by' attribute because its argument is invalid}}
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 **'}}
+ // expected-warning {{'guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute; 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 'capability' attribute; type here is 'UnlockableMu'}}
// illegal attribute arguments
int * pgb_var_arg_bad_1 PT_GUARDED_BY(1); // \
- // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
int * pgb_var_arg_bad_2 PT_GUARDED_BY("mu"); // \
// expected-warning {{ignoring 'pt_guarded_by' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int * pgb_var_arg_bad_4 PT_GUARDED_BY(umu); // \
// expected-warning {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute}}
// illegal attribute arguments
Mutex aa_var_arg_bad_1 ACQUIRED_AFTER(1); // \
- // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'acquired_after' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
Mutex aa_var_arg_bad_2 ACQUIRED_AFTER("mu"); // \
// expected-warning {{ignoring 'acquired_after' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'acquired_after' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
Mutex aa_var_arg_bad_4 ACQUIRED_AFTER(umu); // \
// expected-warning {{'acquired_after' attribute requires arguments whose type is annotated with 'capability' attribute}}
UnlockableMu aa_var_arg_bad_5 ACQUIRED_AFTER(mu_aa); // \
// illegal attribute arguments
Mutex ab_var_arg_bad_1 ACQUIRED_BEFORE(1); // \
- // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'acquired_before' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
Mutex ab_var_arg_bad_2 ACQUIRED_BEFORE("mu"); // \
// expected-warning {{ignoring 'acquired_before' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'acquired_before' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
Mutex ab_var_arg_bad_4 ACQUIRED_BEFORE(umu); // \
// expected-warning {{'acquired_before' attribute requires arguments whose type is annotated with 'capability' attribute}}
UnlockableMu ab_var_arg_bad_5 ACQUIRED_BEFORE(mu_ab); // \
int elf_function_bad_2() EXCLUSIVE_LOCK_FUNCTION("mu"); // \
// expected-warning {{ignoring 'exclusive_lock_function' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int elf_function_bad_4() EXCLUSIVE_LOCK_FUNCTION(umu); // \
// expected-warning {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
int slf_function_bad_2() SHARED_LOCK_FUNCTION("mu"); // \
// expected-warning {{ignoring 'shared_lock_function' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'shared_lock_function' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int slf_function_bad_4() SHARED_LOCK_FUNCTION(umu); // \
// expected-warning {{'shared_lock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
int etf_function_bad_4() EXCLUSIVE_TRYLOCK_FUNCTION(1, "mu"); // \
// expected-warning {{ignoring 'exclusive_trylock_function' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int etf_function_bad_6() EXCLUSIVE_TRYLOCK_FUNCTION(1, umu); // \
// expected-warning {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
int stf_function_bad_4() SHARED_TRYLOCK_FUNCTION(1, "mu"); // \
// expected-warning {{ignoring 'shared_trylock_function' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int stf_function_bad_6() SHARED_TRYLOCK_FUNCTION(1, umu); // \
// expected-warning {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
int uf_function_bad_2() UNLOCK_FUNCTION("mu"); // \
// expected-warning {{ignoring 'unlock_function' attribute because its argument is invalid}}
int uf_function_bad_3() UNLOCK_FUNCTION(muDoublePointer); // \
- // expected-warning {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'unlock_function' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int uf_function_bad_4() UNLOCK_FUNCTION(umu); // \
// expected-warning {{'unlock_function' attribute requires arguments whose type is annotated with 'capability' attribute}}
// illegal attribute arguments
int lr_function_bad_1() LOCK_RETURNED(1); // \
- // expected-warning {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'lock_returned' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
int lr_function_bad_2() LOCK_RETURNED("mu"); // \
// expected-warning {{ignoring 'lock_returned' attribute because its argument is invalid}}
int lr_function_bad_3() LOCK_RETURNED(muDoublePointer); // \
- // expected-warning {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'lock_returned' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int lr_function_bad_4() LOCK_RETURNED(umu); // \
// expected-warning {{'lock_returned' attribute requires arguments whose type is annotated with 'capability' attribute}}
// illegal attribute arguments
int le_function_bad_1() LOCKS_EXCLUDED(1); // \
- // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'locks_excluded' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
int le_function_bad_2() LOCKS_EXCLUDED("mu"); // \
// expected-warning {{ignoring 'locks_excluded' attribute because its argument is invalid}}
int le_function_bad_3() LOCKS_EXCLUDED(muDoublePointer); // \
- // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'locks_excluded' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int le_function_bad_4() LOCKS_EXCLUDED(umu); // \
// expected-warning {{'locks_excluded' attribute requires arguments whose type is annotated with 'capability' attribute}}
// illegal attribute arguments
int elr_function_bad_1() EXCLUSIVE_LOCKS_REQUIRED(1); // \
- // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
int elr_function_bad_2() EXCLUSIVE_LOCKS_REQUIRED("mu"); // \
// expected-warning {{ignoring 'exclusive_locks_required' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int elr_function_bad_4() EXCLUSIVE_LOCKS_REQUIRED(umu); // \
// expected-warning {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'capability' attribute}}
// illegal attribute arguments
int slr_function_bad_1() SHARED_LOCKS_REQUIRED(1); // \
- // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+ // expected-warning {{'shared_locks_required' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
int slr_function_bad_2() SHARED_LOCKS_REQUIRED("mu"); // \
// expected-warning {{ignoring 'shared_locks_required' attribute because its argument is invalid}}
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}}
+ // expected-warning {{'shared_locks_required' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'Mutex **'}}
int slr_function_bad_4() SHARED_LOCKS_REQUIRED(umu); // \
// expected-warning {{'shared_locks_required' attribute requires arguments whose type is annotated with 'capability' attribute}}