Skip to content

Demangler: fix demangling and remangling of associated type paths. #12434

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Globals
global ::= protocol-conformance 'WP' // protocol witness table

global ::= protocol-conformance identifier 'Wt' // associated type metadata accessor
global ::= protocol-conformance identifier nominal-type 'WT' // associated type witness table accessor
global ::= protocol-conformance assoc_type_path nominal-type 'WT' // associated type witness table accessor
global ::= type protocol-conformance 'Wl' // lazy protocol witness table accessor
global ::= type 'WV' // value witness table
global ::= entity 'Wv' DIRECTNESS // field offset
Expand All @@ -84,6 +84,8 @@ Globals
global ::= type 'Wr' // Outlined Retain Function Type
global ::= type 'Ws' // Outlined Release Function Type

assoc_type_path ::= identifier '_' identifier*

DIRECTNESS ::= 'd' // direct
DIRECTNESS ::= 'i' // indirect

Expand Down
2 changes: 2 additions & 0 deletions include/swift/Basic/Mangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ class Mangler {
static void verify(StringRef mangledName);
static void verifyOld(StringRef mangledName);

void dump();

/// Appends a mangled identifier string.
void appendIdentifier(StringRef ident);

Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -189,5 +189,6 @@ NODE(OutlinedConsume)
NODE(OutlinedRetain)
NODE(OutlinedRelease)
NODE(OutlinedVariable)
NODE(AssocTypePath)
#undef CONTEXT_NODE
#undef NODE
4 changes: 4 additions & 0 deletions lib/Basic/Mangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ void Mangler::appendIdentifier(StringRef ident) {
recordOpStat("<identifier>", OldPos);
}

void Mangler::dump() {
llvm::errs() << Buffer.str() << '\n';
}

bool Mangler::tryMangleSubstitution(const void *ptr) {
auto ir = Substitutions.find(ptr);
if (ir == Substitutions.end())
Expand Down
14 changes: 12 additions & 2 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1653,10 +1653,20 @@ NodePointer Demangler::demangleWitness() {
}
case 'T': {
NodePointer ProtoTy = popNode(Node::Kind::Type);
NodePointer Name = popNode(isDeclName);
NodePointer AssocTypePath = createNode(Node::Kind::AssocTypePath);
bool firstElem = false;
do {
firstElem = (popNode(Node::Kind::FirstElementMarker) != nullptr);
NodePointer AssocTyName = popNode(isDeclName);
if (!AssocTyName)
return nullptr;
AssocTypePath->addChild(AssocTyName, *this);
} while (!firstElem);
AssocTypePath->reverseChildren();

NodePointer Conf = popProtocolConformance();
return createWithChildren(Node::Kind::AssociatedTypeWitnessTableAccessor,
Conf, Name, ProtoTy);
Conf, AssocTypePath, ProtoTy);
}
case 'y': {
return createWithChild(Node::Kind::OutlinedCopy,
Expand Down
4 changes: 4 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ class NodePrinter {
case Node::Kind::OutlinedRetain:
case Node::Kind::OutlinedRelease:
case Node::Kind::OutlinedVariable:
case Node::Kind::AssocTypePath:
return false;
}
printer_unreachable("bad node kind");
Expand Down Expand Up @@ -1779,6 +1780,9 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
&& Node->getChild(0)->getKind() == Node::Kind::Type);
print(Node->getChild(0));
return nullptr;
case Node::Kind::AssocTypePath:
printChildren(Node->begin(), Node->end(), ".");
return nullptr;
}
printer_unreachable("bad node kind!");
}
Expand Down
4 changes: 4 additions & 0 deletions lib/Demangling/OldRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1797,6 +1797,10 @@ void Remangler::mangleSILBoxImmutableField(Node *node) {
mangleType(node->getChild(0));
}

void Remangler::mangleAssocTypePath(Node *node) {
unreachable("unsupported");
}

