plotfi updated this revision to Diff 459268.
plotfi added a comment.

Adding a test case to cover @protocol methods not being allowed to contain 
direct


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86049

Files:
  clang/include/clang/AST/DeclObjC.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/lib/AST/DeclObjC.cpp
  clang/lib/AST/Mangle.cpp
  clang/lib/CodeGen/CGObjC.cpp
  clang/lib/CodeGen/CGObjCRuntime.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/CodeGenObjC/objc-direct-wrapper.m

Index: clang/test/CodeGenObjC/objc-direct-wrapper.m
===================================================================
--- /dev/null
+++ clang/test/CodeGenObjC/objc-direct-wrapper.m
@@ -0,0 +1,63 @@
+// RUN: %clang -fobjc-arc -Wno-objc-root-class -ObjC -fobjc-runtime=ios -FFoundation \
+// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=1 \
+// RUN: -target x86_64-apple-macosx10.15.0 -c -o - %s | \
+// RUN: llvm-nm - | FileCheck -check-prefix=CHECK-WRAPPER %s
+
+// RUN: %clang -fobjc-arc -Wno-objc-root-class \
+// RUN: -target x86_64-apple-macosx10.15.0 \
+// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s | llvm-nm - | \
+// RUN: FileCheck -check-prefix=CHECK-DEFAULT %s
+
+// RUN: %clang -fobjc-arc -Wno-objc-root-class \
+// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=1 \
+// RUN: -target x86_64-apple-macosx10.15.0 \
+// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s -S -emit-llvm | \
+// RUN: FileCheck -check-prefix=CHECK-WRAPPER-IR-DEFINE %s
+
+// RUN: %clang -fobjc-arc -Wno-objc-root-class -DNO_OBJC_IMPL \
+// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=1 \
+// RUN: -target x86_64-apple-macosx10.15.0 \
+// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s -S -emit-llvm | \
+// RUN: FileCheck -check-prefix=CHECK-WRAPPER-IR-DECLARE %s
+
+// RUN: not %clang -fobjc-arc -Wno-objc-root-class -DENABLE_PROTOCOL_DIRECT_FAIL \
+// RUN: -DENABLE_VISIBLE_OBJC_DIRECT=1 \
+// RUN: -target x86_64-apple-macosx10.15.0 \
+// RUN: -ObjC -fobjc-runtime=ios -FFoundation -c -o - %s -S -emit-llvm 2>&1 | \
+// RUN: FileCheck -check-prefix=CHECK-PROTOCOL-DIRECT-FAIL %s
+
+// CHECK-WRAPPER: T _-<C testMethod:bar:>
+         // TODO: Fix this
+// CHECK-DEFAULT: t -[C testMethod:bar:]
+// CHECK-WRAPPER-IR-DEFINE: define {{(dso_local )?}}void @"-<C testMethod:bar:>"
+// CHECK-WRAPPER-IR-DECLARE: declare {{(dso_local )?}}void @"-<C testMethod:bar:>"
+// CHECK-PROTOCOL-DIRECT-FAIL: error: 'objc_direct' attribute cannot be applied to methods declared in an Objective-C protocol
+
+#if ENABLE_VISIBLE_OBJC_DIRECT
+#define OBJC_DIRECT __attribute__((objc_direct_visible))
+#else
+#define OBJC_DIRECT
+#endif
+
+@interface C
+- (void)testMethod:(int)arg1 bar:(float)arg2 OBJC_DIRECT;
+@end
+
+#ifndef NO_OBJC_IMPL
+@implementation C
+- (void)testMethod:(int)arg1 bar:(float)arg2 OBJC_DIRECT {
+}
+@end
+#endif
+
+#ifdef ENABLE_PROTOCOL_DIRECT_FAIL
+@protocol ProtoDirectVisibleFail
+- (void)protoMethod OBJC_DIRECT;      // expected-error {{'objc_direct' attribute cannot be applied to methods declared in an Objective-C protocol}}
+@end
+#endif
+
+C *c;
+
+void f() {
+  [c testMethod:1 bar:1.0];
+}
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -2943,6 +2943,22 @@
   }
 }
 
+static void handleObjCDirectVisibleAttr(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()) {
+    if (!D->hasAttr<ObjCDirectAttr>())
+      handleSimpleAttribute<ObjCDirectAttr>(S, D, AL);
+    handleSimpleAttribute<ObjCDirectVisibleAttr>(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)) {
@@ -8783,6 +8799,9 @@
   case ParsedAttr::AT_ObjCDirect:
     handleObjCDirectAttr(S, D, AL);
     break;
+  case ParsedAttr::AT_ObjCDirectVisible:
+    handleObjCDirectVisibleAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_ObjCDirectMembers:
     handleObjCDirectMembersAttr(S, D, AL);
     handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
Index: clang/lib/CodeGen/CGObjCRuntime.cpp
===================================================================
--- clang/lib/CodeGen/CGObjCRuntime.cpp
+++ clang/lib/CodeGen/CGObjCRuntime.cpp
@@ -474,7 +474,7 @@
   std::string buffer;
   llvm::raw_string_ostream out(buffer);
   CGM.getCXXABI().getMangleContext().mangleObjCMethodName(OMD, out,
-                                       /*includePrefixByte=*/true,
+                                       /*includePrefixByte=*/!OMD->isDirectMethodVisible(),
                                        includeCategoryName);
   return buffer;
 }
