MadCoder updated this revision to Diff 229183.
MadCoder marked 2 inline comments as done.
MadCoder added a comment.

Beefed up the tests, addressed the `selfValue` related issue.

Also rolled back to the `ObjCDeclInterfaceDecl` cast in GenerateDirectMethod as 
it turns out that all callers pass this type rather than an `ObjCImplDecl` 
however it's never nil and always of that type so make this an assert instead.

Did a pass of clang-format to clean up style


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69991/new/

https://reviews.llvm.org/D69991

Files:
  clang/include/clang/AST/DeclObjC.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/ObjCRuntime.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/DeclObjC.cpp
  clang/lib/AST/DeclPrinter.cpp
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/CodeGen/CGObjC.cpp
  clang/lib/CodeGen/CGObjCGNU.cpp
  clang/lib/CodeGen/CGObjCMac.cpp
  clang/lib/CodeGen/CGObjCRuntime.h
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaDeclObjC.cpp
  clang/lib/Sema/SemaExprObjC.cpp
  clang/lib/Sema/SemaObjCProperty.cpp
  clang/test/CodeGenObjC/direct-method.m
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaObjC/method-direct.m

Index: clang/test/SemaObjC/method-direct.m
===================================================================
--- /dev/null
+++ clang/test/SemaObjC/method-direct.m
@@ -0,0 +1,139 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wselector-type-mismatch %s
+
+@protocol Proto
+- (void)protoMethod;      // expected-note {{previous declaration is here}}
++ (void)classProtoMethod; // expected-note {{previous declaration is here}}
+@end
+
+@protocol ProtoDirectFail
+@property(nonatomic, direct) int protoProperty;        // expected-error {{'objc_direct' attribute cannot be applied to properties declared in an Objective-C protocol}}
+- (void)protoMethod __attribute__((objc_direct));      // expected-error {{'objc_direct' attribute cannot be applied to methods declared in an Objective-C protocol}}
++ (void)classProtoMethod __attribute__((objc_direct)); // expected-error {{'objc_direct' attribute cannot be applied to methods declared in an Objective-C protocol}}
+@end
+
+__attribute__((objc_root_class))
+@interface Root
+@property(nonatomic, direct) int directOrNot; // expected-note {{previous declaration is here}}
+- (int)directOrNot;
+- (void)rootRegular;                                  // expected-note {{previous declaration is here}}
++ (void)classRootRegular;                             // expected-note {{previous declaration is here}}
+- (void)rootDirect __attribute__((objc_direct));      // expected-note {{previous declaration is here}};
++ (void)classRootDirect __attribute__((objc_direct)); // expected-note {{previous declaration is here}};
+- (void)notDirectInIface;                             // expected-note {{previous declaration is here}}
++ (void)classNotDirectInIface;                        // expected-note {{previous declaration is here}}
+@end
+
+__attribute__((objc_direct_members))
+@interface
+Root()
+- (void)rootExtensionDirect;      // expected-note {{previous declaration is here}}
++ (void)classRootExtensionDirect; // expected-note {{previous declaration is here}}
+@end
+
+__attribute__((objc_direct_members))
+@interface Root(Direct)
+- (void)rootCategoryDirect;      // expected-note {{previous declaration is here}}
++ (void)classRootCategoryDirect; // expected-note {{previous declaration is here}}
+@end
+
+@interface Root ()
+- (void)rootExtensionRegular;                                   // expected-note {{previous declaration is here}}
++ (void)classRootExtensionRegular;                              // expected-note {{previous declaration is here}}
+- (void)rootExtensionDirect2 __attribute__((objc_direct));      // expected-note {{previous declaration is here}}
++ (void)classRootExtensionDirect2 __attribute__((objc_direct)); // expected-note {{previous declaration is here}}
+@end
+
+@interface Root (Direct2)
+- (void)rootCategoryRegular;                                   // expected-note {{previous declaration is here}}
++ (void)classRootCategoryRegular;                              // expected-note {{previous declaration is here}}
+- (void)rootCategoryDirect2 __attribute__((objc_direct));      // expected-note {{previous declaration is here}}
++ (void)classRootCategoryDirect2 __attribute__((objc_direct)); // expected-note {{previous declaration is here}}
+@end
+
+__attribute__((objc_root_class, objc_direct_members)) // expected-error {{'objc_direct_members' attribute only applies to Objective-C implementation declarations and Objective-C containers}}
+@interface SubDirectFail : Root
+- (instancetype)init;
+@end
+
+@interface Sub : Root <Proto>
+/* invalid overrides with directs */
+- (void)rootRegular __attribute__((objc_direct));               // expected-error {{methods that override superclass methods cannot be direct}}
++ (void)classRootRegular __attribute__((objc_direct));          // expected-error {{methods that override superclass methods cannot be direct}}
+- (void)protoMethod __attribute__((objc_direct));               // expected-error {{methods that implement protocol requirements cannot be direct}}
++ (void)classProtoMethod __attribute__((objc_direct));          // expected-error {{methods that implement protocol requirements cannot be direct}}
+- (void)rootExtensionRegular __attribute__((objc_direct));      // expected-error {{methods that override superclass methods cannot be direct}}
++ (void)classRootExtensionRegular __attribute__((objc_direct)); // expected-error {{methods that override superclass methods cannot be direct}}
+- (void)rootCategoryRegular __attribute__((objc_direct));       // expected-error {{methods that override superclass methods cannot be direct}}
++ (void)classRootCategoryRegular __attribute__((objc_direct));  // expected-error {{methods that override superclass methods cannot be direct}}
+
+/* allowed override because definition wasn't marked explicitly */
+- (int)directOrNot;
+
+/* invalid overrides of directs */
+- (void)setDirectOrNot:(int)value; // expected-error {{cannot override a method that is declared direct by a superclass}}
+- (void)rootDirect;                // expected-error {{cannot override a method that is declared direct by a superclass}}
++ (void)classRootDirect;           // expected-error {{cannot override a method that is declared direct by a superclass}}
+- (void)rootExtensionDirect;       // expected-error {{cannot override a method that is declared direct by a superclass}}
++ (void)classRootExtensionDirect;  // expected-error {{cannot override a method that is declared direct by a superclass}}
+- (void)rootExtensionDirect2;      // expected-error {{cannot override a method that is declared direct by a superclass}}
++ (void)classRootExtensionDirect2; // expected-error {{cannot override a method that is declared direct by a superclass}}
+- (void)rootCategoryDirect;        // expected-error {{cannot override a method that is declared direct by a superclass}}
++ (void)classRootCategoryDirect;   // expected-error {{cannot override a method that is declared direct by a superclass}}
+- (void)rootCategoryDirect2;       // expected-error {{cannot override a method that is declared direct by a superclass}}
++ (void)classRootCategoryDirect2;  // expected-error {{cannot override a method that is declared direct by a superclass}}
+@end
+
+__attribute__((objc_direct_members))
+@implementation Root
+- (void)rootRegular {
+}
++ (void)classRootRegular {
+}
+- (void)rootDirect {
+}
++ (void)classRootDirect {
+}
+- (void)rootExtensionDirect {
+}
++ (void)classRootExtensionDirect {
+}
+- (void)rootExtensionRegular {
+}
++ (void)classRootExtensionRegular {
+}
+- (void)rootExtensionDirect2 {
+}
++ (void)classRootExtensionDirect2 {
+}
+- (void)notDirectInIface __attribute__((objc_direct)) // expected-error {{direct method implementation was previously declared not direct}}
+{
+}
++ (void)classNotDirectInIface __attribute__((objc_direct)) // expected-error {{direct method implementation was previously declared not direct}}
+{
+}
+- (void)direct1 { // expected-note {{direct method 'direct1' declared here}}
+}
+- (void)direct2 { // expected-note {{direct method 'direct2' declared here}}
+}
+@end
+
+@interface Foo : Root
+- (id)directMismatch1; // expected-note {{using}}
+- (id)directMismatch2; // expected-note {{method 'directMismatch2' declared here}}
+@end
+
+@interface Bar : Root
+- (void)directMismatch1 __attribute__((objc_direct)); // expected-note {{also found}}
+- (void)directMismatch2 __attribute__((objc_direct)); // expected-note {{method 'directMismatch2' declared here}}
+@end
+
+extern void callMethod(id obj);
+extern void useSel(SEL sel);
+
+void callMethod(id obj) {
+  [obj direct1]; // expected-error {{messaging unqualified id with a method that is possibly direct}}
+  [(Root *)obj direct1];
+  [obj directMismatch1];              // expected-warning {{multiple methods named 'directMismatch1' found}}
+  useSel(@selector(direct2));         // expected-error {{@selector expression formed with direct selector 'direct2'}}
+  useSel(@selector(directMismatch2)); // expected-warning {{several methods with selector 'directMismatch2' of mismatched types are found for the @selector expression}}
+}
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
@@ -104,6 +104,8 @@
 // CHECK-NEXT: ObjCBridgeRelated (SubjectMatchRule_record)
 // CHECK-NEXT: ObjCClassStub (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: ObjCDesignatedInitializer (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCDirect (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCDirectMembers (SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_category)
 // CHECK-NEXT: ObjCException (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol)
 // CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable_not_is_parameter, SubjectMatchRule_function, SubjectMatchRule_block, SubjectMatchRule_objc_method)
