Skip to content

Commit 69e6e7c

Browse files
committedMar 24, 2014
Capability attributes can now be declared on a typedef declaration as well as a structure declaration. This allows for C code to use Boolean expressions on a capability as part of another attribute. Eg) __attribute__((requires_capability(!SomeCapability)))
llvm-svn: 204657
1 parent d23118c commit 69e6e7c

File tree

6 files changed

+91
-78
lines changed

6 files changed

+91
-78
lines changed
 

‎clang/include/clang/Basic/Attr.td

+2-1
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,8 @@ def Capability : InheritableAttr {
13021302
let Spellings = [GNU<"capability">, CXX11<"clang", "capability">,
13031303
GNU<"shared_capability">,
13041304
CXX11<"clang", "shared_capability">];
1305-
let Subjects = SubjectList<[Struct], ErrorDiag, "ExpectedStruct">;
1305+
let Subjects = SubjectList<[Struct, TypedefName], ErrorDiag,
1306+
"ExpectedStructOrTypedef">;
13061307
let Args = [StringArgument<"Name">];
13071308
let Accessors = [Accessor<"isShared",
13081309
[GNU<"shared_capability">,

‎clang/include/clang/Basic/DiagnosticSemaKinds.td

+1-5
Original file line numberDiff line numberDiff line change
@@ -2102,7 +2102,7 @@ def warn_attribute_wrong_decl_type : Warning<
21022102
"struct or union|struct, union or class|types|"
21032103
"Objective-C instance methods|init methods of interface or class extension declarations|"
21042104
"variables, functions and classes|Objective-C protocols|"
2105-
"functions and global variables}1">,
2105+
"functions and global variables|structs or typedefs}1">,
21062106
InGroup<IgnoredAttributes>;
21072107
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
21082108
def warn_type_attribute_wrong_type : Warning<
@@ -2180,10 +2180,6 @@ def warn_thread_attribute_argument_not_lockable : Warning<
21802180
"%0 attribute requires arguments whose type is annotated "
21812181
"with 'capability' attribute; type here is %1">,
21822182
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
2183-
def warn_thread_attribute_argument_not_class : Warning<
2184-
"%0 attribute requires arguments that are class type or point to"
2185-
" class type; type here is %1">,
2186-
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
21872183
def warn_thread_attribute_decl_not_lockable : Warning<
21882184
"%0 attribute can only be applied in a context annotated "
21892185
"with 'capability(\"mutex\")' attribute">,

‎clang/include/clang/Sema/AttributeList.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,8 @@ enum AttributeDeclKind {
838838
ExpectedObjCInterfaceDeclInitMethod,
839839
ExpectedFunctionVariableOrClass,
840840
ExpectedObjectiveCProtocol,
841-
ExpectedFunctionGlobalVarMethodOrProperty
841+
ExpectedFunctionGlobalVarMethodOrProperty,
842+
ExpectedStructOrTypedef
842843
};
843844

844845
} // end namespace clang

‎clang/lib/Sema/SemaDeclAttr.cpp

+60-45
Original file line numberDiff line numberDiff line change
@@ -363,63 +363,78 @@ static const RecordType *getRecordType(QualType QT) {
363363
return 0;
364364
}
365365

366-
367-
static bool checkBaseClassIsLockableCallback(const CXXBaseSpecifier *Specifier,
368-
CXXBasePath &Path, void *Unused) {
369-
const RecordType *RT = Specifier->getType()->getAs<RecordType>();
370-
return RT->getDecl()->hasAttr<CapabilityAttr>();
371-
}
372-
373-
374-
/// \brief Thread Safety Analysis: Checks that the passed in RecordType
375-
/// resolves to a lockable object.
376-
static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
377-
QualType Ty) {
366+
static bool checkRecordTypeForCapability(Sema &S, const AttributeList &Attr,
367+
QualType Ty) {
378368
const RecordType *RT = getRecordType(Ty);
379369

380-
// Warn if could not get record type for this argument.
381-
if (!RT) {
382-
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_class)
383-
<< Attr.getName() << Ty;
384-
return;
385-
}
370+
if (!RT)
371+
return false;
386372

387-
// Don't check for lockable if the class hasn't been defined yet.
373+
// Don't check for the capability if the class hasn't been defined yet.
388374
if (RT->isIncompleteType())
389-
return;
375+
return true;
390376

391-
// Allow smart pointers to be used as lockable objects.
377+
// Allow smart pointers to be used as capability objects.
392378
// FIXME -- Check the type that the smart pointer points to.
393379
if (threadSafetyCheckIsSmartPointer(S, RT))
394-
return;
380+
return true;
395381

396-
// Check if the type is lockable.
382+
// Check if the record itself has a capability.
397383
RecordDecl *RD = RT->getDecl();
398384
if (RD->hasAttr<CapabilityAttr>())
399-
return;
385+
return true;
400386

401-
// Else check if any base classes are lockable.
387+
// Else check if any base classes have a capability.
402388
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
403389
CXXBasePaths BPaths(false, false);
404-
if (CRD->lookupInBases(checkBaseClassIsLockableCallback, 0, BPaths))
405-
return;
390+
if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &P,
391+
void *) {
392+
return BS->getType()->getAs<RecordType>()
393+
->getDecl()->hasAttr<CapabilityAttr>();
394+
}, 0, BPaths))
395+
return true;
406396
}
397+
return false;
398+
}
399+
400+
static bool checkTypedefTypeForCapability(Sema &S, const AttributeList &Attr,
401+
QualType Ty) {
402+
const auto *TD = Ty->getAs<TypedefType>();
403+
if (!TD)
404+
return false;
405+
406+
TypedefNameDecl *TN = TD->getDecl();
407+
if (!TN)
408+
return false;
409+
410+
return TN->hasAttr<CapabilityAttr>();
411+
}
412+
413+
/// \brief Checks that the passed in type is qualified as a capability. This
414+
/// type can either be a struct, or a typedef to a built-in type (such as int).
415+
static void checkForCapability(Sema &S, const AttributeList &Attr,
416+
QualType Ty) {
417+
if (checkTypedefTypeForCapability(S, Attr, Ty))
418+
return;
419+
420+
if (checkRecordTypeForCapability(S, Attr, Ty))
421+
return;
407422

408423
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
409424
<< Attr.getName() << Ty;
410425
}
411426

