[llvm] 984744a - Fix a variety of minor issues with ObjC method mangling:

John McCall via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 29 16:52:00 PDT 2020


Author: John McCall
Date: 2020-09-29T19:51:53-04:00
New Revision: 984744a1314ce165378e7945bc45995302a8cb80

URL: https://github.com/llvm/llvm-project/commit/984744a1314ce165378e7945bc45995302a8cb80
DIFF: https://github.com/llvm/llvm-project/commit/984744a1314ce165378e7945bc45995302a8cb80.diff

LOG: Fix a variety of minor issues with ObjC method mangling:

- Fix a memory leak accidentally introduced yesterday by using CodeGen's
  existing mangling context instead of creating a new context afresh.

- Move GNU-runtime ObjC method mangling into the AST mangler; this will
  eventually be necessary to support direct methods there, but is also
  just the right architecture.

- Make the Apple-runtime method mangling work properly when given an
  interface declaration, fixing a bug (which had solidified into a test)
  where mangling a category method from the interface could cause it to
  be mangled as if the category name was a class name.  (Category names
  are namespaced within their class and have no global meaning.)

- Fix a code cross-reference in dsymutil.

Based on a patch by Ellis Hoag.

Added: 
    

Modified: 
    clang/include/clang/AST/DeclObjC.h
    clang/lib/AST/DeclObjC.cpp
    clang/lib/AST/Mangle.cpp
    clang/lib/CodeGen/CGObjCGNU.cpp
    clang/lib/CodeGen/CGObjCMac.cpp
    clang/lib/CodeGen/CGObjCRuntime.cpp
    clang/lib/CodeGen/CGObjCRuntime.h
    clang/test/AST/ast-dump-decl-json.m
    llvm/tools/dsymutil/SymbolMap.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h
index 5613ed8370c0..32e69d7fe1ed 100644
--- a/clang/include/clang/AST/DeclObjC.h
+++ b/clang/include/clang/AST/DeclObjC.h
@@ -320,6 +320,13 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
     return const_cast<ObjCMethodDecl*>(this)->getClassInterface();
   }
 
+  /// If this method is declared or implemented in a category, return
+  /// that category.
+  ObjCCategoryDecl *getCategory();
+  const ObjCCategoryDecl *getCategory() const {
+    return const_cast<ObjCMethodDecl*>(this)->getCategory();
+  }
+
   Selector getSelector() const { return getDeclName().getObjCSelector(); }
 
   QualType getReturnType() const { return MethodDeclType; }

diff  --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index 5c8b34731f36..78ef9a1c67c9 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -1165,6 +1165,14 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
   llvm_unreachable("unknown method context");
 }
 