Index: clang/test/CodeGenObjC/direct-method.m
===================================================================
--- /dev/null
+++ clang/test/CodeGenObjC/direct-method.m
@@ -0,0 +1,154 @@
+// RUN: %clang_cc1 -emit-llvm -fobjc-arc -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+
+struct my_complex_struct {
+  int a, b;
+};
+
+struct my_aggregate_struct {
+  int a, b;
+  char buf[128];
+};
+
+__attribute__((objc_root_class))
+@interface Root
+@end
+
+@implementation Root
+// CHECK-LABEL: define hidden i32 @"\01-[Root getInt]"(
+- (int)getInt __attribute__((objc_direct)) {
+  // loading parameters
+  // CHECK-LABEL: entry:
+  // CHECK-NEXT: [[RETVAL:%.*]] = alloca
+  // CHECK-NEXT: %self.addr = alloca %0*,
+  // CHECK-NEXT: %_cmd.addr = alloca i8*,
+  // CHECK-NEXT: store %0* %self, %0** %self.addr,
+  // CHECK-NEXT: store i8* %_cmd, i8** %_cmd.addr,
+
+  // self nil-check
+  // CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** %self.addr,
+  // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq %0* [[SELF]], null
+  // CHECK-NEXT: br i1 [[NILCHECK]],
+
+  // setting return value to nil
+  // CHECK-LABEL: objc_direct_method.self_is_nil:
+  // CHECK: [[RET0:%.*]] = bitcast{{.*}}[[RETVAL]]
+  // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RET0]], i8 0,
+  // CHECK-NEXT: br label
+
+  // set value
+  // CHECK-LABEL: objc_direct_method.cont:
+  // CHECK: store{{.*}}[[RETVAL]],
+  // CHECK-NEXT: br label
+
+  // return
+  // CHECK-LABEL: return:
+  // CHECK: {{%.*}} = load{{.*}}[[RETVAL]],
+  // CHECK-NEXT: ret
+  return 42;
+}
+
+// CHECK-LABEL: define hidden i32 @"\01+[Root classGetInt]"(
++ (int)classGetInt __attribute__((objc_direct)) {
+  // loading parameters
+  // CHECK-LABEL: entry:
+  // CHECK-NEXT: %self.addr = alloca i8*,
+  // CHECK-NEXT: %_cmd.addr = alloca i8*,
+  // CHECK-NEXT: store i8* %self, i8** %self.addr,
+  // CHECK-NEXT: store i8* %_cmd, i8** %_cmd.addr,
+
+  // [self self]
+  // CHECK-NEXT: [[SELF:%.*]] = load i8*, i8** %self.addr,
+  // CHECK-NEXT: [[SELFSEL:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[SELF0:%.*]] = call {{.*}} @objc_msgSend
+  // CHECK-NEXT: store i8* [[SELF0]], i8** %self.addr,
+
+  // return
+  // CHECK-NEXT: ret
+  return 42;
+}
+
+// CHECK-LABEL: define hidden i64 @"\01-[Root getComplex]"(
+- (struct my_complex_struct)getComplex __attribute__((objc_direct)) {
+  // loading parameters
+  // CHECK-LABEL: entry:
+  // CHECK-NEXT: [[RETVAL:%.*]] = alloca
+  // CHECK-NEXT: %self.addr = alloca %0*,
+  // CHECK-NEXT: %_cmd.addr = alloca i8*,
+  // CHECK-NEXT: store %0* %self, %0** %self.addr,
+  // CHECK-NEXT: store i8* %_cmd, i8** %_cmd.addr,
+
+  // self nil-check
+  // CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** %self.addr,
+  // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq %0* [[SELF]], null
+  // CHECK-NEXT: br i1 [[NILCHECK]],
+
+  // setting return value to nil
+  // CHECK-LABEL: objc_direct_method.self_is_nil:
+  // CHECK: [[RET0:%.*]] = bitcast{{.*}}[[RETVAL]]
+  // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RET0]], i8 0,
+  // CHECK-NEXT: br label
+
+  // set value
+  // CHECK-LABEL: objc_direct_method.cont:
+  // CHECK: [[RET1:%.*]] = bitcast{{.*}}[[RETVAL]]
+  // CHECK-NEXT: call void @llvm.memcpy{{[^(]*}}({{[^,]*}}[[RET1]],
+  // CHECK-NEXT: br label
+
+  // return
+  // CHECK-LABEL: return:
+  // CHECK: [[RET2:%.*]] = bitcast{{.*}}[[RETVAL]]
+  // CHECK-NEXT: {{%.*}} = load{{.*}}[[RET2]],
+  // CHECK-NEXT: ret
+  struct my_complex_struct st = {.a = 42};
+  return st;
+}
+
+// CHECK-LABEL: define hidden i64 @"\01+[Root classGetComplex]"(
++ (struct my_complex_struct)classGetComplex __attribute__((objc_direct)) {
+  struct my_complex_struct st = {.a = 42};
+  return st;
+  // CHECK: ret i64
+}
+
+// CHECK-LABEL: define hidden void @"\01-[Root getAggregate]"(
+- (struct my_aggregate_struct)getAggregate __attribute__((objc_direct)) {
+  // CHECK: %struct.my_aggregate_struct* noalias sret [[RETVAL:%[^,]*]],
+
+  // loading parameters
+  // CHECK-LABEL: entry:
+  // CHECK-NEXT: %self.addr = alloca %0*,
+  // CHECK-NEXT: %_cmd.addr = alloca i8*,
+  // CHECK-NEXT: store %0* %self, %0** %self.addr,
+  // CHECK-NEXT: store i8* %_cmd, i8** %_cmd.addr,
+
+  // self nil-check
+  // CHECK-NEXT: [[SELF:%.*]] = load %0*, %0** %self.addr,
+  // CHECK-NEXT: [[NILCHECK:%.*]] = icmp eq %0* [[SELF]], null
+  // CHECK-NEXT: br i1 [[NILCHECK]],
+
+  // setting return value to nil
+  // CHECK-LABEL: objc_direct_method.self_is_nil:
+  // CHECK: [[RET0:%.*]] = bitcast{{.*}}[[RETVAL]]
+  // CHECK-NEXT: call void @llvm.memset{{[^(]*}}({{[^,]*}}[[RET0]], i8 0,
+  // CHECK-NEXT: br label
+
+  // set value
+  // CHECK-LABEL: objc_direct_method.cont:
+  // CHECK: [[RET1:%.*]] = bitcast{{.*}}[[RETVAL]]
+  // CHECK: br label
+
+  // return
+  // CHECK-LABEL: return:
+  // CHECK: ret void
+  struct my_aggregate_struct st = {.a = 42};
+  return st;
+}
+
+// CHECK-LABEL: define hidden void @"\01+[Root classGetAggregate]"(
++ (struct my_aggregate_struct)classGetAggregate __attribute__((objc_direct)) {
+  struct my_aggregate_struct st = {.a = 42};
+  return st;
+  // CHECK: ret void
+}
+
+@end
Index: clang/lib/Sema/SemaObjCProperty.cpp
===================================================================
--- clang/lib/Sema/SemaObjCProperty.cpp
+++ clang/lib/Sema/SemaObjCProperty.cpp
@@ -306,6 +306,8 @@
     attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
   if (Attributes & ObjCDeclSpec::DQ_PR_class)
     attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class;
