Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -1307,6 +1307,12 @@ let Documentation = [Undocumented]; } +def MIGServerRoutine : InheritableAttr { + let Spellings = [Clang<"mig_server_routine">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [MIGCallingConventionDocs]; +} + def MSABI : DeclOrTypeAttr { let Spellings = [GCC<"ms_abi">]; // let Subjects = [Function, ObjCMethod]; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -4028,3 +4028,23 @@ When compiled without ``-fobjc-arc``, this attribute is ignored. }]; } + +def MIGCallingConventionDocs : Documentation { + let Category = DocCatType; + let Content = [{ + The Mach Interface Generator release-on-success calling convention dictates +functions that follow it to only release arguments passed to them when they +return "success" (a ``kern_return_t`` error code that indicates that +no errors have occured). Otherwise the release is performed by the MIG client +that called the function. The annotation ``__attribute__((mig_server_routine))`` +is applied in order to specify which functions are affected by the calling +convention. This allows the Static Analyzer to find bugs caused by violations of +that convention. The attribute would normally appear on the forward declaration +of the actual server routine in the MIG server header, but it may also be +added to arbitrary functions that need to follow the same convention - for +example, a user can add them to auxiliary functions called by the server routine +that have their return value of type ``kern_return_t`` unconditionally returned +from the routine. The attribute can be applied to C++ methods, and in this case +it will be automatically applied to overrides if the method is virtual. +}]; +} Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8696,6 +8696,11 @@ def ext_opencl_ext_vector_type_rgba_selector: ExtWarn< "vector component name '%0' is an OpenCL version 2.2 feature">, InGroup; + +// MIG routine annotations. +def warn_mig_server_routine_does_not_return_kern_return_t : Warning< + "'%0' attribute only applies to functions that return a kernel return code">, + InGroup; } // end of sema category let CategoryName = "OpenMP Issue" in { Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -6396,6 +6396,25 @@ handleSimpleAttribute(S, D, AL); } +static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Check that the return type is a `typedef int kern_return_t` or a typedef + // around it, because otherwise calling convention checks make no sense. + QualType T = cast(D)->getReturnType(); + bool IsKernReturnT = false; + while (const auto *TT = T->getAs()) { + IsKernReturnT = (TT->getDecl()->getName() == "kern_return_t"); + T = TT->desugar(); + } + if (!IsKernReturnT || T.getCanonicalType() != S.getASTContext().IntTy) { + S.Diag(D->getBeginLoc(), + diag::warn_mig_server_routine_does_not_return_kern_return_t) + << AL.getName()->getName(); + return; + } + + handleSimpleAttribute(S, D, AL); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -7119,6 +7138,11 @@ case ParsedAttr::AT_ObjCExternallyRetained: handleObjCExternallyRetainedAttr(S, D, AL); break; + + // Mach Interface Generator annotations. + case ParsedAttr::AT_MIGServerRoutine: + handleMIGServerRoutineAttr(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 @@ -60,6 +60,7 @@ // CHECK-NEXT: InternalLinkage (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record) // CHECK-NEXT: LTOVisibilityPublic (SubjectMatchRule_record) // CHECK-NEXT: Lockable (SubjectMatchRule_record) +// CHECK-NEXT: MIGServerRoutine (SubjectMatchRule_function) // CHECK-NEXT: MSStruct (SubjectMatchRule_record) // CHECK-NEXT: MicroMips (SubjectMatchRule_function) // CHECK-NEXT: MinSize (SubjectMatchRule_function, SubjectMatchRule_objc_method) Index: clang/test/Sema/attr-mig.c =================================================================== --- /dev/null +++ clang/test/Sema/attr-mig.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +typedef int kern_return_t; +#define KERN_SUCCESS 0 + +__attribute__((mig_server_routine)) kern_return_t var = KERN_SUCCESS; // expected-warning-re{{'mig_server_routine' attribute only applies to functions{{$}}}} + +__attribute__((mig_server_routine)) void foo_void(); // expected-warning{{'mig_server_routine' attribute only applies to functions that return a kernel return code}} +__attribute__((mig_server_routine)) int foo_int(); // expected-warning{{'mig_server_routine' attribute only applies to functions that return a kernel return code}} + +__attribute__((mig_server_routine)) kern_return_t bar_extern(); // no-warning +__attribute__((mig_server_routine)) kern_return_t bar_forward(); // no-warning + +__attribute__((mig_server_routine)) kern_return_t bar_definition() { // no-warning + return KERN_SUCCESS; +} + +kern_return_t bar_forward() { // no-warning + return KERN_SUCCESS; +} Index: clang/test/Sema/attr-mig.cpp =================================================================== --- /dev/null +++ clang/test/Sema/attr-mig.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +typedef int kern_return_t; +typedef kern_return_t IOReturn; +#define KERN_SUCCESS 0 +#define kIOReturnSuccess KERN_SUCCESS + +class MyServer { +public: + virtual __attribute__((mig_server_routine)) IOReturn externalMethod(); + virtual __attribute__((mig_server_routine)) void anotherMethod(); // expected-warning{{'mig_server_routine' attribute only applies to functions that return a kernel return code}} + virtual __attribute__((mig_server_routine)) int yetAnotherMethod(); // expected-warning{{'mig_server_routine' attribute only applies to functions that return a kernel return code}} +}; + +IOReturn MyServer::externalMethod() { + return kIOReturnSuccess; +}