Skip to content

Commit 28c489c

Browse files
committed
[ABI] Mangle retroactive conformances as part of bound generic types.
A "retroactive" protocol conformance is a conformance that is provided by a module that is neither the module that defines the protocol nor the module that defines the conforming type. It is possible for such conformances to conflict at runtime, if defined in different modules that were not both visible to the compiler at the same time. When mangling a bound generic type, also mangle retroactive protocol conformances that were needed to satisfy the generic requirements of the generic type. This prevents name collisions between (e.g.) types formed using retroactive conformances from different modules. The impact on the size of the mangling is expected to be relatively small, because most conformances are not retroactive. Fixes the ABI part of rdar://problem/14375889.
1 parent e1fc3dc commit 28c489c

18 files changed

+157
-11
lines changed

docs/ABI/Mangling.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ Types
369369
type ::= type 'Xm' METATYPE-REPR // existential metatype with representation
370370
type ::= 'Xe' // error or unresolved type
371371
372-
bound-generic-type ::= type 'y' (type* '_')* type* 'G' // one type-list per nesting level of type
372+
bound-generic-type ::= type 'y' (type* '_')* type* retroactive-conformance* 'G' // one type-list per nesting level of type
373373
bound-generic-type ::= substitution
374374

375375
FUNCTION-KIND ::= 'f' // @thin function type
@@ -559,6 +559,17 @@ values indicates a single generic parameter at the outermost depth::
559559
A generic signature must only precede an operator character which is different
560560
from any character in a ``<GENERIC-PARAM-COUNT>``.
561561

562+
::
563+
564+
retroactive-conformance ::= protocol-conformance 'g' INDEX
565+
566+
When a protocol conformance used to satisfy one of a bound generic type's
567+
generic requirements is retroactive (i.e., it is specified in a module other
568+
than the module of the conforming type or the conformed-to protocol), it is
569+
mangled with its offset into the set of conformance requirements, the
570+
root protocol conformance, and the suffix 'g'.
571+
572+
562573
Identifiers
563574
~~~~~~~~~~~
564575

include/swift/AST/ASTMangler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ class ASTMangler : public Mangler {
190190

191191
void appendBoundGenericArgs(Type type, bool &isFirstArgList);
192192

193+
/// Append any retroactive conformances.
194+
void appendRetroactiveConformances(Type type);
195+
193196
void appendImplFunctionType(SILFunctionType *fn);
194197

195198
void appendContextOf(const ValueDecl *decl);

include/swift/AST/ProtocolConformance.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,10 @@ class NormalProtocolConformance : public ProtocolConformance,
468468
/// defines the conforming type.
469469
bool isRetroactive() const;
470470

471+
/// Whether this conformance was synthesized automatically in multiple
472+
/// modules, but in a manner that ensures that all copies are equivalent.
473+
bool isSynthesizedNonUnique() const;
474+
471475
/// Retrieve the type witness and type decl (if one exists)
472476
/// for the given associated type.
473477
std::pair<Type, TypeDecl *>

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ NODE(QualifiedArchetype)
144144
NODE(ReabstractionThunk)
145145
NODE(ReabstractionThunkHelper)
146146
NODE(RelatedEntityDeclName)
147+
NODE(RetroactiveConformance)
147148
NODE(ReturnType)
148149
NODE(Shared)
149150
NODE(SILBoxType)

include/swift/Demangling/Demangler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ class Demangler : public NodeFactory {
429429
NodePointer demangleBoundGenericArgs(NodePointer nominalType,
430430
const Vector<NodePointer> &TypeLists,
431431
size_t TypeListIdx);
432+
NodePointer demangleRetroactiveConformance();
432433
NodePointer demangleInitializer();
433434
NodePointer demangleImplParamConvention();
434435
NodePointer demangleImplResultConvention(Node::Kind ConvKind);

lib/AST/ASTMangler.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "swift/AST/Module.h"
2424
#include "swift/AST/ParameterList.h"
2525
#include "swift/AST/ProtocolConformance.h"
26+
#include "swift/AST/ProtocolConformanceRef.h"
27+
#include "swift/Basic/Defer.h"
2628
#include "swift/Demangling/ManglingUtils.h"
2729
#include "swift/Demangling/Demangler.h"
2830
#include "swift/Strings.h"
@@ -856,6 +858,7 @@ void ASTMangler::appendType(Type type) {
856858
appendAnyGenericType(NDecl);
857859
bool isFirstArgList = true;
858860
appendBoundGenericArgs(type, isFirstArgList);
861+
appendRetroactiveConformances(type);
859862
appendOperator("G");
860863
}
861864
addSubstitution(type.getPointer());
@@ -1088,6 +1091,44 @@ void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) {
10881091
}
10891092
}
10901093

