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, ObjCMethod, Block]>; + let Documentation = [MIGConventionDocs]; +} + 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,24 @@ When compiled without ``-fobjc-arc``, this attribute is ignored. }]; } + +def MIGConventionDocs : Documentation { + let Category = DocCatType; + let Content = [{ + The Mach Interface Generator release-on-success 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 expected to follow the +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. The +attribute can be written using C++11 syntax: ``[[mig::server_routine]]``. +}]; +} 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< + "'mig_server_routine' attribute only applies to routines that return a kern_return_t">, + 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 @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Analysis/AnyCall.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -6396,6 +6397,29 @@ 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 MIG convention checks make no sense. + // BlockDecl doesn't store a return type, so it's annoying to check, + // so let's skip it for now. + if (!isa(D)) { + ASTContext &ACtx = S.getASTContext(); + QualType T = AnyCall::forDecl(D)->getReturnType(ACtx); + bool IsKernReturnT = false; + while (const auto *TT = T->getAs()) { + IsKernReturnT = (TT->getDecl()->getName() == "kern_return_t"); + T = TT->desugar(); + } + if (!IsKernReturnT || T.getCanonicalType() != ACtx.IntTy) { + S.Diag(D->getBeginLoc(), + diag::warn_mig_server_routine_does_not_return_kern_return_t); + return; + } + } + + handleSimpleAttribute(S, D, AL); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -7119,6 +7143,10 @@ case ParsedAttr::AT_ObjCExternallyRetained: handleObjCExternallyRetainedAttr(S, D, AL); break; + + 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,22 @@ +// 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, Objective-C methods, and blocks{{$}}}} + +__attribute__((mig_server_routine)) void foo_void(); // expected-warning{{'mig_server_routine' attribute only applies to routines that return a kern_return_t}} +__attribute__((mig_server_routine)) int foo_int(); // expected-warning{{'mig_server_routine' attribute only applies to routines that return a kern_return_t}} + +__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; +} + +__attribute__((mig_server_routine(123))) kern_return_t bar_with_argument(); // expected-error{{'mig_server_routine' attribute takes no arguments}} Index: clang/test/Sema/attr-mig.cpp =================================================================== --- /dev/null +++ clang/test/Sema/attr-mig.cpp @@ -0,0 +1,20 @@ +// 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 routines that return a kern_return_t}} + virtual __attribute__((mig_server_routine)) int yetAnotherMethod(); // expected-warning{{'mig_server_routine' attribute only applies to routines that return a kern_return_t}} + [[clang::mig_server_routine]] virtual IOReturn cppAnnotatedMethod(); + [[clang::mig_server_routine("arg")]] virtual IOReturn cppAnnotatedMethodWithInvalidArgs(); // expected-error{{'mig_server_routine' attribute takes no arguments}} + [[clang::mig_server_routine]] virtual int cppInvalidAnnotatedMethod(); // expected-warning{{'mig_server_routine' attribute only applies to routines that return a kern_return_t}} +}; + +IOReturn MyServer::externalMethod() { + return kIOReturnSuccess; +} Index: clang/test/Sema/attr-mig.m =================================================================== --- /dev/null +++ clang/test/Sema/attr-mig.m @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s + +typedef int kern_return_t; +#define KERN_SUCCESS 0 + +@interface NSObject +@end + +@interface I: NSObject +- (kern_return_t)foo __attribute__((mig_server_routine)); // no-warning +- (void) bar_void __attribute__((mig_server_routine)); // expected-warning{{'mig_server_routine' attribute only applies to routines that return a kern_return_t}} +- (int) bar_int __attribute__((mig_server_routine)); // expected-warning{{'mig_server_routine' attribute only applies to routines that return a kern_return_t}} +@end + +@implementation I +- (kern_return_t)foo { + kern_return_t (^block)() = ^ __attribute__((mig_server_routine)) { // no-warning + return KERN_SUCCESS; + }; + + // TODO: Warn that this block doesn't return a kern_return_t. + void (^invalid_block)() = ^ __attribute__((mig_server_routine)) {}; + + return block(); +} +- (void)bar_void { +} +- (int)bar_int { + return 0; +} +@end