412-
/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
413-
/// from Sidx, resolve to a lockable object.
427+
/// \brief Checks that all attribute arguments, starting from Sidx, resolve to
428+
/// a capability object.
414429
/// \param Sidx The attribute argument index to start checking with.
415430
/// \param ParamIdxOk Whether an argument can be indexing into a function
416431
/// parameter list.
417-
static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
418-
const AttributeList &Attr,
419-
SmallVectorImpl<Expr*> &Args,
420-
int Sidx = 0,
421-
bool ParamIdxOk = false) {
422-
for(unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
432+
static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
433+
const AttributeList &Attr,
434+
SmallVectorImpl<Expr *> &Args,
435+
int Sidx = 0,
436+
bool ParamIdxOk = false) {
437+
for (unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
423438
Expr *ArgExp = Attr.getArgAsExpr(Idx);
424439

425440
if (ArgExp->isTypeDependent()) {
@@ -455,7 +470,7 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
455470
if (DRE->getDecl()->isCXXInstanceMember())
456471
ArgTy = DRE->getDecl()->getType();
457472

458-
// First see if we can just cast to record type, or point to record type.
473+
// First see if we can just cast to record type, or pointer to record type.
459474
const RecordType *RT = getRecordType(ArgTy);
460475

461476
// Now check if we index into a record type function param.
@@ -476,7 +491,7 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
476491
}
477492
}
478493

479-
checkForLockableRecord(S, D, Attr, ArgTy);
494+
checkForCapability(S, Attr, ArgTy);
480495

481496
Args.push_back(ArgExp);
482497
}
@@ -505,7 +520,7 @@ static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
505520
Expr* &Arg) {
506521
SmallVector<Expr*, 1> Args;
507522
// check that all arguments are lockable objects
508-
checkAttrArgsAreLockableObjs(S, D, Attr, Args);
523+
checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
509524
unsigned Size = Args.size();
510525
if (Size != 1)
511526
return false;
@@ -556,7 +571,7 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
556571
}
557572

558573
// Check that all arguments are lockable objects.
559-
checkAttrArgsAreLockableObjs(S, D, Attr, Args);
574+
checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
560575
if (Args.empty())
561576
return false;
562577

@@ -594,7 +609,7 @@ static bool checkLockFunAttrCommon(Sema &S, Decl *D,
594609
SmallVectorImpl<Expr *> &Args) {
595610
// zero or more arguments ok
596611
// check that all arguments are lockable objects
597-
checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
612+
checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
598613

599614
return true;
600615
}
@@ -640,7 +655,7 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
640655
}
641656

