[clang] 984744a - Fix a variety of minor issues with ObjC method mangling:
John McCall via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 29 16:52:02 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 cfe-commits
mailing list