1094+
void ASTMangler::appendRetroactiveConformances(Type type) {
1095+
auto nominal = type->getAnyNominal();
1096+
if (!nominal) return;
1097+
1098+
auto genericSig = nominal->getGenericSignatureOfContext();
1099+
if (!genericSig) return;
1100+
1101+
auto module = Mod ? Mod : nominal->getModuleContext();
1102+
auto subMap = type->getContextSubstitutionMap(module, nominal);
1103+
if (subMap.empty()) return;
1104+
1105+
unsigned numProtocolRequirements = 0;
1106+
for (const auto &req: genericSig->getRequirements()) {
1107+
if (req.getKind() != RequirementKind::Conformance)
1108+
continue;
1109+
1110+
SWIFT_DEFER {
1111+
++numProtocolRequirements;
1112+
};
1113+
1114+
// Fast path: we're in the module of the protocol.
1115+
auto proto = req.getSecondType()->castTo<ProtocolType>()->getDecl();
1116+
if (proto->getModuleContext() == module)
1117+
continue;
1118+
1119+
auto conformance =
1120+
subMap.lookupConformance(req.getFirstType()->getCanonicalType(), proto);
1121+
if (!conformance || !conformance->isConcrete()) continue;
1122+
1123+
auto normal = conformance->getConcrete()->getRootNormalConformance();
1124+
if (!normal->isRetroactive() || normal->isSynthesizedNonUnique())
1125+
continue;
1126+
1127+
appendProtocolConformance(normal);
1128+
appendOperator("g", Index(numProtocolRequirements));
1129+
}
1130+
}
1131+
10911132
static char getParamConvention(ParameterConvention conv) {
10921133
// @in and @out are mangled the same because they're put in
10931134
// different places.

lib/AST/ProtocolConformance.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/AST/Substitution.h"
2525
#include "swift/AST/Types.h"
2626
#include "swift/AST/TypeWalker.h"
27+
#include "swift/ClangImporter/ClangModule.h"
2728
#include "llvm/ADT/MapVector.h"
2829
#include "llvm/ADT/Statistic.h"
2930
#include "llvm/ADT/TinyPtrVector.h"
@@ -353,6 +354,10 @@ bool NormalProtocolConformance::isRetroactive() const {
353354
return true;
354355
}
355356

357+
bool NormalProtocolConformance::isSynthesizedNonUnique() const {
358+
return isa<ClangModuleUnit>(getDeclContext()->getModuleScopeContext());
359+
}
360+
356361
ArrayRef<Requirement> ProtocolConformance::getConditionalRequirements() const {
357362
CONFORMANCE_SUBCLASS_DISPATCH(getConditionalRequirements, ());
358363
}

lib/Demangling/Demangler.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ NodePointer Demangler::demangleOperator() {
458458
case 'c': return popFunctionType(Node::Kind::FunctionType);
459459
case 'd': return createNode(Node::Kind::VariadicMarker);
460460
case 'f': return demangleFunctionEntity();
461+
case 'g': return demangleRetroactiveConformance();
461462
case 'h': return createType(createWithChild(Node::Kind::Shared,
462463
popTypeAndGetChild()));
463464
case 'i': return demangleSubscript();
@@ -1060,7 +1061,27 @@ NodePointer Demangler::popProtocol() {
10601061
return createType(Proto);
10611062
}
10621063

1064+
NodePointer Demangler::demangleRetroactiveConformance() {
1065+
NodePointer Index = demangleIndexAsNode();
1066+
NodePointer Conformance = popProtocolConformance();
1067+
if (!Index || !Conformance)
1068+
return nullptr;
1069+
1070+
return createWithChildren(Node::Kind::RetroactiveConformance,
1071+
Index, Conformance);
1072+
}
1073+
10631074
NodePointer Demangler::demangleBoundGenericType() {
1075+
NodePointer RetroactiveConformances = nullptr;
1076+
while (auto RetroactiveConformance =
1077+
popNode(Node::Kind::RetroactiveConformance)) {
1078+
if (!RetroactiveConformances)
1079+
RetroactiveConformances = createNode(Node::Kind::TypeList);
1080+
RetroactiveConformances->addChild(RetroactiveConformance, *this);
1081+
}
1082+
if (RetroactiveConformances)
1083+
RetroactiveConformances->reverseChildren();
1084+
10641085
Vector<NodePointer> TypeListList(*this, 4);
10651086
for (;;) {
10661087
NodePointer TList = createNode(Node::Kind::TypeList);
@@ -1076,7 +1097,10 @@ NodePointer Demangler::demangleBoundGenericType() {
10761097
return nullptr;
10771098
}
10781099
NodePointer Nominal = popTypeAndGetAnyGeneric();
1079-
NodePointer NTy = createType(demangleBoundGenericArgs(Nominal, TypeListList, 0));
1100+
NodePointer BoundNode = demangleBoundGenericArgs(Nominal, TypeListList, 0);
1101+
if (RetroactiveConformances)
1102+
BoundNode->addChild(RetroactiveConformances, *this);
1103+
NodePointer NTy = createType(BoundNode);
10801104
addSubstitution(NTy);
10811105
return NTy;
10821106
}

lib/Demangling/NodePrinter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ class NodePrinter {
398398
case Node::Kind::ReabstractionThunk:
399399
case Node::Kind::ReabstractionThunkHelper:
400400
case Node::Kind::RelatedEntityDeclName:
401+
case Node::Kind::RetroactiveConformance:
401402
case Node::Kind::Setter:
402403
case Node::Kind::Shared:
403404
case Node::Kind::SILBoxLayout:
@@ -1083,6 +1084,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
10831084
printChildren(Node);
10841085
}
10851086
return nullptr;
1087+
case Node::Kind::RetroactiveConformance:
1088+
if (Node->getNumChildren() != 2)
1089+
return nullptr;
1090+
1091+
Printer << "retroactive @ ";
1092+
print(Node->getChild(0));
1093+
print(Node->getChild(1));
1094+
return nullptr;
10861095
case Node::Kind::Weak:
10871096
Printer << "weak ";
10881097
print(Node->getChild(0));

lib/Demangling/OldRemangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,10 @@ void Remangler::mangleFunctionSignatureSpecializationParamKind(Node *node) {
659659
unreachable("This should never be called");
660660
}
661661

662+
void Remangler::mangleRetroactiveConformance(Node *node) {
663+
unreachable("Retroactive conformances aren't in the old mangling");
664+
}
665+
662666
void Remangler::mangleProtocolConformance(Node *node) {
663667
// type, protocol name, context
664668
assert(node->getNumChildren() == 3);

lib/Demangling/Remangler.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,15 @@ void Remangler::mangleAnyNominalType(Node *node) {
437437
mangleAnyNominalType(unboundType);
438438
char Separator = 'y';
439439
mangleGenericArgs(node, Separator);
440+
441+
if (node->getNumChildren() == 3) {
442+
// Retroactive conformances.
443+
auto listNode = node->getChild(2);
444+
for (size_t Idx = 0, Num = listNode->getNumChildren(); Idx < Num; ++Idx) {
445+
mangle(listNode->getChild(Idx));
446+
}
447+
}
448+
440449
Buffer << 'G';
441450
addSubstitution(entry);
442451
return;
@@ -1446,6 +1455,12 @@ void Remangler::mangleProtocol(Node *node) {
14461455
mangleAnyGenericType(node, "P");
14471456
}
14481457

1458+
void Remangler::mangleRetroactiveConformance(Node *node) {
1459+
mangleProtocolConformance(node->getChild(1));
1460+
Buffer << 'g';
1461+
mangleIndex(node->getChild(0)->getIndex());
1462+
}
1463+
14491464
void Remangler::mangleProtocolConformance(Node *node) {
14501465
Node *Ty = getChildOfType(node->getChild(0));
14511466
Node *GenSig = nullptr;

lib/IRGen/GenDecl.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2644,9 +2644,8 @@ namespace {
26442644
void addFlags() {
26452645
// Miscellaneous flags.
26462646
Flags = Flags.withIsRetroactive(Conformance->isRetroactive());
2647-
Flags = Flags.withIsSynthesizedNonUnique(
2648-
isa<ClangModuleUnit>(
2649-
Conformance->getDeclContext()->getModuleScopeContext()));
2647+
Flags =
2648+
Flags.withIsSynthesizedNonUnique(Conformance->isSynthesizedNonUnique());
26502649

26512650
// Add the flags.
26522651
B.addInt32(Flags.getIntValue());

test/Demangle/Inputs/manglings.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,4 @@ _T0So13GenericOptionas8HashableSCsACP9hashValueSivgTW ---> {T:} protocol witness
307307
_T0So11CrappyColorVs16RawRepresentableSCMA --> reflection metadata associated type descriptor __C.CrappyColor : Swift.RawRepresentable in __C_Synthesized
308308
$S28protocol_conformance_records15NativeValueTypeVAA8RuncibleAAMc --> protocol conformance descriptor for protocol_conformance_records.NativeValueType : protocol_conformance_records.Runcible in protocol_conformance_records
309309
$SSC9SomeErrorLeVD ---> __C_Synthesized.related decl 'e' for SomeError
310+
$S20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAg_AiJ1QAAg1_GF -> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()

test/IRGen/objc_bridge.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ import Foundation
8888
// CHECK: { i8*, i8*, i8* } {
8989
// CHECK: i8* getelementptr inbounds ([11 x i8], [11 x i8]* @"\01L_selector_data(acceptSet:)", i64 0, i64 0),
9090
// CHECK: i8* getelementptr inbounds ([11 x i8], [11 x i8]* @{{[0-9]+}}, i64 0, i64 0),
91-
// CHECK: i8* bitcast (void (%3*, i8*, %4*)* @"$S11objc_bridge3BasC9acceptSetyys0E0VyACGFTo" to i8*)
91+
// CHECK: i8* bitcast (void (%3*, i8*, %4*)* @"$S11objc_bridge3BasC9acceptSetyys0E0VyACSo8NSObjectCs8Hashable10ObjectiveCg_GFTo" to i8*)
9292
// CHECK: }
9393
// CHECK: { i8*, i8*, i8* } {
9494
// CHECK: i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(.cxx_destruct)", i64 0, i64 0),

test/SILGen/Inputs/RetroactiveA.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
public protocol P { }
2+
public protocol Q { }

test/SILGen/Inputs/RetroactiveB.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
public struct X { }
2+
public struct Y { }
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -enable-sil-ownership -o %t %S/Inputs/RetroactiveA.swift
3+
// RUN: %target-swift-frontend -emit-module -enable-sil-ownership -o %t %S/Inputs/RetroactiveB.swift
4+
// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -I %t %s | %FileCheck %s
5+
6+
7+
import RetroactiveA
8+
import RetroactiveB
9+
10+
struct Z<T: P, U: Hashable, V: Q> { }
11+
12+
extension X: P { } // retroactive
13+
extension Y: Q { } // retroactive
14+
15+
// CHECK: sil hidden @$S20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAg_AiJ1QAAg1_GF
16+
func test0(_: Z<X, Int, Y>) { }
17+
18+
struct Z2<T: P> {
19+
struct Inner<V: Q> { }
20+
}
21+
22+
// CHECK: sil hidden @$S20mangling_retroactive5test1yyAA2Z2V5InnerVy12RetroactiveB1XV_AG1YVAI0F1A1PAAg_AkL1QAAg0_GF
23+
func test1(_: Z2<X>.Inner<Y>) { }

test/SILGen/objc_dictionary_bridging.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,12 @@ import gizmo
5151
var property: Dictionary<Foo, Foo> = [:]
5252

5353
// Property getter
54-
// CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvgTo : $@convention(objc_method) (Foo) -> @autoreleased NSDictionary
54+
// CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_GvgTo : $@convention(objc_method) (Foo) -> @autoreleased NSDictionary
55+
// @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvpfi
5556
// CHECK: bb0([[SELF:%[0-9]+]] : @unowned $Foo):
5657
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
5758
// CHECK: [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
58-
// CHECK: [[GETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvg : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
59+
// CHECK: [[GETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvg : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
5960
// CHECK: [[DICT:%[0-9]+]] = apply [[GETTER]]([[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
6061
// CHECK: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
6162
// CHECK: destroy_value [[SELF_COPY]]
@@ -65,10 +66,10 @@ import gizmo
6566
// CHECK: end_borrow [[BORROWED_DICT]] from [[DICT]]
6667
// CHECK: destroy_value [[DICT]]
6768
// CHECK: return [[NSDICT]] : $NSDictionary
68-
// CHECK: } // end sil function '$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvgTo'
69+
// CHECK: } // end sil function
6970

7071
// Property setter
71-
// CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvsTo : $@convention(objc_method) (NSDictionary, Foo) -> ()
72+
// CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_GvsTo : $@convention(objc_method) (NSDictionary, Foo) -> ()
7273
// CHECK: bb0([[NSDICT:%[0-9]+]] : @unowned $NSDictionary, [[SELF:%[0-9]+]] : @unowned $Foo):
7374
// CHECK: [[NSDICT_COPY:%.*]] = copy_value [[NSDICT]]
7475
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
@@ -78,7 +79,7 @@ import gizmo
7879
// CHECK: [[DICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[OPT_NSDICT]], [[DICT_META]])
7980

8081
// CHECK: [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
81-
// CHECK: [[SETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvs : $@convention(method) (@owned Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
82+
// CHECK: [[SETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvs : $@convention(method) (@owned Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
8283
// CHECK: [[RESULT:%[0-9]+]] = apply [[SETTER]]([[DICT]], [[BORROWED_SELF_COPY]]) : $@convention(method) (@owned Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
8384
// CHECK: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
8485
// CHECK: destroy_value [[SELF_COPY]]

0 commit comments

Comments
 (0)