642657
// check that all arguments are lockable objects
643-
checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1);
658+
checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 1);
644659

645660
return true;
646661
}
@@ -675,7 +690,7 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
675690
const AttributeList &Attr) {
676691
// check that the argument is lockable object
677692
SmallVector<Expr*, 1> Args;
678-
checkAttrArgsAreLockableObjs(S, D, Attr, Args);
693+
checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
679694
unsigned Size = Args.size();
680695
if (Size == 0)
681696
return;
@@ -692,7 +707,7 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
692707

693708
// check that all arguments are lockable objects
694709
SmallVector<Expr*, 1> Args;
695-
checkAttrArgsAreLockableObjs(S, D, Attr, Args);
710+
checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
696711
unsigned Size = Args.size();
697712
if (Size == 0)
698713
return;
@@ -3898,7 +3913,7 @@ static void handleReleaseCapabilityAttr(Sema &S, Decl *D,
38983913
const AttributeList &Attr) {
38993914
// Check that all arguments are lockable objects.
39003915
SmallVector<Expr *, 1> Args;
3901-
checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, true);
3916+
checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, true);
39023917

39033918
D->addAttr(::new (S.Context) ReleaseCapabilityAttr(
39043919
Attr.getRange(), S.Context, Args.data(), Args.size(),
@@ -3912,7 +3927,7 @@ static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
39123927

39133928
// check that all arguments are lockable objects
39143929
SmallVector<Expr*, 1> Args;
3915-
checkAttrArgsAreLockableObjs(S, D, Attr, Args);
3930+
checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
39163931
if (Args.empty())
39173932
return;
39183933

‎clang/test/Sema/attr-capabilities.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// RUN: %clang_cc1 -fsyntax-only -Wthread-safety -verify %s
22

3-
struct __attribute__((capability("role"))) ThreadRole {};
3+
typedef int __attribute__((capability("role"))) ThreadRole;
44
struct __attribute__((shared_capability("mutex"))) Mutex {};
55
struct NotACapability {};
66

77
// Test an invalid capability name
88
struct __attribute__((capability("wrong"))) IncorrectName {}; // expected-warning {{invalid capability name 'wrong'; capability name must be 'mutex' or 'role'}}
99

10-
int Test1 __attribute__((capability("test1"))); // expected-error {{'capability' attribute only applies to structs}}
11-
int Test2 __attribute__((shared_capability("test2"))); // expected-error {{'shared_capability' attribute only applies to structs}}
10+
int Test1 __attribute__((capability("test1"))); // expected-error {{'capability' attribute only applies to structs or typedefs}}
11+
int Test2 __attribute__((shared_capability("test2"))); // expected-error {{'shared_capability' attribute only applies to structs or typedefs}}
1212
int Test3 __attribute__((acquire_capability("test3"))); // expected-warning {{'acquire_capability' attribute only applies to functions}}
1313
int Test4 __attribute__((try_acquire_capability("test4"))); // expected-error {{'try_acquire_capability' attribute only applies to functions}}
1414
int Test5 __attribute__((release_capability("test5"))); // expected-warning {{'release_capability' attribute only applies to functions}}
@@ -20,14 +20,14 @@ struct __attribute__((capability)) Test5 {}; // expected-error {{'capability' at
2020
struct __attribute__((shared_capability("test1", 12))) Test6 {}; // expected-error {{'shared_capability' attribute takes one argument}}
2121

2222
struct NotACapability BadCapability;
23-
struct ThreadRole GUI, Worker;
23+
ThreadRole GUI, Worker;
2424
void Func1(void) __attribute__((requires_capability(GUI))) {}
2525
void Func2(void) __attribute__((requires_shared_capability(Worker))) {}
2626

2727
void Func3(void) __attribute__((requires_capability)) {} // expected-error {{'requires_capability' attribute takes at least 1 argument}}
2828
void Func4(void) __attribute__((requires_shared_capability)) {} // expected-error {{'requires_shared_capability' attribute takes at least 1 argument}}
2929

30-
void Func5(void) __attribute__((requires_capability(1))) {} // expected-warning {{'requires_capability' attribute requires arguments that are class type or point to class type}}
30+
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'}}
3131
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'}}
3232

3333
void Func7(void) __attribute__((assert_capability(GUI))) {}

0 commit comments

Comments
 (0)
Please sign in to comment.