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/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3072,6 +3072,8 @@ def err_cconv_incomplete_param_type : Error< "parameter %0 must have a complete type to use function %1 with the %2 " "calling convention">; +def err_attribute_output_parameter : Error< + "attribute only applies to output parameters">; def ext_cannot_use_trivial_abi : ExtWarn< "'trivial_abi' cannot be applied to %0">, InGroup; Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -6518,6 +6518,18 @@ handleSimpleAttribute(S, D, AL); } +static void handeAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Warn if the parameter is definitely not an output parameter. + if (auto *PVD = dyn_cast(D)) { + if (PVD->getType()->isIntegerType()) { + S.Diag(AL.getLoc(), diag::err_attribute_output_parameter) + << AL.getRange(); + return; + } + } + handleSimpleAttribute(S, D, AL); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -7282,6 +7294,16 @@ case ParsedAttr::AT_ArmMveAlias: handleArmMveAliasAttr(S, D, AL); break; + + case ParsedAttr::AT_AcquireHandle: + handeAcquireHandleAttr(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) Index: clang/test/Sema/attr-acquire_handle.c =================================================================== --- /dev/null +++ clang/test/Sema/attr-acquire_handle.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +void f(int *a __attribute__((acquire_handle))); +void g(int a __attribute__((acquire_handle))); // expected-error {{attribute only applies to output parameters}}