+ObjCCategoryDecl *ObjCMethodDecl::getCategory() {
+  if (auto *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext()))
+    return CD;
+  if (auto *IMD = dyn_cast<ObjCCategoryImplDecl>(getDeclContext()))
+    return IMD->getCategoryDecl();
+  return nullptr;
+}
+
 SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const {
   const auto *TSI = getReturnTypeSourceInfo();
   if (TSI)

diff  --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index a67f57688e30..3282fcbd584f 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -308,12 +308,44 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
                                          raw_ostream &OS,
                                          bool includePrefixByte,
                                          bool includeCategoryNamespace) {
+  if (getASTContext().getLangOpts().ObjCRuntime.isGNUFamily()) {
+    // This is the mangling we've always used on the GNU runtimes, but it
+    // has obvious collisions in the face of underscores within class
+    // names, category names, and selectors; maybe we should improve it.
+
+    OS << (MD->isClassMethod() ? "_c_" : "_i_")
+       << MD->getClassInterface()->getName() << '_';
+
+    if (includeCategoryNamespace) {
+      if (auto category = MD->getCategory())
+        OS << category->getName();
+    }
+    OS << '_';
+
+    auto selector = MD->getSelector();
+    for (unsigned slotIndex = 0,
+                  numArgs = selector.getNumArgs(),
+                  slotEnd = std::max(numArgs, 1U);
+           slotIndex != slotEnd; ++slotIndex) {
+      if (auto name = selector.getIdentifierInfoForSlot(slotIndex))
+        OS << name->getName();
+
+      // Replace all the positions that would've been ':' with '_'.
+      // That's after each slot except that a unary selector doesn't
+      // end in ':'.
+      if (numArgs)
+        OS << '_';
+    }
+
+    return;
+  }
+
   // \01+[ContainerName(CategoryName) SelectorName]
   if (includePrefixByte) {
     OS << '\01';
   }
   OS << (MD->isInstanceMethod() ? '-' : '+') << '[';
-  if (const auto *CID = dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) {
+  if (const auto *CID = MD->getCategory()) {
     OS << CID->getClassInterface()->getName();
     if (includeCategoryNamespace) {
       OS << '(' << *CID << ')';

diff  --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index bb9c494ae68e..ed36e4a5cbc1 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -42,16 +42,6 @@ using namespace CodeGen;
 
 namespace {
 
-std::string SymbolNameForMethod( StringRef ClassName,
-     StringRef CategoryName, const Selector MethodName,
-    bool isClassMethod) {
-  std::string MethodNameColonStripped = MethodName.getAsString();
-  std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
-      ':', '_');
-  return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
-    CategoryName + "_" + MethodNameColonStripped).str();
-}
-
 /// Class that lazily initialises the runtime function.  Avoids inserting the
 /// types and the function declaration into a module if they're not used, and
 /// avoids constructing the type more than once if it's used more than once.
@@ -2823,9 +2813,7 @@ GenerateMethodList(StringRef ClassName,
   ASTContext &Context = CGM.getContext();
   for (const auto *OMD : Methods) {
     llvm::Constant *FnPtr =
-      TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName,
-                                                OMD->getSelector(),
-                                                isClassMethodList));
+      TheModule.getFunction(getSymbolNameForMethod(OMD));
     assert(FnPtr && "Can't generate metadata for method that doesn't exist");
     auto Method = MethodArray.beginStruct(ObjCMethodTy);
     if (isV2ABI) {
@@ -3873,18 +3861,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
 
 llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
                                           const ObjCContainerDecl *CD) {
-  const ObjCCategoryImplDecl *OCD =
-    dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext());
-  StringRef CategoryName = OCD ? OCD->getName() : "";
-  StringRef ClassName = CD->getName();
-  Selector MethodName = OMD->getSelector();
-  bool isClassMethod = !OMD->isInstanceMethod();
-
   CodeGenTypes &Types = CGM.getTypes();
   llvm::FunctionType *MethodTy =
     Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
-  std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
-      MethodName, isClassMethod);
+  std::string FunctionName = getSymbolNameForMethod(OMD);
 
   llvm::Function *Method
     = llvm::Function::Create(MethodTy,

diff  --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index e2f4cabce278..aa50d2173a7d 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -1079,8 +1079,8 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
   void EmitImageInfo();
 
 public:
-  CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
-    CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) { }
+  CGObjCCommonMac(CodeGen::CodeGenModule &cgm)
+      : CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) {}
 
   bool isNonFragileABI() const {
     return ObjCABI == 2;
@@ -4001,18 +4001,14 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
   if (OMD->isDirectMethod()) {
     Method = GenerateDirectMethod(OMD, CD);
   } else {
-    SmallString<256> Name;
-    llvm::raw_svector_ostream OS(Name);
-    const auto &MC = CGM.getContext().createMangleContext();
-    MC->mangleObjCMethodName(OMD, OS, /*includePrefixByte=*/true,
-                             /*includeCategoryNamespace=*/true);
+    auto Name = getSymbolNameForMethod(OMD);
 
     CodeGenTypes &Types = CGM.getTypes();
     llvm::FunctionType *MethodTy =
         Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
     Method =
         llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage,
-                               Name.str(), &CGM.getModule());
+                               Name, &CGM.getModule());
   }
 
   MethodDefinitions.insert(std::make_pair(OMD, Method));
