plotfi updated this revision to Diff 451041.
plotfi added a comment.
Herald added a reviewer: aaron.ballman.

Updating implementation to use an objc_direct_visible attr to explicitly mark 
when we want objc_direct to be exposed outside of the link unit.

Work on dropping the selector param has been proposed in D131424 
<https://reviews.llvm.org/D131424>


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/CodeGen/CGObjC.cpp
  clang/lib/CodeGen/CGObjCMac.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,41 @@
+// RUN: %clang -fobjc-arc -Wno-objc-root-class -ObjC -fobjc-runtime=ios -FFoundation \
+// 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: -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: -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
+
+// 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:>"
+
+@interface C
+- (void)testMethod:(int)arg1 bar:(float)arg2 __attribute((objc_direct)) __attribute__((objc_direct_visible));
+@end
+
+#ifndef NO_OBJC_IMPL
+@implementation C
+- (void)testMethod:(int)arg1 bar:(float)arg2 __attribute((objc_direct)) __attribute__((objc_direct_visible)) {
+}
+@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,20 @@
   }
 }
 
+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()) {
+    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)) {
@@ -8782,6 +8796,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/CGObjCMac.cpp
===================================================================
--- clang/lib/CodeGen/CGObjCMac.cpp
+++ clang/lib/CodeGen/CGObjCMac.cpp
@@ -4021,6 +4021,20 @@
     DirectMethodDefinitions.insert(std::make_pair(COMD, Fn));
   }
 
+  // If we want to explicitly export objc_direct methods, we need a name fixup.
+  if (OMD->isDirectMethodVisible() && Fn->getName().str()[0] == '\1') {
+    // Drop '\1' to work with dlsym.
+    std::string Name = Fn->getName().str().substr(1);
+
+    assert(Name[0] == '-' || Name[0] == '+');
+    assert(Name[1] == '[' && Name[Name.length() - 1] == ']');
+
+    // replace "[ ]" by  "< >" to avoid strip by ld64.
+    Name = Name.substr(0, 1) + "<" + Name.substr(2, Name.length() - 3) + ">";
+
+    Fn->setName(Name);
+  }
+
   return Fn;
 }
 
Index: clang/lib/CodeGen/CGObjC.cpp
===================================================================
--- clang/lib/CodeGen/CGObjC.cpp
+++ clang/lib/CodeGen/CGObjC.cpp
@@ -761,6 +761,8 @@
   const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
   if (OMD->isDirectMethod()) {
     Fn->setVisibility(llvm::Function::HiddenVisibility);
+    if (OMD->isDirectMethodVisible())
+      Fn->setVisibility(llvm::Function::DefaultVisibility);
     CGM.SetLLVMFunctionAttributes(OMD, FI, Fn, /*IsThunk=*/false);
     CGM.SetLLVMFunctionAttributesForDefinition(OMD, Fn);
   } else {
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
@@ -5377,6 +5377,15 @@
   }];
 }
 
+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.
+    }];
+}
+
 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
@@ -2248,6 +2248,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
  • [PATCH] D86049: RFC: Impleme... Puyan Lotfi via Phabricator via cfe-commits

Reply via email to