mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
When a declaration has a structural opaque return type like: func foo() -> Bar<some P> then to mangle that return type `Bar<some P>`, we have to mangle the `some P` part by referencing its defining declaration `foo()`, which in turn includes its return type `Bar<some P>` again (this time using a special mangling for `some P` that prevents infinite recursion). Since we mangle `Bar<some P>` once as part of mangling the declaration, and we register substitutions for bound generic types when they're complete, we end up registering the substitution for `Bar<some P>` twice, once as the return type of the declaration name, and again as the actual type. This would be fine, except that the mangler doesn't check for key collisions, and it picks substitution indexes based on the number of entries in its hash map, so the duplicated substitution ends up corrupting the substitution sequence, causing the mangler to produce an invalid mangled name. Fixing that exposes us to another problem in the remangler: the AST mangler keys substitutions by type identity, but the remangler uses the value of the demangled nodes to recognize substitutions. The mangling for `Bar<current declaration's opaque return type>` can appear multiple times in a demangled tree, but referring to different declarations' opaque return types, and the remangler would reconstruct an incorrect mangled name when this happens. To avoid this, change the way the demangler represents `OpaqueReturnType` nodes so that they contain a backreference to the declaration they represent, so that substitutions involving different declarations' opaque return types don't get confused.
219 lines
6.4 KiB
C++
219 lines
6.4 KiB
C++
//===--- Mangler.h - Base class for Swift name mangling ---------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_BASIC_MANGLER_H
|
|
#define SWIFT_BASIC_MANGLER_H
|
|
|
|
#include "swift/Demangling/ManglingUtils.h"
|
|
#include "swift/Demangling/NamespaceMacros.h"
|
|
#include "swift/Basic/Debug.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace swift {
|
|
namespace Mangle {
|
|
SWIFT_BEGIN_INLINE_NAMESPACE
|
|
|
|
void printManglingStats();
|
|
|
|
/// The basic Swift symbol mangler.
|
|
///
|
|
/// This class serves as an abstract base class for specific manglers. It
|
|
/// provides some basic utilities, like handling of substitutions, mangling of
|
|
/// identifiers, etc.
|
|
class Mangler {
|
|
protected:
|
|
template <typename Mangler>
|
|
friend void mangleIdentifier(Mangler &M, StringRef ident);
|
|
friend class SubstitutionMerging;
|
|
|
|
/// The storage for the mangled symbol.
|
|
llvm::SmallString<128> Storage;
|
|
|
|
/// The output stream for the mangled symbol.
|
|
llvm::raw_svector_ostream Buffer;
|
|
|
|
/// A temporary storage needed by the ::mangleIdentifier() template function.
|
|
llvm::SmallVector<WordReplacement, 8> SubstWordsInIdent;
|
|
|
|
/// Substitutions, except identifier substitutions.
|
|
llvm::DenseMap<const void *, unsigned> Substitutions;
|
|
|
|
/// Identifier substitutions.
|
|
llvm::StringMap<unsigned> StringSubstitutions;
|
|
|
|
/// Index to use for the next added substitution.
|
|
/// Note that this is not simply the sum of the size of the \c Substitutions
|
|
/// and \c StringSubstitutions maps above, since in some circumstances the
|
|
/// same entity may be registered for multiple substitution indexes.
|
|
unsigned NextSubstitutionIndex = 0;
|
|
|
|
/// Word substitutions in mangled identifiers.
|
|
llvm::SmallVector<SubstitutionWord, 26> Words;
|
|
|
|
/// Used for repeated substitutions and known substitutions, e.g. A3B, S2i.
|
|
SubstitutionMerging SubstMerging;
|
|
|
|
size_t MaxNumWords = 26;
|
|
|
|
/// If enabled, non-ASCII names are encoded in modified Punycode.
|
|
bool UsePunycode = true;
|
|
|
|
/// If enabled, repeated entities are mangled using substitutions ('A...').
|
|
bool UseSubstitutions = true;
|
|
|
|
/// A helpful little wrapper for an integer value that should be mangled
|
|
/// in a particular, compressed value.
|
|
class Index {
|
|
unsigned N;
|
|
public:
|
|
explicit Index(unsigned n) : N(n) {}
|
|
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &out, Index n) {
|
|
if (n.N != 0) out << (n.N - 1);
|
|
return (out << '_');
|
|
}
|
|
};
|
|
|
|
void addSubstWordsInIdent(const WordReplacement &repl) {
|
|
SubstWordsInIdent.push_back(repl);
|
|
}
|
|
|
|
void addWord(const SubstitutionWord &word) {
|
|
Words.push_back(word);
|
|
}
|
|
|
|
/// Returns the buffer as a StringRef, needed by mangleIdentifier().
|
|
StringRef getBufferStr() const {
|
|
return StringRef(Storage.data(), Storage.size());
|
|
}
|
|
|
|
/// Removes the last characters of the buffer by setting it's size to a
|
|
/// smaller value.
|
|
void resetBuffer(size_t toPos) {
|
|
assert(toPos <= Storage.size());
|
|
Storage.resize(toPos);
|
|
}
|
|
|
|
protected:
|
|
Mangler() : Buffer(Storage) { }
|
|
|
|
/// Begins a new mangling but does not add the mangling prefix.
|
|
void beginManglingWithoutPrefix();
|
|
|
|
/// Begins a new mangling but and adds the mangling prefix.
|
|
void beginMangling();
|
|
|
|
/// Finish the mangling of the symbol and return the mangled name.
|
|
std::string finalize();
|
|
|
|
/// Finish the mangling of the symbol and write the mangled name into
|
|
/// \p stream.
|
|
void finalize(llvm::raw_ostream &stream);
|
|
|
|
/// Verify that demangling and remangling works.
|
|
static void verify(StringRef mangledName);
|
|
|
|
SWIFT_DEBUG_DUMP;
|
|
|
|
/// Appends a mangled identifier string.
|
|
void appendIdentifier(StringRef ident);
|
|
|
|
// NOTE: the addSubstitution functions perform the value computation before
|
|
// the assignment because there is no sequence point synchronising the
|
|
// computation of the value before the insertion of the new key, resulting in
|
|
// the computed value being off-by-one causing an undecoration failure during
|
|
// round-tripping.
|
|
void addSubstitution(const void *ptr) {
|
|
if (!UseSubstitutions)
|
|
return;
|
|
|
|
auto value = NextSubstitutionIndex++;
|
|
Substitutions[ptr] = value;
|
|
}
|
|
void addSubstitution(StringRef Str) {
|
|
if (!UseSubstitutions)
|
|
return;
|
|
|
|
auto value = NextSubstitutionIndex++;
|
|
StringSubstitutions[Str] = value;
|
|
}
|
|
|
|
bool tryMangleSubstitution(const void *ptr);
|
|
|
|
void mangleSubstitution(unsigned Index);
|
|
|
|
#ifndef NDEBUG
|
|
void recordOpStatImpl(StringRef op, size_t OldPos);
|
|
#endif
|
|
|
|
void recordOpStat(StringRef op, size_t OldPos) {
|
|
#ifndef NDEBUG
|
|
recordOpStatImpl(op, OldPos);
|
|
#endif
|
|
}
|
|
|
|
void appendOperator(StringRef op) {
|
|
size_t OldPos = Storage.size();
|
|
Buffer << op;
|
|
recordOpStat(op, OldPos);
|
|
}
|
|
void appendOperator(StringRef op, Index index) {
|
|
size_t OldPos = Storage.size();
|
|
Buffer << op << index;
|
|
recordOpStat(op, OldPos);
|
|
}
|
|
void appendOperator(StringRef op, Index index1, Index index2) {
|
|
size_t OldPos = Storage.size();
|
|
Buffer << op << index1 << index2;
|
|
recordOpStat(op, OldPos);
|
|
}
|
|
void appendOperator(StringRef op, StringRef arg) {
|
|
size_t OldPos = Storage.size();
|
|
Buffer << op << arg;
|
|
recordOpStat(op, OldPos);
|
|
}
|
|
void appendListSeparator() {
|
|
appendOperator("_");
|
|
}
|
|
void appendListSeparator(bool &isFirstListItem) {
|
|
if (isFirstListItem) {
|
|
appendListSeparator();
|
|
isFirstListItem = false;
|
|
}
|
|
}
|
|
void appendOperatorParam(StringRef op) {
|
|
Buffer << op;
|
|
}
|
|
void appendOperatorParam(StringRef op, int natural) {
|
|
Buffer << op << natural << '_';
|
|
}
|
|
void appendOperatorParam(StringRef op, Index index) {
|
|
Buffer << op << index;
|
|
}
|
|
void appendOperatorParam(StringRef op, Index index1, Index index2) {
|
|
Buffer << op << index1 << index2;
|
|
}
|
|
void appendOperatorParam(StringRef op, StringRef arg) {
|
|
Buffer << op << arg;
|
|
}
|
|
};
|
|
|
|
SWIFT_END_INLINE_NAMESPACE
|
|
} // end namespace Mangle
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_BASIC_MANGLER_H
|