@@ -4057,14 +4053,10 @@ CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD,
     // Replace the cached function in the map.
     I->second = Fn;
   } else {
-    SmallString<256> Name;
-    llvm::raw_svector_ostream OS(Name);
-    const auto &MC = CGM.getContext().createMangleContext();
-    MC->mangleObjCMethodName(OMD, OS, /*includePrefixByte=*/true,
-                             /*includeCategoryNamespace=*/false);
+    auto Name = getSymbolNameForMethod(OMD, /*include category*/ false);
 
     Fn = llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage,
-                                Name.str(), &CGM.getModule());
+                                Name, &CGM.getModule());
     DirectMethodDefinitions.insert(std::make_pair(COMD, Fn));
   }
 

diff  --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp
index 39efe040302d..9bf4d83f9bc4 100644
--- a/clang/lib/CodeGen/CGObjCRuntime.cpp
+++ b/clang/lib/CodeGen/CGObjCRuntime.cpp
@@ -390,3 +390,13 @@ clang::CodeGen::emitObjCProtocolObject(CodeGenModule &CGM,
                                        const ObjCProtocolDecl *protocol) {
   return CGM.getObjCRuntime().GetOrEmitProtocol(protocol);
 }
+
+std::string CGObjCRuntime::getSymbolNameForMethod(const ObjCMethodDecl *OMD,
+                                                  bool includeCategoryName) {
+  std::string buffer;
+  llvm::raw_string_ostream out(buffer);
+  CGM.getCXXABI().getMangleContext().mangleObjCMethodName(OMD, out,
+                                       /*includePrefixByte=*/true,
+                                       includeCategoryName);
+  return buffer;
+}

diff  --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h
index a2c189585f7b..60f98389067e 100644
--- a/clang/lib/CodeGen/CGObjCRuntime.h
+++ b/clang/lib/CodeGen/CGObjCRuntime.h
@@ -115,6 +115,9 @@ class CGObjCRuntime {
 public:
   virtual ~CGObjCRuntime();
 
+  std::string getSymbolNameForMethod(const ObjCMethodDecl *method,
+                                     bool includeCategoryName = true);
+
   /// Generate the function required to register all Objective-C components in
   /// this compilation unit with the runtime library.
   virtual llvm::Function *ModuleInitFunction() = 0;

diff  --git a/clang/test/AST/ast-dump-decl-json.m b/clang/test/AST/ast-dump-decl-json.m
index d100811c1c24..be730039f9bf 100644
--- a/clang/test/AST/ast-dump-decl-json.m
+++ b/clang/test/AST/ast-dump-decl-json.m
@@ -836,7 +836,7 @@ void f() {
 // CHECK-NEXT:     }
 // CHECK-NEXT:    },
 // CHECK-NEXT:    "name": "bar",
-// CHECK-NEXT:    "mangledName": "-[TestObjCCategoryDecl bar]",
+// CHECK-NEXT:    "mangledName": "-[TestObjCClass(TestObjCCategoryDecl) bar]",
 // CHECK-NEXT:    "returnType": {
 // CHECK-NEXT:     "qualType": "void"
 // CHECK-NEXT:    },

diff  --git a/llvm/tools/dsymutil/SymbolMap.cpp b/llvm/tools/dsymutil/SymbolMap.cpp
index abf7557ca61e..07a54795a841 100644
--- a/llvm/tools/dsymutil/SymbolMap.cpp
+++ b/llvm/tools/dsymutil/SymbolMap.cpp
@@ -47,7 +47,7 @@ StringRef SymbolMapTranslator::operator()(StringRef Input) {
     return Translation;
 
   // Objective-C symbols for the MachO symbol table start with a \1. Please see
-  // `CGObjCCommonMac::GetNameForMethod` in clang.
+  // `MangleContext::mangleObjCMethodName` in clang.
   if (Translation[0] == 1)
     return StringRef(Translation).drop_front();
 


        


More information about the llvm-commits mailing list