+  if (Attributes & ObjCDeclSpec::DQ_PR_direct)
+    attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_direct;
 
   return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
 }
@@ -705,9 +707,20 @@
   if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
 
- if (Attributes & ObjCDeclSpec::DQ_PR_class)
+  if (Attributes & ObjCDeclSpec::DQ_PR_class)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class);
 
+  if (Attributes & ObjCDeclSpec::DQ_PR_direct) {
+    if (isa<ObjCProtocolDecl>(CDecl)) {
+      Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true;
+    } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+      PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_direct);
+    } else {
+      Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored)
+          << PDecl->getDeclName();
+    }
+  }
+
   return PDecl;
 }
 
@@ -2410,6 +2423,9 @@
 
     AddPropertyAttrs(*this, GetterMethod, property);
 
+    if (property->isDirectProperty())
+      GetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
+
     if (property->hasAttr<NSReturnsNotRetainedAttr>())
       GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
                                                                      Loc));
@@ -2483,6 +2499,9 @@
 
       AddPropertyAttrs(*this, SetterMethod, property);
 
+      if (property->isDirectProperty())
+        SetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
+
       CD->addDecl(SetterMethod);
       if (const SectionAttr *SA = property->getAttr<SectionAttr>())
         SetterMethod->addAttr(SectionAttr::CreateImplicit(
Index: clang/lib/Sema/SemaExprObjC.cpp
===================================================================
--- clang/lib/Sema/SemaExprObjC.cpp
+++ clang/lib/Sema/SemaExprObjC.cpp
@@ -1118,6 +1118,16 @@
   return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc);
 }
 
+static void HelperNoteMethodDeclaredAt(Sema &S, ObjCMethodDecl *Method) {
+  if (Method->isDirectMethod()) {
+    S.Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+        << Method->getDeclName();
+  } else {
+    S.Diag(Method->getLocation(), diag::note_method_declared_at)
+        << Method->getDeclName();
+  }
+}
+
 static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
                                                SourceLocation AtLoc,
                                                SourceLocation LParenLoc,
@@ -1139,11 +1149,9 @@
         S.Diag(AtLoc, diag::warn_multiple_selectors)
           << Method->getSelector() << FixItHint::CreateInsertion(LParenLoc, "(")
           << FixItHint::CreateInsertion(RParenLoc, ")");
-        S.Diag(Method->getLocation(), diag::note_method_declared_at)
-          << Method->getDeclName();
+        HelperNoteMethodDeclaredAt(S, Method);
       }
-      S.Diag(MatchingMethodDecl->getLocation(), diag::note_method_declared_at)
-        << MatchingMethodDecl->getDeclName();
+      HelperNoteMethodDeclaredAt(S, MatchingMethodDecl);
     }
   }
   return Warned;
@@ -1174,6 +1182,35 @@
   }
 }
 
+static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
+                                                Selector Sel,
+                                                ObjCMethodList &MethList,
+                                                bool &onlyDirect) {
+  ObjCMethodList *M = &MethList;
+  for (M = M->getNext(); M; M = M->getNext()) {
+    ObjCMethodDecl *Method = M->getMethod();
+    if (Method->getSelector() != Sel)
+      continue;
+    if (!Method->isDirectMethod())
+      onlyDirect = false;
+  }
+}
+
+static void DiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
+                                        Selector Sel, bool &onlyDirect) {
+  for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(),
+       e = S.MethodPool.end(); b != e; b++) {
+    // first, instance methods
+    ObjCMethodList &InstMethList = b->second.first;
+    HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, InstMethList,
+                                        onlyDirect);
+
+    // second, class methods
+    ObjCMethodList &ClsMethList = b->second.second;
+    HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, ClsMethList, onlyDirect);
+  }
+}
+
 ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
                                              SourceLocation AtLoc,
                                              SourceLocation SelLoc,
@@ -1196,9 +1233,18 @@
 
     } else
         Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
-  } else
+  } else {
+    bool onlyDirect = Method->isDirectMethod();
+    DiagnoseDirectSelectorsExpr(*this, AtLoc, Sel, onlyDirect);
     DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
                                 WarnMultipleSelectors);
+    if (onlyDirect) {
+      Diag(AtLoc, diag::err_direct_selector_expression)
+          << Method->getSelector();
+      Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+          << Method->getDeclName();
+    }
+  }
 
   if (Method &&
       Method->getImplementationControl() != ObjCMethodDecl::Optional &&
@@ -2771,9 +2817,6 @@
     }
   }
 
-  if (ReceiverType->isObjCIdType() && !isImplicit)
-    Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
-
   // There's a somewhat weird interaction here where we assume that we
   // won't actually have a method unless we also don't need to do some
   // of the more detailed type-checking on the receiver.
@@ -2975,6 +3018,17 @@
     (Method && Method->getMethodFamily() == OMF_init)
       ? getEnclosingFunction() : nullptr;
 
