Skip to content

Commit 009dc06

Browse files
authored
Merge pull request #22917 from DougGregor/objc-renamed-protocol-metadata-5.1
[5.1] [IRGen] Mangle Swift @objc(renamed) protocols as Objective-C in metadata
2 parents 04f3751 + e974ffb commit 009dc06

File tree

6 files changed

+107
-5
lines changed

6 files changed

+107
-5
lines changed

include/swift/AST/ASTMangler.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ class ASTMangler : public Mangler {
3838
/// Optimize out protocol names if a type only conforms to one protocol.
3939
bool OptimizeProtocolNames = true;
4040

41+
/// If enabled, use Objective-C runtime names when mangling @objc Swift
42+
/// protocols.
43+
bool UseObjCProtocolNames = false;
44+
4145
/// If enabled, non-canonical types are allowed and type alias types get a
4246
/// special mangling.
4347
bool DWARFMangling;
@@ -187,7 +191,7 @@ class ASTMangler : public Mangler {
187191
};
188192

189193
static Optional<SpecialContext>
190-
getSpecialManglingContext(const ValueDecl *decl);
194+
getSpecialManglingContext(const ValueDecl *decl, bool useObjCProtocolNames);
191195

192196
static const clang::NamedDecl *
193197
getClangDeclForMangling(const ValueDecl *decl);

lib/AST/ASTMangler.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ std::string ASTMangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC) {
367367
DWARFMangling = true;
368368
OptimizeProtocolNames = false;
369369
beginMangling();
370-
370+
371371
if (DC)
372372
bindGenericParameters(DC);
373373

@@ -601,6 +601,33 @@ static StringRef getPrivateDiscriminatorIfNecessary(const ValueDecl *decl) {
601601
return discriminator.str();
602602
}
603603

604+
/// If the declaration is an @objc protocol defined in Swift and the
605+
/// Objective-C name has been overrridden from the default, return the
606+
/// specified name.
607+
///
608+
/// \param useObjCProtocolNames When false, always returns \c None.
609+
static Optional<std::string> getOverriddenSwiftProtocolObjCName(
610+
const ValueDecl *decl,
611+
bool useObjCProtocolNames) {
612+
if (!useObjCProtocolNames)
613+
return None;
614+
615+
auto proto = dyn_cast<ProtocolDecl>(decl);
616+
if (!proto) return None;
617+
618+
if (!proto->isObjC()) return None;
619+
620+
// If there is an 'objc' attribute with a name, use that name.
621+
if (auto objc = proto->getAttrs().getAttribute<ObjCAttr>()) {
622+
if (auto name = objc->getName()) {
623+
llvm::SmallString<4> buffer;
624+
return std::string(name->getString(buffer));
625+
}
626+
}
627+
628+
return None;
629+
}
630+
604631
void ASTMangler::appendDeclName(const ValueDecl *decl) {
605632
DeclBaseName name = decl->getBaseName();
606633
assert(!name.isSpecial() && "Cannot print special names");
@@ -625,6 +652,11 @@ void ASTMangler::appendDeclName(const ValueDecl *decl) {
625652
appendOperator("oi");
626653
break;
627654
}
655+
} else if (auto objCName =
656+
getOverriddenSwiftProtocolObjCName(decl, UseObjCProtocolNames)) {
657+
// @objc Swift protocols should be mangled as Objective-C protocols,
658+
// so append the Objective-C runtime name.
659+
appendIdentifier(*objCName);
628660
} else if (!name.empty()) {
629661
appendIdentifier(name.getIdentifier().str());
630662
} else {
@@ -1335,7 +1367,8 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
13351367
}
13361368

13371369
Optional<ASTMangler::SpecialContext>
1338-
ASTMangler::getSpecialManglingContext(const ValueDecl *decl) {
1370+
ASTMangler::getSpecialManglingContext(const ValueDecl *decl,
1371+
bool useObjCProtocolNames) {
13391372
// Declarations provided by a C module have a special context mangling.
13401373
// known-context ::= 'So'
13411374
//
@@ -1351,6 +1384,11 @@ ASTMangler::getSpecialManglingContext(const ValueDecl *decl) {
13511384
}
13521385
}
13531386

1387+
// If @objc Swift protocols should be mangled as Objective-C protocols,
1388+
// they are defined in the Objective-C context.
1389+
if (getOverriddenSwiftProtocolObjCName(decl, useObjCProtocolNames))
1390+
return ASTMangler::ObjCContext;
1391+
13541392
// Nested types imported from C should also get use the special "So" context.
13551393
if (isa<TypeDecl>(decl)) {
13561394
if (auto *clangDecl = cast_or_null<clang::NamedDecl>(decl->getClangDecl())){
@@ -1376,7 +1414,7 @@ ASTMangler::getSpecialManglingContext(const ValueDecl *decl) {
13761414
/// This is the top-level entrypoint for mangling <context>.
13771415
void ASTMangler::appendContextOf(const ValueDecl *decl) {
13781416
// Check for a special mangling context.
1379-
if (auto context = getSpecialManglingContext(decl)) {
1417+
if (auto context = getSpecialManglingContext(decl, UseObjCProtocolNames)) {
13801418
switch (*context) {
13811419
case ClangImporterContext:
13821420
return appendOperator("SC");

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,9 @@ IRGenModule::getAddrOfParentContextDescriptor(DeclContext *from,
747747
// Some types get special treatment.
748748
if (auto Type = dyn_cast<NominalTypeDecl>(from)) {
749749
// Use a special module context if we have one.
750-
if (auto context = Mangle::ASTMangler::getSpecialManglingContext(Type)) {
750+
if (auto context =
751+
Mangle::ASTMangler::getSpecialManglingContext(
752+
Type, /*UseObjCProtocolNames=*/false)) {
751753
switch (*context) {
752754
case Mangle::ASTMangler::ObjCContext:
753755
return {getAddrOfObjCModuleContextDescriptor(),

lib/IRGen/IRGenMangler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ IRGenMangler::withSymbolicReferences(IRGenModule &IGM,
8383
llvm::function_ref<void ()> body) {
8484
Mod = IGM.getSwiftModule();
8585
OptimizeProtocolNames = false;
86+
UseObjCProtocolNames = true;
8687

8788
llvm::SaveAndRestore<bool>
8889
AllowSymbolicReferencesLocally(AllowSymbolicReferences);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name main -o %t/a.out
3+
// RUN: %target-codesign %t/a.out
4+
// RUN: %target-run %t/a.out
5+
// REQUIRES: executable_test
6+
// REQUIRES: objc_interop
7+
8+
import Foundation
9+
import StdlibUnittest
10+
11+
@objc(MyObjCProtocol) public protocol MyProtocol { }
12+
13+
public protocol OtherProtocol {
14+
associatedtype AssocType
15+
}
16+
17+
public struct MyThing: OtherProtocol {
18+
public typealias AssocType = MyProtocol
19+
}
20+
21+
func getAssocType<T: OtherProtocol>(_: T.Type) -> Any.Type {
22+
return T.AssocType.self
23+
}
24+
let RenamedObjCDemangleTests = TestSuite("RenamedObjCDemangle")
25+
26+
RenamedObjCDemangleTests.test("@objc protocols") {
27+
expectEqual(getAssocType(MyThing.self), MyProtocol.self)
28+
}
29+
30+
@objc(MyObjCClass) class MyClass: NSObject { }
31+
32+
struct MyClassWrapper: OtherProtocol {
33+
typealias AssocType = MyClass
34+
}
35+
36+
RenamedObjCDemangleTests.test("@objc classes") {
37+
expectEqual(getAssocType(MyClassWrapper.self), MyClass.self)
38+
}
39+
40+
runAllTests()

test/Runtime/demangleToMetadataObjC.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,24 @@ import Dispatch
1111
let DemangleToMetadataTests = TestSuite("DemangleToMetadataObjC")
1212

1313
@objc class C : NSObject { }
14+
@objc(CRenamedInObjC) class CRenamed : NSObject { }
1415
@objc enum E: Int { case a }
1516
@objc protocol P1 { }
1617
protocol P2 { }
1718
@objc protocol P3: P1 { }
1819
@objc protocol mainP4 { }
1920

21+
@objc(P5RenamedInObjC) protocol P5 { }
22+
2023
DemangleToMetadataTests.test("@objc classes") {
2124
expectEqual(type(of: C()), _typeByName("4main1CC")!)
25+
26+
// @objc class that's been renamed, which can be found by its Objective-C
27+
// name...
28+
expectEqual(type(of: CRenamed()), _typeByName("So14CRenamedInObjCC")!)
29+
30+
// ... but not by it's Swift name.
31+
expectNil(_typeByName("4main8CRenamed"))
2232
}
2333

2434
DemangleToMetadataTests.test("@objc enums") {
@@ -40,9 +50,16 @@ DemangleToMetadataTests.test("Objective-C classes") {
4050
}
4151

4252
func f1_composition_NSCoding(_: NSCoding) { }
53+
func f1_composition_P5(_: P5) { }
4354

4455
DemangleToMetadataTests.test("Objective-C protocols") {
4556
expectEqual(type(of: f1_composition_NSCoding), _typeByName("yySo8NSCoding_pc")!)
57+
58+
// @objc Swift protocols can be found by their Objective-C names...
59+
expectEqual(type(of: f1_composition_P5), _typeByName("yySo15P5RenamedInObjC_pc")!)
60+
61+
// ... but not their Swift names.
62+
expectNil(_typeByName("yy4main2P5_pc"))
4663
}
4764

4865
DemangleToMetadataTests.test("Classes that don't exist") {

0 commit comments

Comments
 (0)