/// The top-level interface to the remangler.
std::string Demangle::mangleNodeOld(const NodePointer &node) {
if (!node) return "";
Expand Down
8 changes: 8 additions & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,14 @@ void Remangler::mangleSILBoxImmutableField(Node *node) {
unreachable("should be part of SILBoxTypeWithLayout");
}

void Remangler::mangleAssocTypePath(Node *node) {
bool FirstElem = true;
for (NodePointer Child : *node) {
mangle(Child);
mangleListSeparator(FirstElem);
}
}

} // anonymous namespace

/// The top-level interface to the remangler.
Expand Down
8 changes: 5 additions & 3 deletions lib/IRGen/IRGenMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,18 @@ class IRGenMangler : public Mangle::ASTMangler {
const ProtocolDecl *Proto) {
beginMangling();
appendProtocolConformance(Conformance);
appendAssociatedTypePath(AssociatedType);
bool isFirstAssociatedTypeIdentifier = true;
appendAssociatedTypePath(AssociatedType, isFirstAssociatedTypeIdentifier);
appendAnyGenericType(Proto);
appendOperator("WT");
return finalize();
}

void appendAssociatedTypePath(CanType associatedType) {
void appendAssociatedTypePath(CanType associatedType, bool &isFirst) {
if (auto memberType = dyn_cast<DependentMemberType>(associatedType)) {
appendAssociatedTypePath(memberType.getBase());
appendAssociatedTypePath(memberType.getBase(), isFirst);
appendIdentifier(memberType->getName().str());
appendListSeparator(isFirst);
} else {
assert(isa<GenericTypeParamType>(associatedType));
}
Expand Down
1 change: 1 addition & 0 deletions test/Demangle/Inputs/manglings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,4 @@ _T0So11UITextFieldC4textSSSgvgToTepb_ ---> outlined bridged method (pb) of @objc
_T0So11UITextFieldC4textSSSgvgToTeab_ ---> outlined bridged method (ab) of @objc __ObjC.UITextField.text.getter : Swift.String?
_T0So5GizmoC11doSomethingSQyypGSQySaySSGGFToTembnn_ ---> outlined bridged method (mbnn) of @objc __ObjC.Gizmo.doSomething([Swift.String]!) -> Any!
_T0So5GizmoC12modifyStringSQySSGAD_Si10withNumberSQyypG0D6FoobartFToTembnnnb_ ---> outlined bridged method (mbnnnb) of @objc __ObjC.Gizmo.modifyString(Swift.String!, withNumber: Swift.Int, withFoobar: Any!) -> Swift.String!
_T04test1SVyxGAA1RA2A1ZRzAA1Y2ZZRpzl1A_AhaGPWT ---> {C} associated type witness table accessor for A.ZZ : test.Y in <A where A: test.Z, A.ZZ: test.Y> test.S<A> : test.R in test
12 changes: 6 additions & 6 deletions test/IRGen/associated_type_witness.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ struct GenericWithUniversal<T> : Assocked {
// Witness table for Fulfilled : Assocked.
// GLOBAL-LABEL: @_T023associated_type_witness9FulfilledVyxGAA8AssockedAAWP = hidden constant [3 x i8*] [
// GLOBAL-SAME: i8* bitcast (%swift.type* (%swift.type*, i8**)* @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5AssocWt to i8*)
// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5AssocAA1PPWT to i8*)
// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5AssocAA1QPWT to i8*)
// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5Assoc_AA1PPWT to i8*)
// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5Assoc_AA1QPWT to i8*)
// GLOBAL-SAME: ]
struct Fulfilled<T : P & Q> : Assocked {
typealias Assoc = T
Expand All @@ -56,14 +56,14 @@ struct Fulfilled<T : P & Q> : Assocked {
// CHECK-NEXT: ret %swift.type* [[T2]]

// Associated type witness table access function for Fulfilled.Assoc : P.
// CHECK-LABEL: define internal i8** @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5AssocAA1PPWT(%swift.type* %"Fulfilled<T>.Assoc", %swift.type* %"Fulfilled<T>", i8** %"Fulfilled<T>.Assocked")
// CHECK-LABEL: define internal i8** @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5Assoc_AA1PPWT(%swift.type* %"Fulfilled<T>.Assoc", %swift.type* %"Fulfilled<T>", i8** %"Fulfilled<T>.Assocked")
// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Fulfilled<T>" to i8***
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 3
// CHECK-NEXT: [[T2:%.*]] = load i8**, i8*** [[T1]], align 8, !invariant.load
// CHECK-NEXT: ret i8** [[T2]]

// Associated type witness table access function for Fulfilled.Assoc : Q.
// CHECK-LABEL: define internal i8** @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5AssocAA1QPWT(%swift.type* %"Fulfilled<T>.Assoc", %swift.type* %"Fulfilled<T>", i8** %"Fulfilled<T>.Assocked")
// CHECK-LABEL: define internal i8** @_T023associated_type_witness9FulfilledVyxGAA8AssockedAA5Assoc_AA1QPWT(%swift.type* %"Fulfilled<T>.Assoc", %swift.type* %"Fulfilled<T>", i8** %"Fulfilled<T>.Assocked")
// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Fulfilled<T>" to i8***
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 4
// CHECK-NEXT: [[T2:%.*]] = load i8**, i8*** [[T1]], align 8, !invariant.load
Expand All @@ -74,8 +74,8 @@ struct Pair<T, U> : P, Q {}
// Generic witness table pattern for Computed : Assocked.
// GLOBAL-LABEL: @_T023associated_type_witness8ComputedVyxq_GAA8AssockedAAWP = hidden constant [3 x i8*] [
// GLOBAL-SAME: i8* bitcast (%swift.type* (%swift.type*, i8**)* @_T023associated_type_witness8ComputedVyxq_GAA8AssockedAA5AssocWt to i8*)
// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_T023associated_type_witness8ComputedVyxq_GAA8AssockedAA5AssocAA1PPWT to i8*)
// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_T023associated_type_witness8ComputedVyxq_GAA8AssockedAA5AssocAA1QPWT to i8*)
// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_T023associated_type_witness8ComputedVyxq_GAA8AssockedAA5Assoc_AA1PPWT to i8*)
// GLOBAL-SAME: i8* bitcast (i8** (%swift.type*, %swift.type*, i8**)* @_T023associated_type_witness8ComputedVyxq_GAA8AssockedAA5Assoc_AA1QPWT to i8*)
// GLOBAL-SAME: ]
// Generic witness table cache for Computed : Assocked.
// GLOBAL-LABEL: @_T023associated_type_witness8ComputedVyxq_GAA8AssockedAAWG = internal constant %swift.generic_witness_table_cache {
Expand Down
24 changes: 24 additions & 0 deletions test/IRGen/assoctypepath.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail because there are no CHECK: directives -- can you add some for the mangled symbols?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, thanks! Yeah, that's what I wanted but apparently not did


// Check that we can mangle+demangle the associated type witness table accessor
// and do not crash

protocol V {}
protocol W: V {}
protocol X: W {}
protocol Y: X {}
protocol Z: W {
associatedtype ZZ: X
}

protocol P {
associatedtype A: W
}
protocol Q: P where A: Z {}
protocol R: Q where A.ZZ: Y {}

// CHECK: define {{.*}} @_T013assoctypepath1SVyxGAA1RAA1A_2ZZAA1YPWT

struct S<T>: R where T: Z, T.ZZ: Y {
typealias A = T
}
2 changes: 1 addition & 1 deletion test/IRGen/same_type_constraints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ where Self : CodingType,
print(Self.ValueType.self)
}

// OSIZE: define internal i8** @_T021same_type_constraints12GenericKlazzCyxq_GAA1EAA4DataAA0F4TypePWT(%swift.type* %"GenericKlazz<T, R>.Data", %swift.type* nocapture readonly %"GenericKlazz<T, R>", i8** nocapture readnone %"GenericKlazz<T, R>.E") [[ATTRS:#[0-9]+]] {
// OSIZE: define internal i8** @_T021same_type_constraints12GenericKlazzCyxq_GAA1EAA4Data_AA0F4TypePWT(%swift.type* %"GenericKlazz<T, R>.Data", %swift.type* nocapture readonly %"GenericKlazz<T, R>", i8** nocapture readnone %"GenericKlazz<T, R>.E") [[ATTRS:#[0-9]+]] {
// OSIZE: [[ATTRS]] = {{{.*}}noinline