+  if (ReceiverType->isObjCIdType() && !isImplicit) {
+    if (Method && Method->isDirectMethod()) {
+      Diag(Receiver->getExprLoc(),
+           diag::err_messaging_unqualified_id_with_direct_method);
+      Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+          << Method->getDeclName();
+    } else {
+      Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
+    }
+  }
+
   if (DIFunctionScopeInfo &&
       DIFunctionScopeInfo->ObjCIsDesignatedInit &&
       (SuperLoc.isValid() || isSelfExpr(Receiver))) {
Index: clang/lib/Sema/SemaDeclObjC.cpp
===================================================================
--- clang/lib/Sema/SemaDeclObjC.cpp
+++ clang/lib/Sema/SemaDeclObjC.cpp
@@ -3233,6 +3233,9 @@
   if (left->isHidden() || right->isHidden())
     return false;
 
+  if (left->isDirectMethod() != right->isDirectMethod())
+    return false;
+
   if (getLangOpts().ObjCAutoRefCount &&
       (left->hasAttr<NSReturnsRetainedAttr>()
          != right->hasAttr<NSReturnsRetainedAttr>() ||
@@ -3424,6 +3427,9 @@
   if (!chosen->isInstanceMethod())
     return false;
 
+  if (chosen->isDirectMethod() != other->isDirectMethod())
+    return false;
+
   Selector sel = chosen->getSelector();
   if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")
     return false;
@@ -4314,6 +4320,18 @@
 };
 } // end anonymous namespace
 
+void Sema::CheckObjCMethodDirectOverrides(ObjCMethodDecl *method,
+                                          ObjCMethodDecl *overridden) {
+  if (const auto *attr = overridden->getAttr<ObjCDirectAttr>()) {
+    Diag(method->getLocation(), diag::err_objc_override_direct_method);
+    Diag(attr->getLocation(), diag::note_previous_declaration);
+  } else if (const auto *attr = method->getAttr<ObjCDirectAttr>()) {
+    Diag(attr->getLocation(), diag::err_objc_direct_on_override)
+        << isa<ObjCProtocolDecl>(overridden->getDeclContext());
+    Diag(overridden->getLocation(), diag::note_previous_declaration);
+  }
+}
+
 void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
                                     ObjCInterfaceDecl *CurrentClass,
                                     ResultTypeCompatibilityKind RTC) {
@@ -4332,8 +4350,8 @@
       if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
           CurrentClass != overridden->getClassInterface() ||
           overridden->isOverriding()) {
+        CheckObjCMethodDirectOverrides(ObjCMethod, overridden);
         hasOverriddenMethodsInBaseOrProtocol = true;
-
       } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {
         // OverrideSearch will return as "overridden" the same method in the
         // interface. For hasOverriddenMethodsInBaseOrProtocol, we need to
@@ -4357,6 +4375,7 @@
               for (ObjCMethodDecl *SuperOverridden : overrides) {
                 if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||
                     CurrentClass != SuperOverridden->getClassInterface()) {
+                  CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden);
                   hasOverriddenMethodsInBaseOrProtocol = true;
                   overridden->setOverriding(true);
                   break;
@@ -4464,6 +4483,12 @@
                                             method->getLocation()));
   }
 
+  if (!method->isDirectMethod())
+    if (const auto *attr = prevMethod->getAttr<ObjCDirectAttr>()) {
+      method->addAttr(
+          ObjCDirectAttr::CreateImplicit(S.Context, attr->getLocation()));
+    }
+
   // Merge nullability of the result type.
   QualType newReturnType
     = mergeTypeNullabilityForRedecl(
@@ -4672,6 +4697,12 @@
       if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
                                           ObjCMethod->isInstanceMethod())) {
         mergeInterfaceMethodToImpl(*this, ObjCMethod, IMD);
+        if (const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>()) {
+          if (!IMD->isDirectMethod()) {
+            Diag(attr->getLocation(), diag::err_objc_direct_missing_on_decl);
+            Diag(IMD->getLocation(), diag::note_previous_declaration);
+          }
+        }
 
         // Warn about defining -dealloc in a category.
         if (isa<ObjCCategoryImplDecl>(ImpDecl) && IMD->isOverriding() &&
@@ -4679,6 +4710,9 @@
           Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)
             << ObjCMethod->getDeclName();
         }
+      } else if (ImpDecl->hasAttr<ObjCDirectMembersAttr>()) {
+        ObjCMethod->addAttr(
+            ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
       }
 
       // Warn if a method declared in a protocol to which a category or
@@ -4698,6 +4732,11 @@
           }
     }
   } else {
+    if (!ObjCMethod->isDirectMethod() &&
+        ClassDecl->hasAttr<ObjCDirectMembersAttr>()) {
+      ObjCMethod->addAttr(
+          ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
+    }
     cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
   }
 
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -2600,6 +2600,29 @@
     D->addAttr(newAttr);
 }
 
+static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  // objc_direct cannot be set on methods declared in the context of a protocol
+  if (isa<ObjCProtocolDecl>(D->getDeclContext())) {
+    S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false;
+    return;
+  }
+
+  if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+    handleSimpleAttribute<ObjCDirectAttr>(S, D, AL);
+  } else {
+    S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
+  }
+}
+
+static void handleObjCDirectMembersAttr(Sema &S, Decl *D,
+                                        const ParsedAttr &AL) {
+  if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+    handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
+  } else {
+    S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
+  }
+}
+
 static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   const auto *M = cast<ObjCMethodDecl>(D);
   if (!AL.isArgIdent(0)) {
@@ -6909,6 +6932,13 @@
   case ParsedAttr::AT_ObjCRootClass:
     handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
     break;
+  case ParsedAttr::AT_ObjCDirect:
+    handleObjCDirectAttr(S, D, AL);
+    break;
+  case ParsedAttr::AT_ObjCDirectMembers:
+    handleObjCDirectMembersAttr(S, D, AL);
+    handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
+    break;
   case ParsedAttr::AT_ObjCNonLazyClass:
     handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL);
     break;
Index: clang/lib/Parse/ParseObjc.cpp
===================================================================
--- clang/lib/Parse/ParseObjc.cpp
+++ clang/lib/Parse/ParseObjc.cpp
@@ -822,6 +822,7 @@
 ///   property-attribute:
 ///     getter '=' identifier
 ///     setter '=' identifier ':'
+///     direct
 ///     readonly
 ///     readwrite
 ///     assign
@@ -954,6 +955,8 @@
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable);
     } else if (II->isStr("class")) {
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_class);
+    } else if (II->isStr("direct")) {
+      DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_direct);
     } else {
       Diag(AttrName, diag::err_objc_expected_property_attr) << II;
       SkipUntil(tok::r_paren, StopAtSemi);
Index: clang/lib/CodeGen/CGObjCRuntime.h
===================================================================
--- clang/lib/CodeGen/CGObjCRuntime.h
+++ clang/lib/CodeGen/CGObjCRuntime.h
@@ -169,6 +169,21 @@
                       const ObjCInterfaceDecl *Class = nullptr,
                       const ObjCMethodDecl *Method = nullptr) = 0;
 
+  /// Generate an Objective-C message send operation.
+  ///
+  /// This variant allows for the call to be substituted with an optimized
+  /// variant.
+  CodeGen::RValue
+  GeneratePossiblySpecializedMessageSend(CodeGenFunction &CGF,
+                                         ReturnValueSlot Return,
+                                         QualType ResultType,
+                                         Selector Sel,
+                                         llvm::Value *Receiver,
+                                         const CallArgList& Args,
+                                         const ObjCInterfaceDecl *OID,
+                                         const ObjCMethodDecl *Method,
+                                         bool isClassMessage);
+
   /// Generate an Objective-C message send operation to the super
   /// class initiated in a method for Class and with the given Self
   /// object.
@@ -205,6 +220,12 @@
   virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
                                          const ObjCContainerDecl *CD) = 0;
 
+  /// Generates prologue for direct Objective-C Methods.
+  virtual void GenerateDirectMethodPrologue(CodeGenFunction &CGF,
+                                            llvm::Function *Fn,
+                                            const ObjCMethodDecl *OMD,
+                                            const ObjCContainerDecl *CD) = 0;
+
   /// Return the runtime function for getting properties.
   virtual llvm::FunctionCallee GetPropertyGetFunction() = 0;
 
Index: clang/lib/CodeGen/CGObjCMac.cpp
===================================================================
--- clang/lib/CodeGen/CGObjCMac.cpp
+++ clang/lib/CodeGen/CGObjCMac.cpp
@@ -874,6 +874,10 @@
   /// this translation unit.
   llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions;
 
