From: Aaron Ballman Date: Fri, 21 Feb 2014 21:05:14 +0000 (+0000) Subject: Adding role-based capability attributes that allow you to express role management... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e81eb42ceb255a6fc0f2804adcb128dd04c4bbb2;p=clang Adding role-based capability attributes that allow you to express role management: asserting a capability is held, acquiring a capability and releasing a capability. Also includes some skeleton documentation for these new attributes. This functionality should be considered a WIP. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201890 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 3b70c4cc3e..148de47206 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -1302,6 +1302,82 @@ def Capability : InheritableAttr { let Documentation = [Undocumented]; } +def AssertCapability : InheritableAttr { + let Spellings = [GNU<"assert_capability">, + CXX11<"clang", "assert_capability">, + GNU<"assert_shared_capability">, + CXX11<"clang", "assert_shared_capability">]; + let Subjects = SubjectList<[Function, FunctionTemplate]>; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Args = [ExprArgument<"Expr">]; + let Accessors = [Accessor<"isShared", + [GNU<"assert_shared_capability">, + CXX11<"clang", "assert_shared_capability">]>]; + let Documentation = [AssertCapabilityDocs]; +} + +def AcquireCapability : InheritableAttr { + let Spellings = [GNU<"acquire_capability">, + CXX11<"clang", "acquire_capability">, + GNU<"acquire_shared_capability">, + CXX11<"clang", "acquire_shared_capability">]; + let Subjects = SubjectList<[Function, FunctionTemplate], + ErrorDiag>; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Args = [VariadicExprArgument<"Args">]; + let Accessors = [Accessor<"isShared", + [GNU<"acquire_shared_capability">, + CXX11<"clang", "acquire_shared_capability">]>]; + let Documentation = [AcquireCapabilityDocs]; +} + +def TryAcquireCapability : InheritableAttr { + let Spellings = [GNU<"try_acquire_capability">, + CXX11<"clang", "try_acquire_capability">, + GNU<"try_acquire_shared_capability">, + CXX11<"clang", "try_acquire_shared_capability">]; + let Subjects = SubjectList<[Function, FunctionTemplate], + ErrorDiag>; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; + let Accessors = [Accessor<"isShared", + [GNU<"try_acquire_shared_capability">, + CXX11<"clang", "try_acquire_shared_capability">]>]; + let Documentation = [TryAcquireCapabilityDocs]; +} + +def ReleaseCapability : InheritableAttr { + let Spellings = [GNU<"release_capability">, + CXX11<"clang", "release_capability">, + GNU<"release_shared_capability">, + CXX11<"clang", "release_shared_capability">, + GNU<"release_generic_capability">, + CXX11<"clang", "release_generic_capability">]; + let Subjects = SubjectList<[Function, FunctionTemplate], + ErrorDiag>; + let LateParsed = 1; + let TemplateDependent = 1; + let ParseArgumentsAsUnevaluated = 1; + let DuplicatesAllowedWhileMerging = 1; + let Args = [VariadicExprArgument<"Args">]; + let Accessors = [Accessor<"isShared", + [GNU<"release_shared_capability">, + CXX11<"clang", "release_shared_capability">]>, + Accessor<"isGeneric", + [GNU<"release_generic_capability">, + CXX11<"clang", "release_generic_capability">]>]; + let Documentation = [ReleaseCapabilityDocs]; +} + def RequiresCapability : InheritableAttr { let Spellings = [GNU<"requires_capability">, CXX11<"clang", "requires_capability">, diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index a2476e43ac..c0f0fbcea1 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -77,6 +77,37 @@ that appears to be capable of returning to its caller. }]; } +def AssertCapabilityDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Marks a function that dynamically tests whether a capability is held, and halts +the program if it is not held. + }]; +} + +def AcquireCapabilityDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Marks a function as acquiring a capability. + }]; +} + +def TryAcquireCapabilityDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Marks a function that attemps to aquire a capability. This function may fail to +actually acquire the capability; they accept a Boolean value determining +whether acquiring the capability means success (true), or failing to acquire +the capability means success (false). + }]; +} + +def ReleaseCapabilityDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Marks a function as releasing a capability. + }]; +} def EnableIfDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index ef19a0b992..19b7955548 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -3905,6 +3905,61 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleAssertCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context, + Attr.getArgAsExpr(0), + Attr.getAttributeSpellingListIndex())); +} + +static void handleAcquireCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + SmallVector Args; + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // Check that all arguments are lockable objects. + checkAttrArgsAreLockableObjs(S, D, Attr, Args); + if (Args.empty()) + return; + + D->addAttr(::new (S.Context) AcquireCapabilityAttr(Attr.getRange(), + S.Context, + Args.data(), Args.size(), + Attr.getAttributeSpellingListIndex())); +} + +static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + SmallVector Args; + if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + return; + + D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(Attr.getRange(), + S.Context, + Attr.getArgAsExpr(0), + Args.data(), + Args.size(), + Attr.getAttributeSpellingListIndex())); +} + +static void handleReleaseCapabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + SmallVector Args; + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // Check that all arguments are lockable objects. + checkAttrArgsAreLockableObjs(S, D, Attr, Args); + if (Args.empty()) + return; + + D->addAttr(::new (S.Context) ReleaseCapabilityAttr(Attr.getRange(), + S.Context, + Args.data(), Args.size(), + Attr.getAttributeSpellingListIndex())); +} + static void handleRequiresCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) @@ -4275,8 +4330,17 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_Capability: case AttributeList::AT_Lockable: handleCapabilityAttr(S, D, Attr); break; - case AttributeList::AT_RequiresCapability: - handleRequiresCapabilityAttr(S, D, Attr); break; + case AttributeList::AT_RequiresCapability: + handleRequiresCapabilityAttr(S, D, Attr); break; + + case AttributeList::AT_AssertCapability: + handleAssertCapabilityAttr(S, D, Attr); break; + case AttributeList::AT_AcquireCapability: + handleAcquireCapabilityAttr(S, D, Attr); break; + case AttributeList::AT_ReleaseCapability: + handleReleaseCapabilityAttr(S, D, Attr); break; + case AttributeList::AT_TryAcquireCapability: + handleTryAcquireCapabilityAttr(S, D, Attr); break; // Consumed analysis attributes. case AttributeList::AT_Consumable: diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e4967f899e..d98a01d33f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12752,6 +12752,13 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { else if (RequiresCapabilityAttr *RC = dyn_cast(*A)) Args = ArrayRef(RC->args_begin(), RC->args_size()); + else if (AcquireCapabilityAttr *AC = dyn_cast(*A)) + Args = ArrayRef(AC->args_begin(), AC->args_size()); + else if (TryAcquireCapabilityAttr *AC + = dyn_cast(*A)) + Args = ArrayRef(AC->args_begin(), AC->args_size()); + else if (ReleaseCapabilityAttr *RC = dyn_cast(*A)) + Args = ArrayRef(RC->args_begin(), RC->args_size()); if (Arg && !Finder.TraverseStmt(Arg)) return true; diff --git a/test/Sema/attr-capabilities.c b/test/Sema/attr-capabilities.c index fa3a3fab25..7a83403934 100644 --- a/test/Sema/attr-capabilities.c +++ b/test/Sema/attr-capabilities.c @@ -6,6 +6,9 @@ struct NotACapability {}; 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 Test3 __attribute__((acquire_capability("test3"))); // expected-error {{'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-error {{'release_capability' attribute only applies to functions}} struct __attribute__((capability(12))) Test3 {}; // expected-error {{'capability' attribute requires a string}} struct __attribute__((shared_capability(Test2))) Test4 {}; // expected-error {{'shared_capability' attribute requires a string}} @@ -23,3 +26,32 @@ void Func4(void) __attribute__((requires_shared_capability)) {} // expected-err void Func5(void) __attribute__((requires_capability(1))) {} // expected-warning {{'requires_capability' attribute requires arguments that are class type or point to class type}} 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))) {} +void Func8(void) __attribute__((assert_shared_capability(GUI))) {} + +void Func9(void) __attribute__((assert_capability())) {} // expected-error {{'assert_capability' attribute takes one argument}} +void Func10(void) __attribute__((assert_shared_capability())) {} // expected-error {{'assert_shared_capability' attribute takes one argument}} + +void Func11(void) __attribute__((acquire_capability(GUI))) {} +void Func12(void) __attribute__((acquire_shared_capability(GUI))) {} + +void Func13(void) __attribute__((acquire_capability())) {} // expected-error {{'acquire_capability' attribute takes at least 1 argument}} +void Func14(void) __attribute__((acquire_shared_capability())) {} // expected-error {{'acquire_shared_capability' attribute takes at least 1 argument}} + +void Func15(void) __attribute__((release_capability(GUI))) {} +void Func16(void) __attribute__((release_shared_capability(GUI))) {} +void Func17(void) __attribute__((release_generic_capability(GUI))) {} + +void Func18(void) __attribute__((release_capability())) {} // expected-error {{'release_capability' attribute takes at least 1 argument}} +void Func19(void) __attribute__((release_shared_capability())) {} // expected-error {{'release_shared_capability' attribute takes at least 1 argument}} +void Func20(void) __attribute__((release_generic_capability())) {} // expected-error {{'release_generic_capability' attribute takes at least 1 argument}} + +void Func21(void) __attribute__((try_acquire_capability(1))) {} +void Func22(void) __attribute__((try_acquire_shared_capability(1))) {} + +void Func23(void) __attribute__((try_acquire_capability(1, GUI))) {} +void Func24(void) __attribute__((try_acquire_shared_capability(1, GUI))) {} + +void Func25(void) __attribute__((try_acquire_capability())) {} // expected-error {{'try_acquire_capability' attribute takes at least 1 argument}} +void Func26(void) __attribute__((try_acquire_shared_capability())) {} // expected-error {{'try_acquire_shared_capability' attribute takes at least 1 argument}} \ No newline at end of file