Skip to content

Commit f918e78

Browse files
authored
Merge pull request #22916 from DougGregor/objc-renamed-protocol-metadata-5.0
[5.0] [IRGen] Mangle Swift @objc(renamed) protocols as Objective-C in metadata
2 parents fa5d493 + 98de1d8 commit f918e78

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;
@@ -171,7 +175,7 @@ class ASTMangler : public Mangler {
171175
};
172176

173177
static Optional<SpecialContext>
174-
getSpecialManglingContext(const ValueDecl *decl);
178+
getSpecialManglingContext(const ValueDecl *decl, bool useObjCProtocolNames);
175179

176180
static const clang::NamedDecl *
177181
getClangDeclForMangling(const ValueDecl *decl);

lib/AST/ASTMangler.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ std::string ASTMangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC) {
371371

372372
DWARFMangling = true;
373373
beginMangling();
374-
374+
375375
if (DC)
376376
bindGenericParameters(DC);
377377

@@ -580,6 +580,33 @@ static StringRef getPrivateDiscriminatorIfNecessary(const ValueDecl *decl) {
580580
return discriminator.str();
581581
}
582582

583+
/// If the declaration is an @objc protocol defined in Swift and the
584+
/// Objective-C name has been overrridden from the default, return the
585+
/// specified name.
586+
///
587+
/// \param useObjCProtocolNames When false, always returns \c None.
588+
static Optional<std::string> getOverriddenSwiftProtocolObjCName(
589+
const ValueDecl *decl,
590+
bool useObjCProtocolNames) {
591+
if (!useObjCProtocolNames)
592+
return None;
593+
594+
auto proto = dyn_cast<ProtocolDecl>(decl);
595+
if (!proto) return None;
596+
597+
if (!proto->isObjC()) return None;
598+
599+
// If there is an 'objc' attribute with a name, use that name.
600+
if (auto objc = proto->getAttrs().getAttribute<ObjCAttr>()) {
601+
if (auto name = objc->getName()) {
602+
llvm::SmallString<4> buffer;
603+
return std::string(name->getString(buffer));
604+
}
605+
}
606+
607+
return None;
608+
}
609+
583610
void ASTMangler::appendDeclName(const ValueDecl *decl) {
584611
DeclBaseName name = decl->getBaseName();
585612
assert(!name.isSpecial() && "Cannot print special names");
@@ -604,6 +631,11 @@ void ASTMangler::appendDeclName(const ValueDecl *decl) {
604631
appendOperator("oi");
605632
break;
606633
}
634+
} else if (auto objCName =
635+
getOverriddenSwiftProtocolObjCName(decl, UseObjCProtocolNames)) {
636+
// @objc Swift protocols should be mangled as Objective-C protocols,
637+
// so append the Objective-C runtime name.
638+
appendIdentifier(*objCName);
607639
} else if (!name.empty()) {
608640
appendIdentifier(name.getIdentifier().str());
609641
} else {
@@ -1314,7 +1346,8 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
13141346
}
13151347

13161348
Optional<ASTMangler::SpecialContext>
1317-
ASTMangler::getSpecialManglingContext(const ValueDecl *decl) {
1349+
ASTMangler::getSpecialManglingContext(const ValueDecl *decl,
1350+
bool useObjCProtocolNames) {
13181351
// Declarations provided by a C module have a special context mangling.
13191352
// known-context ::= 'So'
13201353
//
@@ -1329,6 +1362,11 @@ ASTMangler::getSpecialManglingContext(const ValueDecl *decl) {
13291362
}
13301363
}
13311364

1365+
// If @objc Swift protocols should be mangled as Objective-C protocols,
1366+
// they are defined in the Objective-C context.
1367+
if (getOverriddenSwiftProtocolObjCName(decl, useObjCProtocolNames))
1368+
return ASTMangler::ObjCContext;
1369+
13321370
// Nested types imported from C should also get use the special "So" context.
13331371
if (isa<TypeDecl>(decl)) {
13341372
if (auto *clangDecl = cast_or_null<clang::NamedDecl>(decl->getClangDecl())){
@@ -1354,7 +1392,7 @@ ASTMangler::getSpecialManglingContext(const ValueDecl *decl) {
13541392
/// This is the top-level entrypoint for mangling <context>.
13551393
void ASTMangler::appendContextOf(const ValueDecl *decl) {
13561394
// Check for a special mangling context.
1357-
if (auto context = getSpecialManglingContext(decl)) {
1395+
if (auto context = getSpecialManglingContext(decl, UseObjCProtocolNames)) {
13581396
switch (*context) {
13591397
case ClangImporterContext:
13601398
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)