+  /// DirectMethodDefinitions - map of direct methods which have been defined in
+  /// this translation unit.
+  llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> DirectMethodDefinitions;
+
   /// PropertyNames - uniqued method variable names.
   llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames;
 
@@ -1065,7 +1069,7 @@
   CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
                                   ReturnValueSlot Return,
                                   QualType ResultType,
-                                  llvm::Value *Sel,
+                                  Selector Sel,
                                   llvm::Value *Arg0,
                                   QualType Arg0Ty,
                                   bool IsSuper,
@@ -1092,6 +1096,13 @@
   llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
                                  const ObjCContainerDecl *CD=nullptr) override;
 
+  llvm::Function *GenerateDirectMethod(const ObjCMethodDecl *OMD,
+                                       const ObjCContainerDecl *CD);
+
+  void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
+                                    const ObjCMethodDecl *OMD,
+                                    const ObjCContainerDecl *CD) override;
+
   void GenerateProtocol(const ObjCProtocolDecl *PD) override;
 
   /// GetOrEmitProtocol - Get the protocol object for the given
@@ -1573,9 +1584,13 @@
     // base of the ivar access is a parameter to an Objective C method.
     // However, because the parameters are not available in the current
     // interface, we cannot perform this check.
+    //
+    // Note that for direct methods, because objc_msgSend is skipped,
+    // and that the method may be inlined, this optimization actually
+    // can't be performed.
     if (const ObjCMethodDecl *MD =
           dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
-      if (MD->isInstanceMethod())
+      if (MD->isInstanceMethod() && !MD->isDirectMethod())
         if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
           return IV->getContainingInterface()->isSuperClassOf(ID);
     return false;
@@ -2103,10 +2118,9 @@
     CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
   Target = CGF.Builder.CreateBitCast(Target, ClassTy);
   CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1));
-  return EmitMessageSend(CGF, Return, ResultType,
-                         EmitSelector(CGF, Sel),
-                         ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
-                         true, CallArgs, Method, Class, ObjCTypes);
+  return EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper.getPointer(),
+                         ObjCTypes.SuperPtrCTy, true, CallArgs, Method, Class,
+                         ObjCTypes);
 }
 
 /// Generate code for a message send expression.
@@ -2118,10 +2132,9 @@
                                                const CallArgList &CallArgs,
                                                const ObjCInterfaceDecl *Class,
                                                const ObjCMethodDecl *Method) {
-  return EmitMessageSend(CGF, Return, ResultType,
-                         EmitSelector(CGF, Sel),
-                         Receiver, CGF.getContext().getObjCIdType(),
-                         false, CallArgs, Method, Class, ObjCTypes);
+  return EmitMessageSend(CGF, Return, ResultType, Sel, Receiver,
+                         CGF.getContext().getObjCIdType(), false, CallArgs,
+                         Method, Class, ObjCTypes);
 }
 
 static bool isWeakLinkedClass(const ObjCInterfaceDecl *ID) {
@@ -2137,7 +2150,7 @@
 CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
                                  ReturnValueSlot Return,
                                  QualType ResultType,
-                                 llvm::Value *Sel,
+                                 Selector Sel,
                                  llvm::Value *Arg0,
                                  QualType Arg0Ty,
                                  bool IsSuper,
@@ -2145,11 +2158,22 @@
                                  const ObjCMethodDecl *Method,
                                  const ObjCInterfaceDecl *ClassReceiver,
                                  const ObjCCommonTypesHelper &ObjCTypes) {
+  CodeGenTypes &Types = CGM.getTypes();
   CallArgList ActualArgs;
   if (!IsSuper)
     Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
   ActualArgs.add(RValue::get(Arg0), Arg0Ty);
-  ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
+  if (Method && Method->isDirectMethod()) {
+    // Direct methods will synthesize the proper `_cmd` internally,
+    // so just don't bother with setting the `_cmd` argument.
+    assert(!IsSuper);
+    auto selTy = CGF.getContext().getObjCSelType();
+    auto undefSel = llvm::UndefValue::get(Types.ConvertType(selTy));
+    ActualArgs.add(RValue::get(undefSel), selTy);
+  } else {
+    ActualArgs.add(RValue::get(GetSelector(CGF, Sel)),
+                   CGF.getContext().getObjCSelType());
+  }
   ActualArgs.addFrom(CallArgs);
 
   // If we're calling a method, use the formal signature.
@@ -2190,7 +2214,9 @@
   bool RequiresNullCheck = false;
 
   llvm::FunctionCallee Fn = nullptr;
-  if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
+  if (Method && Method->isDirectMethod()) {
+    Fn = GenerateDirectMethod(Method, Method->getClassInterface());
+  } else if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
     if (ReceiverCanBeNull) RequiresNullCheck = true;
     Fn = (ObjCABI == 2) ?  ObjCTypes.getSendStretFn2(IsSuper)
       : ObjCTypes.getSendStretFn(IsSuper);
@@ -3297,6 +3323,8 @@
   values.addInt(ObjCTypes.IntTy, Properties.size());
   auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy);
   for (auto PD : Properties) {
+    if (PD->isDirectProperty())
+      continue;
     auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy);
     property.add(GetPropertyName(PD->getIdentifier()));
     property.add(GetPropertyTypeString(PD, Container));
@@ -3372,7 +3400,8 @@
   };
   SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
   for (const auto *MD : OCD->methods()) {
-    Methods[unsigned(MD->isClassMethod())].push_back(MD);
+    if (!MD->isDirectMethod())
+      Methods[unsigned(MD->isClassMethod())].push_back(MD);
   }
 
   Values.add(GetClassName(OCD->getName()));
@@ -3554,13 +3583,16 @@
   };
   SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists];
   for (const auto *MD : ID->methods()) {
-    Methods[unsigned(MD->isClassMethod())].push_back(MD);
+    if (!MD->isDirectMethod())
+      Methods[unsigned(MD->isClassMethod())].push_back(MD);
   }
 
   for (const auto *PID : ID->property_impls()) {
     if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
       ObjCPropertyDecl *PD = PID->getPropertyDecl();
 
+      if (PD->isDirectProperty())
+        continue;
       if (ObjCMethodDecl *MD = PD->getGetterMethodDecl())
         if (GetMethodDefinition(MD))
           Methods[InstanceMethods].push_back(MD);
@@ -3959,7 +3991,8 @@
   values.addInt(ObjCTypes.IntTy, methods.size());
   auto methodArray = values.beginArray(ObjCTypes.MethodTy);
   for (auto MD : methods) {
-    emitMethodConstant(methodArray, MD);
+    if (!MD->isDirectMethod())
+      emitMethodConstant(methodArray, MD);
   }
   methodArray.finishAndAddTo(values);
 
@@ -3970,6 +4003,34 @@
 
 llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
                                                 const ObjCContainerDecl *CD) {
+  llvm::Function *Method;
+
+  if (OMD->isDirectMethod()) {
+    Method = GenerateDirectMethod(OMD, CD);
+  } else {
+    SmallString<256> Name;
+    GetNameForMethod(OMD, CD, Name);
+
+    CodeGenTypes &Types = CGM.getTypes();
+    llvm::FunctionType *MethodTy =
+        Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
+    Method =
+        llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage,
+                               Name.str(), &CGM.getModule());
+  }
+
+  MethodDefinitions.insert(std::make_pair(OMD, Method));
+
+  return Method;
+}
+
+llvm::Function *
+CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD,
+                                      const ObjCContainerDecl *CD) {
+  auto I = DirectMethodDefinitions.find(OMD);
+  if (I != DirectMethodDefinitions.end())
+    return I->second;
+
   SmallString<256> Name;
   GetNameForMethod(OMD, CD, Name);
 
@@ -3977,15 +4038,94 @@
   llvm::FunctionType *MethodTy =
     Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
   llvm::Function *Method =
-    llvm::Function::Create(MethodTy,
-                           llvm::GlobalValue::InternalLinkage,
-                           Name.str(),
-                           &CGM.getModule());
-  MethodDefinitions.insert(std::make_pair(OMD, Method));
+      llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
+                             Name.str(), &CGM.getModule());
+  DirectMethodDefinitions.insert(std::make_pair(OMD, Method));
 
   return Method;
 }
 
