Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3439,3 +3439,19 @@ let Subjects = SubjectList<[Function]>; let Documentation = [NoBuiltinDocs]; } + +def AcquireHandle : InheritableAttr { + let Spellings = [Clang<"acquire_handle">]; + let Subjects = SubjectList<[Function, ParmVar], ErrorDiag>; + let Documentation = [AcquireHandleDocs]; +} + +def UseHandle : InheritableParamAttr { + let Spellings = [Clang<"use_handle">]; + let Documentation = [UseHandleDocs]; +} + +def ReleaseHandle : InheritableParamAttr { + let Spellings = [Clang<"release_handle">]; + let Documentation = [ReleaseHandleDocs]; +} Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -4467,3 +4467,50 @@ } }]; } + +def AcquireHandleDocs : Documentation { + let Category = DocCatDecl; + let Content = [{ +If this annotation is on a function it is assumed to return a new handle. +In case this annotation is on an output parameter, the function is assumed +to fill the corresponding argument with a new handle. + +.. code-block:: c++ + + // Output arguments from Zircon. + zx_status_t zx_socket_create(uint32_t options, + zx_handle_t* out0 [[clang::acquire_handle]], + zx_handle_t* out1 [[clang::acquire_handle]]); + + + // Returned handle. + [[clang::acquire_handle]] int open(const char *path, int oflag, ... ); + }]; +} + +def UseHandleDocs : Documentation { + let Category = DocCatDecl; + let Content = [{ +A function taking a handle by value might close the handle. If a function is +annotated with `use_handle` it is assumed to not to change the state of the +handle. It is also assumed to require an open handle to work with. + +.. code-block:: c++ + + zx_status_t zx_port_wait(zx_handle_t handle [[clang::use_handle]], + zx_time_t deadline, + zx_port_packet_t* packet); + }]; +} + +def ReleaseHandleDocs : Documentation { + let Category = DocCatDecl; + let Content = [{ +If a function is annotated with `release_handle` it is assumed to close the handle. +It is also assumed to require an open handle to work with. + +.. code-block:: c++ + + zx_status_t zx_handle_close(zx_handle_t handle [[clang::release_handle]]); + }]; +} Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -7282,6 +7282,16 @@ case ParsedAttr::AT_ArmMveAlias: handleArmMveAliasAttr(S, D, AL); break; + + case ParsedAttr::AT_AcquireHandle: + handleSimpleAttribute(S, D, AL); + break; + case ParsedAttr::AT_ReleaseHandle: + handleSimpleAttribute(S, D, AL); + break; + case ParsedAttr::AT_UseHandle: + handleSimpleAttribute(S, D, AL); + break; } } Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -9,6 +9,7 @@ // CHECK-NEXT: AMDGPUWavesPerEU (SubjectMatchRule_function) // CHECK-NEXT: AVRSignal (SubjectMatchRule_function) // CHECK-NEXT: AbiTag (SubjectMatchRule_record_not_is_union, SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_namespace) +// CHECK-NEXT: AcquireHandle (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: Alias (SubjectMatchRule_function, SubjectMatchRule_variable_is_global) // CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias) // CHECK-NEXT: AllocSize (SubjectMatchRule_function)