Index: clang/lib/CodeGen/CGObjC.cpp
===================================================================
--- clang/lib/CodeGen/CGObjC.cpp
+++ clang/lib/CodeGen/CGObjC.cpp
@@ -760,7 +760,9 @@
 
   const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
   if (OMD->isDirectMethod()) {
-    Fn->setVisibility(llvm::Function::HiddenVisibility);
+    Fn->setVisibility(OMD->isDirectMethodVisible()
+                          ? llvm::Function::DefaultVisibility
+                          : llvm::Function::HiddenVisibility);
     CGM.SetLLVMFunctionAttributes(OMD, FI, Fn, /*IsThunk=*/false);
     CGM.SetLLVMFunctionAttributesForDefinition(OMD, Fn);
   } else {
Index: clang/lib/AST/Mangle.cpp
===================================================================
--- clang/lib/AST/Mangle.cpp
+++ clang/lib/AST/Mangle.cpp
@@ -359,10 +359,16 @@
   }
 
   // \01+[ContainerName(CategoryName) SelectorName]
+  // Note: If we are mangling for an objc_direct method with external visibility
+  //       then the standard mangling scheme will not work. We must replace the
+  //       square braces with angle braces so in the case of visible direct objc
+  //       methods it results in: +<ContainerName(CategoryName) SelectorName>
+  //       This will include a prefix _ on Darwin.
   if (includePrefixByte) {
     OS << '\01';
   }
-  OS << (MD->isInstanceMethod() ? '-' : '+') << '[';
+  OS << (MD->isInstanceMethod() ? '-' : '+');
+  OS << (MD->isDirectMethodVisible() ? '<' : '[');
   if (const auto *CID = MD->getCategory()) {
     OS << CID->getClassInterface()->getName();
     if (includeCategoryNamespace) {
@@ -376,7 +382,7 @@
   }
   OS << ' ';
   MD->getSelector().print(OS);
-  OS << ']';
+  OS << (MD->isDirectMethodVisible() ? '>' : ']');
 }
 
 void MangleContext::mangleObjCMethodNameAsSourceName(const ObjCMethodDecl *MD,
Index: clang/lib/AST/DeclObjC.cpp
===================================================================
--- clang/lib/AST/DeclObjC.cpp
+++ clang/lib/AST/DeclObjC.cpp
@@ -838,6 +838,10 @@
          !getASTContext().getLangOpts().ObjCDisableDirectMethodsForTesting;
 }
 
+bool ObjCMethodDecl::isDirectMethodVisible() const {
+  return isDirectMethod() && hasAttr<ObjCDirectVisibleAttr>();
+}
+
 bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
   return getMethodFamily() == OMF_init &&
       hasAttr<ObjCDesignatedInitializerAttr>();
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -5406,6 +5406,19 @@
   }];
 }
 
+def ObjCDirectVisibleDocs : Documentation {
+    let Category = DocCatDecl;
+    let Content = [{
+This attribute specifies that the ``objc_direct`` method it is placed on is to
+be vislble (ie skip marking for hidden linkage) so that it can be called across
+link unit boundaries. If the ``objc_direct`` attribute is not set manually this
+also enables the attribute (since it would not makesense to do otherwise). When
+an ObjC method is marked visible its internal name is scrubed of characters that
+cause problems with linkage or do not conform to ABI
+(ie ``\0-[a: ]`` becomes ``-<a: >``).
+    }];
+}
+
 def ObjCNonRuntimeProtocolDocs : 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
@@ -2262,6 +2262,13 @@
   let Documentation = [ObjCDirectMembersDocs];
 }
 
+def ObjCDirectVisible : Attr {
+  let Spellings = [Clang<"objc_direct_visible">];
+  let Subjects = SubjectList<[ObjCMethod], ErrorDiag>;
+  let LangOpts = [ObjC];
+  let Documentation = [ObjCDirectVisibleDocs];
+}
+
 def ObjCNonRuntimeProtocol : Attr {
   let Spellings = [Clang<"objc_non_runtime_protocol">];
   let Subjects = SubjectList<[ObjCProtocol], ErrorDiag>;
Index: clang/include/clang/AST/DeclObjC.h
===================================================================
--- clang/include/clang/AST/DeclObjC.h
+++ clang/include/clang/AST/DeclObjC.h
@@ -487,6 +487,9 @@
   /// True if the method is tagged as objc_direct
   bool isDirectMethod() const;
 
+  /// True if the method is tagged as objc_direct and objc_direct_visible
+  bool isDirectMethodVisible() const;
+
   /// True if the method has a parameter that's destroyed in the callee.
   bool hasParamDestroyedInCallee() const;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to