+void CGObjCCommonMac::GenerateDirectMethodPrologue(
+    CodeGenFunction &CGF, llvm::Function *Fn, const ObjCMethodDecl *OMD,
+    const ObjCContainerDecl *CD) {
+  auto &Builder = CGF.Builder;
+  bool ReceiverCanBeNull = true;
+  auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
+  auto selfValue = Builder.CreateLoad(selfAddr);
+
+  // Generate:
+  //
+  // /* for class methods only to force class lazy initialization */
+  // self = [self self];
+  //
+  // /* unless the receiver is never NULL */
+  // if (self == nil) {
+  //     return (ReturnType){ };
+  // }
+  //
+  // _cmd = @selector(...)
+  // ...
+
+  if (OMD->isClassMethod()) {
+    const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
+    assert(OID &&
+           "GenerateDirectMethod() should be called with the Class Interface");
+    Selector SelfSel = GetNullarySelector("self", CGM.getContext());
+    auto ResultType = CGF.getContext().getObjCIdType();
+    RValue result;
+    CallArgList Args;
+
+    // attempt hard to generate objc_opt_self() which is as cheap as it can be
+    // to realize a class lazily
+    //
+    // TODO: make sure that when the inliner kicks in we do this once only
+    result = GeneratePossiblySpecializedMessageSend(
+        CGF, ReturnValueSlot(), ResultType, SelfSel, selfValue, Args, OID,
+        nullptr, true);
+    Builder.CreateStore(result.getScalarVal(), selfAddr);
+
+    ReceiverCanBeNull = isWeakLinkedClass(OID);
+  }
+
+  if (ReceiverCanBeNull) {
+    llvm::BasicBlock *SelfIsNilBlock =
+        CGF.createBasicBlock("objc_direct_method.self_is_nil");
+    llvm::BasicBlock *ContBlock =
+        CGF.createBasicBlock("objc_direct_method.cont");
+
+    // if (self == nil) {
+    auto selfTy = cast<llvm::PointerType>(selfValue->getType());
+    auto Zero = llvm::ConstantPointerNull::get(selfTy);
+
+    llvm::MDBuilder MDHelper(CGM.getLLVMContext());
+    Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero), SelfIsNilBlock,
+                         ContBlock, MDHelper.createBranchWeights(1, 1 << 20));
+
+    CGF.EmitBlock(SelfIsNilBlock);
+
+    //   return (ReturnType){ };
+    auto retTy = OMD->getReturnType();
+    Builder.SetInsertPoint(SelfIsNilBlock);
+    if (retTy->isVoidType()) {
+      Builder.CreateRetVoid();
+    } else {
+      CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
+      CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
+    }
+    // }
+
+    // rest of the body
+    CGF.EmitBlock(ContBlock);
+    Builder.SetInsertPoint(ContBlock);
+  }
+
+  // only synthesize _cmd if it's referenced
+  if (OMD->getCmdDecl()->isUsed()) {
+    Builder.CreateStore(GetSelector(CGF, OMD),
+                        CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
+  }
+}
+
 llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
                                                ConstantStructBuilder &Init,
                                                          StringRef Section,
@@ -6228,15 +6368,18 @@
   SmallVector<const ObjCMethodDecl*, 16> methods;
   if (flags & NonFragileABI_Class_Meta) {
     for (const auto *MD : ID->class_methods())
-      methods.push_back(MD);
+      if (!MD->isDirectMethod())
+        methods.push_back(MD);
   } else {
     for (const auto *MD : ID->instance_methods())
-      methods.push_back(MD);
+      if (!MD->isDirectMethod())
+        methods.push_back(MD);
 
     for (const auto *PID : ID->property_impls()) {
       if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){
         ObjCPropertyDecl *PD = PID->getPropertyDecl();
-
+        if (PD->isDirectProperty())
+          continue;
         if (auto MD = PD->getGetterMethodDecl())
           if (GetMethodDefinition(MD))
             methods.push_back(MD);
@@ -6565,6 +6708,8 @@
   SmallVector<const ObjCMethodDecl *, 16> instanceMethods;
   SmallVector<const ObjCMethodDecl *, 8> classMethods;
   for (const auto *MD : OCD->methods()) {
+    if (MD->isDirectMethod())
+      continue;
     if (MD->isInstanceMethod()) {
       instanceMethods.push_back(MD);
     } else {
@@ -7234,8 +7379,7 @@
     ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
                             Receiver, CGF.getContext().getObjCIdType(),
                             false, CallArgs, Method)
-    : EmitMessageSend(CGF, Return, ResultType,
-                      EmitSelector(CGF, Sel),
+    : EmitMessageSend(CGF, Return, ResultType, Sel,
                       Receiver, CGF.getContext().getObjCIdType(),
                       false, CallArgs, Method, Class, ObjCTypes);
 }
@@ -7466,8 +7610,7 @@
     ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
                             ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
                             true, CallArgs, Method)
-    : EmitMessageSend(CGF, Return, ResultType,
-                      EmitSelector(CGF, Sel),
+    : EmitMessageSend(CGF, Return, ResultType, Sel,
                       ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
                       true, CallArgs, Method, Class, ObjCTypes);
 }
@@ -7492,7 +7635,7 @@
       llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
                                      ObjCTypes.SelectorPtrTy);
     std::string SectionName =
-        GetSectionName("__objc_selrefs", "literal_pointers,no_dead_strip");
+        GetSectionName("__objc_selrefs", "literal_pointers");
     Entry = new llvm::GlobalVariable(
         CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
         getLinkageTypeForObjCMetadata(CGM, SectionName), Casted,
Index: clang/lib/CodeGen/CGObjCGNU.cpp
===================================================================
--- clang/lib/CodeGen/CGObjCGNU.cpp
+++ clang/lib/CodeGen/CGObjCGNU.cpp
@@ -606,6 +606,9 @@
 
   llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
                                  const ObjCContainerDecl *CD) override;
+  void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
+                                    const ObjCMethodDecl *OMD,
+                                    const ObjCContainerDecl *CD) override;
   void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
   void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
   void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override;
@@ -3873,6 +3876,13 @@
   return Method;
 }
 
+void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF,
+                                             llvm::Function *Fn,
+                                             const ObjCMethodDecl *OMD,
+                                             const ObjCContainerDecl *CD) {
+  // GNU runtime doesn't support direct calls at this time
+}
+
 llvm::FunctionCallee CGObjCGNU::GetPropertyGetFunction() {
   return GetPropertyFn;
 }
Index: clang/lib/CodeGen/CGObjC.cpp
===================================================================
--- clang/lib/CodeGen/CGObjC.cpp
+++ clang/lib/CodeGen/CGObjC.cpp
@@ -430,6 +430,20 @@
   return None;
 }
 
+CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
+    CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType,
+    Selector Sel, llvm::Value *Receiver, const CallArgList &Args,
+    const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method,
+    bool isClassMessage) {
+  if (Optional<llvm::Value *> SpecializedResult =
+          tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args,
+                                            Sel, Method, isClassMessage)) {
+    return RValue::get(SpecializedResult.getValue());
+  }
+  return GenerateMessageSend(CGF, Return, ResultType, Sel, Receiver, Args, OID,
+                             Method);
+}
+
 /// Instead of '[[MyClass alloc] init]', try to generate
 /// 'objc_alloc_init(MyClass)'. This provides a code size improvement on the
 /// caller side, as well as the optimized objc_alloc.
@@ -611,16 +625,9 @@
                                               method);
   } else {
     // Call runtime methods directly if we can.
-    if (Optional<llvm::Value *> SpecializedResult =
-            tryGenerateSpecializedMessageSend(*this, ResultType, Receiver, Args,
-                                              E->getSelector(), method,
-                                              isClassMessage)) {
-      result = RValue::get(SpecializedResult.getValue());
-    } else {
-      result = Runtime.GenerateMessageSend(*this, Return, ResultType,
-                                           E->getSelector(), Receiver, Args,
-                                           OID, method);
-    }
+    result = Runtime.GeneratePossiblySpecializedMessageSend(
+        *this, Return, ResultType, E->getSelector(), Receiver, Args, OID,
+        method, isClassMessage);
   }
 
   // For delegate init calls in ARC, implicitly store the result of
@@ -683,7 +690,13 @@
   llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
 
   const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
-  CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
+  if (OMD->isDirectMethod()) {
+    Fn->setVisibility(llvm::Function::HiddenVisibility);
+    CGM.SetLLVMFunctionAttributes(OMD, FI, Fn);
+    CGM.SetLLVMFunctionAttributesForDefinition(OMD, Fn);
+  } else {
+    CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
+  }
 
   args.push_back(OMD->getSelfDecl());
   args.push_back(OMD->getCmdDecl());
@@ -696,6 +709,14 @@
   StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
                 OMD->getLocation(), StartLoc);
 
+  if (OMD->isDirectMethod()) {
+    // This function is a direct call, it has to implement a nil check
+    // on entry.
+    //
+    // TODO: possibly have several entry points to elide the check
+    CGM.getObjCRuntime().GenerateDirectMethodPrologue(*this, Fn, OMD, CD);
+  }
+
   // In ARC, certain methods get an extra cleanup.
   if (CGM.getLangOpts().ObjCAutoRefCount &&
       OMD->isInstanceMethod() &&
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -1921,6 +1921,8 @@
       OS << " unsafe_unretained";
     if (Attrs & ObjCPropertyDecl::OBJC_PR_class)
       OS << " class";
+    if (Attrs & ObjCPropertyDecl::OBJC_PR_direct)
+      OS << " direct";
     if (Attrs & ObjCPropertyDecl::OBJC_PR_getter)
       dumpDeclRef(D->getGetterMethodDecl(), "getter");
     if (Attrs & ObjCPropertyDecl::OBJC_PR_setter)
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -1013,6 +1013,7 @@
     attributeOnlyIfTrue("unsafe_unretained",
                         Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
     attributeOnlyIfTrue("class", Attrs & ObjCPropertyDecl::OBJC_PR_class);
+    attributeOnlyIfTrue("direct", Attrs & ObjCPropertyDecl::OBJC_PR_direct);
     attributeOnlyIfTrue("nullability",
                         Attrs & ObjCPropertyDecl::OBJC_PR_nullability);
     attributeOnlyIfTrue("null_resettable",
Index: clang/lib/AST/DeclPrinter.cpp
===================================================================
--- clang/lib/AST/DeclPrinter.cpp
+++ clang/lib/AST/DeclPrinter.cpp
@@ -1469,6 +1469,11 @@
       first = false;
     }
 
+    if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_direct) {
+      Out << (first ? "" : ", ") << "direct";
+      first = false;
+    }
+
     if (PDecl->getPropertyAttributes() &
         ObjCPropertyDecl::OBJC_PR_nonatomic) {
       Out << (first ? "" : ", ") << "nonatomic";
Index: clang/lib/AST/DeclObjC.cpp
===================================================================
--- clang/lib/AST/DeclObjC.cpp
+++ clang/lib/AST/DeclObjC.cpp
@@ -823,6 +823,10 @@
                                     Selector(), QualType(), nullptr, nullptr);
 }
 
+bool ObjCMethodDecl::isDirectMethod() const {
+  return hasAttr<ObjCDirectAttr>();
+}
+
 bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
   return getMethodFamily() == OMF_init &&
       hasAttr<ObjCDesignatedInitializerAttr>();
@@ -1077,7 +1081,7 @@
 QualType ObjCMethodDecl::getSelfType(ASTContext &Context,
                                      const ObjCInterfaceDecl *OID,
                                      bool &selfIsPseudoStrong,
-                                     bool &selfIsConsumed) {
+                                     bool &selfIsConsumed) const {
   QualType selfTy;
   selfIsPseudoStrong = false;
   selfIsConsumed = false;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -8901,6 +8901,9 @@
     RTC_Unknown
   };
 
+  void CheckObjCMethodDirectOverrides(ObjCMethodDecl *method,
+                                      ObjCMethodDecl *overridden);
+
   void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
                                 ObjCInterfaceDecl *CurrentClass,
                                 ResultTypeCompatibilityKind RTC);
Index: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -833,7 +833,8 @@
     DQ_PR_unsafe_unretained = 0x800,
     DQ_PR_nullability = 0x1000,
     DQ_PR_null_resettable = 0x2000,
-    DQ_PR_class = 0x4000
+    DQ_PR_class = 0x4000,
+    DQ_PR_direct = 0x8000,
   };
 
   ObjCDeclSpec()
@@ -903,7 +904,7 @@
   unsigned objcDeclQualifier : 7;
 
   // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
-  unsigned PropertyAttributes : 15;
+  unsigned PropertyAttributes : 16;
 
   unsigned Nullability : 2;
 
Index: clang/include/clang/Basic/ObjCRuntime.h
===================================================================
--- clang/include/clang/Basic/ObjCRuntime.h
+++ clang/include/clang/Basic/ObjCRuntime.h
@@ -446,6 +446,20 @@
     llvm_unreachable("bad kind");
   }
 
+  /// Does this runtime supports direct dispatch
+  bool allowsDirectDispatch() const {
+    switch (getKind()) {
+    case FragileMacOSX: return false;
+    case MacOSX: return true;
+    case iOS: return true;
+    case WatchOS: return true;
+    case GCC: return false;
+    case GNUstep: return false;
+    case ObjFW: return false;
+    }
+    llvm_unreachable("bad kind");
+  }
+
   /// Try to parse an Objective-C runtime specification from the given
   /// string.
   ///
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -987,6 +987,22 @@
   "string is ill-formed as UTF-8 and will become a null %0 when boxed">,
   InGroup<ObjCBoxing>;
 
