Skip to content

Commit c1c4f52

Browse files
authored
[Mangling] Include private discriminators in constructor manglings. (#9880)
Previously, two constructors with the same full name and argument types would get identical manglings even if they were declared 'private' or 'fileprivate' in different files. This would lead to symbol collisions in whole-module builds. Add a new mangling node for private discriminators on base-name-less decls to make this unique. This still doesn't fix the existing issue with private members, named or not, conflicting when they're in the /same/ file, but since Swift 4 makes those members visible to one another (SE-0169) that's only an issue in Swift 3 mode anyway, and as such probably won't get fixed at all. rdar://problem/27758199
1 parent 5d1412d commit c1c4f52

File tree

8 files changed

+117
-48
lines changed

8 files changed

+117
-48
lines changed

docs/ABI.rst

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,8 @@ Entities
877877
curry-thunk ::= 'Tc'
878878

879879
// The leading type is the function type
880-
entity-spec ::= type 'fC' // allocating constructor
881-
entity-spec ::= type 'fc' // non-allocating constructor
880+
entity-spec ::= type file-discriminator? 'fC' // allocating constructor
881+
entity-spec ::= type file-discriminator? 'fc' // non-allocating constructor
882882
entity-spec ::= type 'fU' INDEX // explicit anonymous closure expression
883883
entity-spec ::= type 'fu' INDEX // implicit anonymous closure
884884
entity-spec ::= 'fA' INDEX // default argument N+1 generator
@@ -911,14 +911,16 @@ Entities
911911

912912
decl-name ::= identifier
913913
decl-name ::= identifier 'L' INDEX // locally-discriminated declaration
914-
decl-name ::= identifier identifier 'LL' // file-discriminated declaration
915-
916-
The first identifier in a file-discriminated ``<decl-name>>`` is a string that
917-
represents the file the original declaration came from.
918-
It should be considered unique within the enclosing module.
919-
The second identifier is the name of the entity.
920-
Not all declarations marked ``private`` declarations will use this mangling;
921-
if the entity's context is enough to uniquely identify the entity, the simple
914+
decl-name ::= identifier identifier 'LL' // file-discriminated declaration
915+
916+
file-discriminator ::= identifier 'Ll' // anonymous file-discriminated declaration
917+
918+
The identifier in a ``<file-discriminator>`` and the first identifier in a
919+
file-discriminated ``<decl-name>`` is a string that represents the file the
920+
original declaration came from. It should be considered unique within the
921+
enclosing module. The second identifier is the name of the entity. Not all
922+
declarations marked ``private`` declarations will use this mangling; if the
923+
entity's context is enough to uniquely identify the entity, the simple
922924
``identifier`` form is preferred.
923925

924926
Declaration Contexts

lib/AST/ASTMangler.cpp

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,29 @@ static unsigned getUnnamedParamIndex(const ParamDecl *D) {
501501
llvm_unreachable("param not found");
502502
}
503503

504+
static StringRef getPrivateDiscriminatorIfNecessary(const ValueDecl *decl) {
505+
if (!decl->hasAccessibility() ||
506+
decl->getFormalAccess() > Accessibility::FilePrivate ||
507+
isInPrivateOrLocalContext(decl)) {
508+
return StringRef();
509+
}
510+
511+
// Mangle non-local private declarations with a textual discriminator
512+
// based on their enclosing file.
513+
auto topLevelContext = decl->getDeclContext()->getModuleScopeContext();
514+
auto fileUnit = cast<FileUnit>(topLevelContext);
515+
516+
Identifier discriminator =
517+
fileUnit->getDiscriminatorForPrivateValue(decl);
518+
assert(!discriminator.empty());
519+
assert(!isNonAscii(discriminator.str()) &&
520+
"discriminator contains non-ASCII characters");
521+
(void)&isNonAscii;
522+
assert(!clang::isDigit(discriminator.str().front()) &&
523+
"not a valid identifier");
524+
return discriminator.str();
525+
}
526+
504527
void ASTMangler::appendDeclName(const ValueDecl *decl) {
505528
if (decl->isOperator()) {
506529
auto name = decl->getBaseName().getIdentifier().str();
@@ -536,27 +559,10 @@ void ASTMangler::appendDeclName(const ValueDecl *decl) {
536559
// Mangle local declarations with a numeric discriminator.
537560
return appendOperator("L", Index(decl->getLocalDiscriminator()));
538561
}
539-
if (decl->hasAccessibility() &&
540-
decl->getFormalAccess() <= Accessibility::FilePrivate &&
541-
!isInPrivateOrLocalContext(decl)) {
542-
// Mangle non-local private declarations with a textual discriminator
543-
// based on their enclosing file.
544-
545-
// The first <identifier> is a discriminator string unique to the decl's
546-
// original source file.
547-
auto topLevelContext = decl->getDeclContext()->getModuleScopeContext();
548-
auto fileUnit = cast<FileUnit>(topLevelContext);
549-
550-
Identifier discriminator =
551-
fileUnit->getDiscriminatorForPrivateValue(decl);
552-
assert(!discriminator.empty());
553-
assert(!isNonAscii(discriminator.str()) &&
554-
"discriminator contains non-ASCII characters");
555-
(void)&isNonAscii;
556-
assert(!clang::isDigit(discriminator.str().front()) &&
557-
"not a valid identifier");
558-
559-
appendIdentifier(discriminator.str());
562+
563+
StringRef privateDiscriminator = getPrivateDiscriminatorIfNecessary(decl);
564+
if (!privateDiscriminator.empty()) {
565+
appendIdentifier(privateDiscriminator.str());
560566
return appendOperator("LL");
561567
}
562568
}
@@ -1802,6 +1808,11 @@ void ASTMangler::appendConstructorEntity(const ConstructorDecl *ctor,
18021808
bool isAllocating) {
18031809
appendContextOf(ctor);
18041810
appendDeclType(ctor);
1811+
StringRef privateDiscriminator = getPrivateDiscriminatorIfNecessary(ctor);
1812+
if (!privateDiscriminator.empty()) {
1813+
appendIdentifier(privateDiscriminator);
1814+
appendOperator("Ll");
1815+
}
18051816
appendOperator(isAllocating ? "fC" : "fc");
18061817
}
18071818

lib/Demangling/Demangler.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,10 @@ NodePointer Demangler::demangleLocalIdentifier() {
641641
NodePointer name = popNode(isDeclName);
642642
return createWithChildren(Node::Kind::PrivateDeclName, discriminator, name);
643643
}
644+
if (nextIf('l')) {
645+
NodePointer discriminator = popNode(Node::Kind::Identifier);
646+
return createWithChild(Node::Kind::PrivateDeclName, discriminator);
647+
}
644648
NodePointer discriminator = demangleIndexAsNode();
645649
NodePointer name = popNode(isDeclName);
646650
return createWithChildren(Node::Kind::LocalDeclName, discriminator, name);
@@ -1672,7 +1676,14 @@ NodePointer Demangler::demangleMetatypeRepresentation() {
16721676
}
16731677

16741678
NodePointer Demangler::demangleFunctionEntity() {
1675-
enum { None, Type, TypeAndName, TypeAndIndex, Index } Args;
1679+
enum {
1680+
None,
1681+
Type,
1682+
TypeAndName,
1683+
TypeAndMaybePrivateName,
1684+
TypeAndIndex,
1685+
Index
1686+
} Args;
16761687

16771688
Node::Kind Kind = Node::Kind::EmptyList;
16781689
switch (nextChar()) {
@@ -1681,8 +1692,10 @@ NodePointer Demangler::demangleFunctionEntity() {
16811692
case 'E': Args = None; Kind = Node::Kind::IVarDestroyer; break;
16821693
case 'e': Args = None; Kind = Node::Kind::IVarInitializer; break;
16831694
case 'i': Args = None; Kind = Node::Kind::Initializer; break;
1684-
case 'C': Args = Type; Kind = Node::Kind::Allocator; break;
1685-
case 'c': Args = Type; Kind = Node::Kind::Constructor; break;
1695+
case 'C':
1696+
Args = TypeAndMaybePrivateName; Kind = Node::Kind::Allocator; break;
1697+
case 'c':
1698+
Args = TypeAndMaybePrivateName; Kind = Node::Kind::Constructor; break;
16861699
case 'g': Args = TypeAndName; Kind = Node::Kind::Getter; break;
16871700
case 'G': Args = TypeAndName; Kind = Node::Kind::GlobalGetter; break;
16881701
case 's': Args = TypeAndName; Kind = Node::Kind::Setter; break;
@@ -1727,6 +1740,10 @@ NodePointer Demangler::demangleFunctionEntity() {
17271740
Child2 = popNode(Node::Kind::Type);
17281741
Child1 = popNode(isDeclName);
17291742
break;
1743+
case TypeAndMaybePrivateName:
1744+
Child1 = popNode(Node::Kind::PrivateDeclName);
1745+
Child2 = popNode(Node::Kind::Type);
1746+
break;
17301747
case TypeAndIndex:
17311748
Child1 = demangleIndexAsNode();
17321749
Child2 = popNode(Node::Kind::Type);
@@ -1743,6 +1760,11 @@ NodePointer Demangler::demangleFunctionEntity() {
17431760
case Index:
17441761
Entity = addChild(Entity, Child1);
17451762
break;
1763+
case TypeAndMaybePrivateName:
1764+
if (Child1)
1765+
Entity = addChild(Entity, Child1);
1766+
Entity = addChild(Entity, Child2);
1767+
break;
17461768
case TypeAndName:
17471769
case TypeAndIndex:
17481770
Entity = addChild(Entity, Child1);

lib/Demangling/NodePrinter.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -867,13 +867,19 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
867867
Printer << " #" << (Node->getChild(0)->getIndex() + 1);
868868
return nullptr;
869869
case Node::Kind::PrivateDeclName:
870-
if (Options.ShowPrivateDiscriminators)
871-
Printer << '(';
870+
if (Node->getNumChildren() > 1) {
871+
if (Options.ShowPrivateDiscriminators)
872+
Printer << '(';
872873

873-
print(Node->getChild(1));
874+
print(Node->getChild(1));
874875

875-
if (Options.ShowPrivateDiscriminators)
876-
Printer << " in " << Node->getChild(0)->getText() << ')';
876+
if (Options.ShowPrivateDiscriminators)
877+
Printer << " in " << Node->getChild(0)->getText() << ')';
878+
} else {
879+
if (Options.ShowPrivateDiscriminators) {
880+
Printer << "(in " << Node->getChild(0)->getText() << ')';
881+
}
882+
}
877883
return nullptr;
878884
case Node::Kind::Module:
879885
if (Options.DisplayModuleNames)
@@ -1472,7 +1478,7 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
14721478
"__allocating_init" : "init");
14731479
case Node::Kind::Constructor:
14741480
return printEntity(Node, asPrefixContext, TypePrinting::FunctionStyle,
1475-
/*hasName*/false, "init");
1481+
/*hasName*/Node->getNumChildren() > 2, "init");
14761482
case Node::Kind::Destructor:
14771483
return printEntity(Node, asPrefixContext, TypePrinting::NoType,
14781484
/*hasName*/false, "deinit");
@@ -1771,8 +1777,9 @@ printEntity(NodePointer Entity, bool asPrefixContext, TypePrinting TypePr,
17711777
Printer << " of ";
17721778
ExtraName = "";
17731779
}
1780+
size_t CurrentPos = Printer.getStringRef().size();
17741781
print(Entity->getChild(1));
1775-
if (!ExtraName.empty())
1782+
if (Printer.getStringRef().size() != CurrentPos && !ExtraName.empty())
17761783
Printer << '.';
17771784
}
17781785
if (!ExtraName.empty()) {

lib/Demangling/Remangler.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ class Remangler {
273273
void mangleAnyNominalType(Node *node);
274274
void mangleAnyGenericType(Node *node, char TypeOp);
275275
void mangleGenericArgs(Node *node, char &Separator);
276+
void mangleAnyConstructor(Node *node, char kindOp);
276277

277278
#define NODE(ID) \
278279
void mangle##ID(Node *node);
@@ -478,8 +479,7 @@ void Remangler::mangleGenericArgs(Node *node, char &Separator) {
478479
}
479480

480481
void Remangler::mangleAllocator(Node *node) {
481-
mangleChildNodes(node);
482-
Buffer << "fC";
482+
mangleAnyConstructor(node, 'C');
483483
}
484484

485485
void Remangler::mangleArgumentTuple(Node *node) {
@@ -600,9 +600,18 @@ void Remangler::mangleClass(Node *node) {
600600
mangleAnyNominalType(node);
601601
}
602602

603+
void Remangler::mangleAnyConstructor(Node *node, char kindOp) {
604+
mangleChildNode(node, 0);
605+
if (node->getNumChildren() > 2) {
606+
assert(node->getNumChildren() == 3);
607+
mangleChildNode(node, 2);
608+
}
609+
mangleChildNode(node, 1);
610+
Buffer << "f" << kindOp;
611+
}
612+
603613
void Remangler::mangleConstructor(Node *node) {
604-
mangleChildNodes(node);
605-
Buffer << "fc";
614+
mangleAnyConstructor(node, 'c');
606615
}
607616

608617
void Remangler::mangleDeallocator(Node *node) {
@@ -1385,7 +1394,7 @@ void Remangler::manglePrefixOperator(Node *node) {
13851394

13861395
void Remangler::manglePrivateDeclName(Node *node) {
13871396
mangleChildNodesReversed(node);
1388-
Buffer << "LL";
1397+
Buffer << (node->getNumChildren() == 1 ? "Ll" : "LL");
13891398
}
13901399

13911400
void Remangler::mangleProtocol(Node *node) {

test/Demangle/Inputs/manglings.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,4 @@ _T0Tk ---> _T0Tk
259259
_T0A8 ---> _T0A8
260260
_T0s30ReversedRandomAccessCollectionVyxGTfq3nnpf_nTfq1cn_nTfq4x_n ---> _T0s30ReversedRandomAccessCollectionVyxGTfq3nnpf_nTfq1cn_nTfq4x_n
261261
_T03abc6testitySiFTm ---> merged abc.testit(Swift.Int) -> ()
262-
262+
_T04main4TestCACSi1x_tc6_PRIV_Llfc ---> main.Test.(in _PRIV_).init(x: Swift.Int) -> main.Test

test/Demangle/Inputs/simplified-manglings.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,4 @@ _TTRXFo_oCSo13SKPhysicsBodydVSC7CGPointdVSC8CGVectordGSpV10ObjectiveC8ObjCBool__
204204
_T0So13SKPhysicsBodyCSC7CGPointVSC8CGVectorVSpy10ObjectiveC8ObjCBoolVGIxxyyy_AbdFSpyAIGIyByyyy_TR ---> thunk for @callee_owned (@owned SKPhysicsBody, @unowned CGPoint, @unowned CGVector, @unowned UnsafeMutablePointer<ObjCBool>) -> ()
205205
_T04main1_yyF ---> _()
206206
_T03abc6testitySiFTm ---> testit(_:)
207-
207+
_T04main4TestCACSi1x_tc6_PRIV_Llfc ---> Test.init(x:)

test/SILGen/mangling_private.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,32 @@ private func privateFunc() -> Int {
2121
public struct PublicStruct {
2222
// CHECK-LABEL: sil private @_T016mangling_private12PublicStructV0B6Method33_A3CCBB841DB59E79A4AD4EE458655068LLyyFZ
2323
private static func privateMethod() {}
24+
25+
// CHECK-LABEL: sil private @_T016mangling_private12PublicStructVACSi1x_tc33_A3CCBB841DB59E79A4AD4EE458655068LlfC
26+
private init(x: Int) {}
2427
}
2528

2629
public struct InternalStruct {
2730
// CHECK-LABEL: sil private @_T016mangling_private14InternalStructV0B6Method33_A3CCBB841DB59E79A4AD4EE458655068LLyyFZ
2831
private static func privateMethod() {}
32+
33+
// CHECK-LABEL: sil private @_T016mangling_private14InternalStructVACSi1x_tc33_A3CCBB841DB59E79A4AD4EE458655068LlfC
34+
private init(x: Int) {}
2935
}
3036

3137
private struct PrivateStruct {
3238
// CHECK-LABEL: sil private @_T016mangling_private13PrivateStruct33_A3CCBB841DB59E79A4AD4EE458655068LLV0B6MethodyyFZ
3339
private static func privateMethod() {}
3440

41+
// CHECK-LABEL: sil private @_T016mangling_private13PrivateStruct33_A3CCBB841DB59E79A4AD4EE458655068LLVADSi1x_tcfC
42+
private init(x: Int) {}
43+
3544
struct Inner {
3645
// CHECK-LABEL: sil private @_T016mangling_private13PrivateStruct33_A3CCBB841DB59E79A4AD4EE458655068LLV5InnerV0B6MethodyyFZ
3746
private static func privateMethod() {}
47+
48+
// CHECK-LABEL: sil private @_T016mangling_private13PrivateStruct33_A3CCBB841DB59E79A4AD4EE458655068LLV5InnerVAFSi1x_tcfC
49+
private init(x: Int) {}
3850
}
3951
}
4052

@@ -47,10 +59,16 @@ func localTypes() {
4759
extension PublicStruct {
4860
// CHECK-LABEL: sil private @_T016mangling_private12PublicStructV16extPrivateMethod33_A3CCBB841DB59E79A4AD4EE458655068LLyyF
4961
private func extPrivateMethod() {}
62+
63+
// CHECK-LABEL: sil private @_T016mangling_private12PublicStructVACSi3ext_tc33_A3CCBB841DB59E79A4AD4EE458655068LlfC
64+
private init(ext: Int) {}
5065
}
5166
extension PrivateStruct {
5267
// CHECK-LABEL: sil private @_T016mangling_private13PrivateStruct33_A3CCBB841DB59E79A4AD4EE458655068LLV03extC6MethodyyF
5368
private func extPrivateMethod() {}
69+
70+
// CHECK-LABEL: sil private @_T016mangling_private13PrivateStruct33_A3CCBB841DB59E79A4AD4EE458655068LLVADSi3ext_tcfC
71+
private init(ext: Int) {}
5472
}
5573

5674
// CHECK-LABEL: sil private @_T016mangling_private10localTypesyyF11LocalStructL_V0B6MethodyyFZ

0 commit comments

Comments
 (0)