+def err_objc_direct_on_protocol : Error<
+  "'objc_direct' attribute cannot be applied to %select{methods|properties}0 "
+  "declared in an Objective-C protocol">;
+def err_objc_direct_missing_on_decl : Error<
+  "direct method implementation was previously declared not direct">;
+def err_objc_direct_on_override : Error<
+  "methods that %select{override superclass methods|implement protocol requirements}0 cannot be direct">;
+def err_objc_override_direct_method : Error<
+  "cannot override a method that is declared direct by a superclass">;
+def warn_objc_direct_ignored : Warning<
+  "%0 attribute isn't implemented by this Objective-C runtime">,
+  InGroup<IgnoredAttributes>;
+def warn_objc_direct_property_ignored : Warning<
+  "direct attribute on property %0 ignored (not implemented by this Objective-C runtime)">,
+  InGroup<IgnoredAttributes>;
+
 def warn_conflicting_overriding_ret_types : Warning<
   "conflicting return type in "
   "declaration of %0%diff{: $ vs $|}1,2">,
@@ -1072,6 +1088,7 @@
   "type of property %0 does not match type of accessor %1">;
 def note_conv_function_declared_at : Note<"type conversion function declared here">;
 def note_method_declared_at : Note<"method %0 declared here">;
+def note_direct_method_declared_at : Note<"direct method %0 declared here">;
 def note_property_attribute : Note<"property %0 is declared "
   "%select{deprecated|unavailable|partial}1 here">;
 def err_setter_type_void : Error<"type of setter must be void">;
@@ -1307,6 +1324,8 @@
   "several methods with selector %0 of mismatched types are found "
   "for the @selector expression">,
   InGroup<SelectorTypeMismatch>, DefaultIgnore;
+def err_direct_selector_expression: Error<
+  "@selector expression formed with direct selector %0">;
 
 def err_objc_kindof_nonobject : Error<
   "'__kindof' specifier cannot be applied to non-object type %0">;
@@ -1320,6 +1339,8 @@
 def warn_messaging_unqualified_id : Warning<
   "messaging unqualified id">, DefaultIgnore,
   InGroup<DiagGroup<"objc-messaging-id">>;
+def err_messaging_unqualified_id_with_direct_method : Error<
+  "messaging unqualified id with a method that is possibly direct">;
 
 // C++ declarations
 def err_static_assert_expression_is_not_constant : Error<
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -3897,6 +3897,69 @@
   }];
 }
 
+def ObjCDirectDocs : Documentation {
+  let Category = DocCatDecl;
+  let Content = [{
+This attribute can be added on methods declaration and implementation,
+to mark it as being called directly.
+
+If an Objective-C property is declared with the `direct` property attribute,
+then its getter and setter are declared to be direct unless they are explicitly
+declared.
+
+A message send to a direct method calls the implementation directly, as if it
+were a C function, rather than using ordinary Objective-C method dispatch. This
+is substantially faster and potentially allows the implementation to be inlined,
+but it also means the method cannot be overridden in subclasses or replaced
+dynamically, as ordinary Objective-C methods can.
+
+Furthermore, a direct method is not listed in the class's method lists. This
+substantially reduces the code-size overhead of the method but also means it
+cannot be called dynamically using ordinary Objective-C method dispatch at all;
+in particular, this means that it cannot override a superclass method or satisfy
+a protocol requirement.
+
+Clang will diagnose attempts to override direct methods, override non-direct
+methods with direct methods, implement a protocol requirement with a direct
+method, or use a selector that is only known to be used for direct methods.
+
+Symbols for direct method implementations are implicitly given hidden
+visibility, meaning that they can only be called within the same linkage unit.
+
+Although a direct method is called directly as if it were a C function, it still
+obeys Objective-C semantics in other ways:
+
+- If the receiver is ``nil``, the call does nothing and returns the zero value
+  for the return type.
+
+- Calling a direct class method will cause the class to be initialized,
+  including calling the ``+initialize`` method if present.
+
+- The method still receives an implicit ``_cmd`` argument containing its selector.
+
+Note, the ``objc_direct_members`` attribute can be used on ``@implementation``
+and ``@interface`` blocks defining Categories or Extensions to mark methods
+as being direct calls in bulk.
+  }];
+}
+
+def ObjCDirectMembersDocs : Documentation {
+  let Category = DocCatDecl;
+  let Content = [{
+This attribute can decorate classes ``@interface`` Categories and Extensions,
+or ``@implementation`` blocks. This attribute isn't allowed on the principal
+class ``@interface`` or on ``@protocol`` definitions.
+
+For Categories and Extensions, all methods and properties declared in this
+``@interface`` are implicitly marked with the ``objc_direct`` attribute.
+
+For ``@implementation`` blocks, then methods that are not declared in any
+``@interface`` (Principal interface, Category or Extension) of this class
+or any of its superclass, as well as methods implementing an ``@protocol``
+conformance, are implicitly marked with the ``objc_direct`` attribute.
+  }];
+}
+
 def SelectAnyDocs : Documentation {
   let Category = DocCatDecl;
   let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1852,6 +1852,20 @@
   let Documentation = [Undocumented];
 }
 
+def ObjCDirect : Attr {
+  let Spellings = [Clang<"objc_direct">];
+  let Subjects = SubjectList<[ObjCMethod], ErrorDiag>;
+  let LangOpts = [ObjC];
+  let Documentation = [ObjCDirectDocs];
+}
+
+def ObjCDirectMembers : Attr {
+  let Spellings = [Clang<"objc_direct_members">];
+  let Subjects = SubjectList<[ObjCImpl, ObjCCategory], ErrorDiag>;
+  let LangOpts = [ObjC];
+  let Documentation = [ObjCDirectMembersDocs];
+}
+
 def ObjCRuntimeName : Attr {
   let Spellings = [Clang<"objc_runtime_name">];
   let Subjects = SubjectList<[ObjCInterface, ObjCProtocol], ErrorDiag>;
Index: clang/include/clang/AST/DeclObjC.h
===================================================================
--- clang/include/clang/AST/DeclObjC.h
+++ clang/include/clang/AST/DeclObjC.h
@@ -408,7 +408,7 @@
   /// \return the type for \c self and set \arg selfIsPseudoStrong and
   /// \arg selfIsConsumed accordingly.
   QualType getSelfType(ASTContext &Context, const ObjCInterfaceDecl *OID,
-                       bool &selfIsPseudoStrong, bool &selfIsConsumed);
+                       bool &selfIsPseudoStrong, bool &selfIsConsumed) const;
 
   ImplicitParamDecl * getSelfDecl() const { return SelfDecl; }
   void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; }
@@ -466,6 +466,9 @@
     ObjCMethodDeclBits.HasSkippedBody = Skipped;
   }
 
+  /// True if the method is tagged as objc_direct
+  bool isDirectMethod() const;
+
   /// Returns the property associated with this method's selector.
   ///
   /// Note that even if this particular method is not marked as a property
@@ -747,13 +750,14 @@
     /// property attribute rather than a type qualifier.
     OBJC_PR_nullability = 0x1000,
     OBJC_PR_null_resettable = 0x2000,
-    OBJC_PR_class = 0x4000
+    OBJC_PR_class = 0x4000,
+    OBJC_PR_direct = 0x8000
     // Adding a property should change NumPropertyAttrsBits
   };
 
   enum {
     /// Number of bits fitting all the property attributes.
-    NumPropertyAttrsBits = 15
+    NumPropertyAttrsBits = 16
   };
 
   enum SetterKind { Assign, Retain, Copy, Weak };
@@ -876,6 +880,7 @@
 
   bool isInstanceProperty() const { return !isClassProperty(); }
   bool isClassProperty() const { return PropertyAttributes & OBJC_PR_class; }
+  bool isDirectProperty() const { return PropertyAttributes & OBJC_PR_direct; }
 
   ObjCPropertyQueryKind getQueryKind() const {
     return isClassProperty() ? ObjCPropertyQueryKind::OBJC_PR_query_class :
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to