Merge pull request #9989 from ahoppen/introduce-special-declnames

Introduce special decl names
diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h
index 40da25f..a6b82ed 100644
--- a/include/swift/AST/Identifier.h
+++ b/include/swift/AST/Identifier.h
@@ -51,6 +51,8 @@
 /// ASTContext.  It just wraps a nul-terminated "const char*".
 class Identifier {
   friend class ASTContext;
+  friend class DeclBaseName;
+
   const char *Pointer;
   
   /// Constructor, only accessible by ASTContext, which handles the uniquing.
@@ -207,6 +209,19 @@
 /// Wrapper that may either be an Identifier or a special name
 /// (e.g. for subscripts)
 class DeclBaseName {
+public:
+  enum class Kind: uint8_t {
+    Normal,
+    Subscript
+  };
+  
+private:
+  /// In a special DeclName represenenting a subscript, this opaque pointer
+  /// is used as the data of the base name identifier.
+  /// This is an implementation detail that should never leak outside of
+  /// DeclName.
+  static void *SubscriptIdentifierData;
+
   Identifier Ident;
 
 public:
@@ -214,7 +229,19 @@
 
   DeclBaseName(Identifier I) : Ident(I) {}
 
-  bool isSpecial() const { return false; }
+  static DeclBaseName createSubscript() {
+    return DeclBaseName(Identifier((const char *)SubscriptIdentifierData));
+  }
+
+  Kind getKind() const {
+    if (Ident.get() == SubscriptIdentifierData) {
+      return Kind::Subscript;
+    } else {
+      return Kind::Normal;
+    }
+  }
+
+  bool isSpecial() const { return getKind() != Kind::Normal; }
 
   /// Return the identifier backing the name. Assumes that the name is not
   /// special.
@@ -238,12 +265,17 @@
   StringRef userFacingName() const {
     if (empty())
       return "_";
-    return getIdentifier().str();
+
+    switch (getKind()) {
+    case Kind::Normal:
+      return getIdentifier().str();
+    case Kind::Subscript:
+      return "subscript";
+    }
   }
 
   int compare(DeclBaseName other) const {
-    // TODO: Sort special names cleverly
-    return getIdentifier().compare(other.getIdentifier());
+    return userFacingName().compare(other.userFacingName());
   }
 
   bool operator==(StringRef Str) const {
diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def
index 1937658..fabeb8e 100644
--- a/include/swift/AST/KnownIdentifiers.def
+++ b/include/swift/AST/KnownIdentifiers.def
@@ -90,7 +90,6 @@
 IDENTIFIER(some)
 IDENTIFIER(storage)
 IDENTIFIER(stringValue)
-IDENTIFIER(subscript)
 IDENTIFIER(super)
 IDENTIFIER(superDecoder)
 IDENTIFIER(superEncoder)
diff --git a/include/swift/Serialization/ModuleFile.h b/include/swift/Serialization/ModuleFile.h
index 75eb0e3..dd40305 100644
--- a/include/swift/Serialization/ModuleFile.h
+++ b/include/swift/Serialization/ModuleFile.h
@@ -740,7 +740,11 @@
   /// Returns the type with the given ID, deserializing it if needed.
   llvm::Expected<Type> getTypeChecked(serialization::TypeID TID);
 
-  /// Returns the identifier with the given ID, deserializing it if needed.
+  /// Returns the base name with the given ID, deserializing it if needed.
+  DeclBaseName getDeclBaseName(serialization::IdentifierID IID);
+
+  /// Convenience method to retrieve the identifier backing the name with
+  /// given ID. Asserts that the name with this ID is not special.
   Identifier getIdentifier(serialization::IdentifierID IID);
 
   /// Returns the decl with the given ID, deserializing it if needed.
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 90832f9..42dbbd2 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,7 @@
 /// in source control, you should also update the comment to briefly
 /// describe what change you made. The content of this comment isn't important;
 /// it just ensures a conflict if two people change the module format.
-const uint16_t VERSION_MINOR = 349; // Last change: '@autoclosure' and '@noescape' no longer decl attributes.
+const uint16_t VERSION_MINOR = 350; // Last change: special decl names
 
 using DeclID = PointerEmbeddedInt<unsigned, 31>;
 using DeclIDField = BCFixed<31>;
@@ -342,18 +342,27 @@
 
 // These IDs must \em not be renumbered or reordered without incrementing
 // VERSION_MAJOR.
-enum SpecialModuleID : uint8_t {
+enum class DeclNameKind: uint8_t {
+  Normal,
+  Subscript
+};
+
+// These IDs must \em not be renumbered or reordered without incrementing
+// VERSION_MAJOR.
+enum SpecialIdentifierID : uint8_t {
   /// Special IdentifierID value for the Builtin module.
   BUILTIN_MODULE_ID = 0,
   /// Special IdentifierID value for the current module.
   CURRENT_MODULE_ID,
   /// Special value for the module for imported Objective-C headers.
   OBJC_HEADER_MODULE_ID,
+  /// Special value for the special subscript name
+  SUBSCRIPT_ID,
 
-  /// The number of special modules. This value should never be encoded;
+  /// The number of special Identifier IDs. This value should never be encoded;
   /// it should only be used to count the number of names above. As such, it
   /// is correct and necessary to add new values above this one.
-  NUM_SPECIAL_MODULES
+  NUM_SPECIAL_IDS
 };
 
 // These IDs must \em not be renumbered or reordered without incrementing
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index 9d5b4ab..f5fbc72 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -540,8 +540,15 @@
         break;
     }
   } else if (decl->hasName()) {
-    // TODO: Handle special names
-    appendIdentifier(decl->getBaseName().getIdentifier().str());
+    // FIXME: Should a mangled subscript name contain the string "subscript"?
+    switch (decl->getBaseName().getKind()) {
+    case DeclBaseName::Kind::Normal:
+      appendIdentifier(decl->getBaseName().getIdentifier().str());
+      break;
+    case DeclBaseName::Kind::Subscript:
+      appendIdentifier("subscript");
+      break;
+    }
   } else {
     assert(AllowNamelessEntities && "attempt to mangle unnamed decl");
     // Fall back to an unlikely name, so that we still generate a valid
diff --git a/lib/AST/Identifier.cpp b/lib/AST/Identifier.cpp
index 1fae6e5..a743912 100644
--- a/lib/AST/Identifier.cpp
+++ b/lib/AST/Identifier.cpp
@@ -20,6 +20,8 @@
 #include "llvm/Support/ConvertUTF.h"
 using namespace swift;
 
+void *DeclBaseName::SubscriptIdentifierData =
+    &DeclBaseName::SubscriptIdentifierData;
 
 raw_ostream &llvm::operator<<(raw_ostream &OS, Identifier I) {
   if (I.get() == nullptr)
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index dcf9c97..0ebb9e7 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -2974,7 +2974,7 @@
   auto &clangCtx = getClangASTContext();
   auto clangTU = clangCtx.getTranslationUnitDecl();
 
-  for (auto entry : table.lookup(name.getBaseIdentifier().str(), clangTU)) {
+  for (auto entry : table.lookup(name.getBaseName(), clangTU)) {
     // If the entry is not visible, skip it.
     if (!isVisibleClangEntry(clangCtx, entry)) continue;
 
@@ -3070,7 +3070,7 @@
 
   // Look for namespace-scope entities with each base name.
   for (auto baseName : baseNames) {
-    lookupValue(table, SwiftContext.getIdentifier(baseName), consumer);
+    lookupValue(table, baseName.toDeclBaseName(SwiftContext), consumer);
   }
 }
 
@@ -3079,9 +3079,8 @@
        DeclName name,
        VisibleDeclConsumer &consumer) {
   auto &clangCtx = getClangASTContext();
-  auto baseName = name.getBaseIdentifier().str();
 
-  for (auto clangDecl : table.lookupObjCMembers(baseName)) {
+  for (auto clangDecl : table.lookupObjCMembers(name.getBaseName())) {
     // If the entry is not visible, skip it.
     if (!isVisibleClangEntry(clangCtx, clangDecl)) continue;
 
@@ -3121,7 +3120,7 @@
 
   // Look for Objective-C members with each base name.
   for (auto baseName : baseNames) {
-    lookupObjCMembers(table, SwiftContext.getIdentifier(baseName), consumer);
+    lookupObjCMembers(table, baseName.toDeclBaseName(SwiftContext), consumer);
   }
 }
 
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 2e4ab67..3782850 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -5410,7 +5410,7 @@
       Impl.findLookupTable(*getClangSubmoduleForDecl(accessor));
   assert(lookupTable && "No lookup table?");
   bool foundAccessor = false;
-  for (auto entry : lookupTable->lookup(propertyName.str(),
+  for (auto entry : lookupTable->lookup(SerializedSwiftName(propertyName),
                                         importedName.getEffectiveContext())) {
     auto decl = entry.dyn_cast<clang::NamedDecl *>();
     if (!decl)
@@ -6246,7 +6246,7 @@
   // Build the subscript declaration.
   auto &C = Impl.SwiftContext;
   auto bodyParams = getterThunk->getParameterList(1)->clone(C);
-  DeclName name(C, C.Id_subscript, {Identifier()});
+  DeclName name(C, DeclBaseName::createSubscript(), {Identifier()});
   auto subscript = Impl.createDeclWithClangNode<SubscriptDecl>(
       getter->getClangNode(), getOverridableAccessibility(dc), name,
       decl->getLoc(), bodyParams, decl->getLoc(),
diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp
index b470a24..016af64 100644
--- a/lib/ClangImporter/SwiftLookupTable.cpp
+++ b/lib/ClangImporter/SwiftLookupTable.cpp
@@ -179,12 +179,12 @@
   clang::serialization::ModuleFile &getModuleFile() { return ModuleFile; }
 
   /// Retrieve the set of base names that are stored in the on-disk hash table.
-  SmallVector<StringRef, 4> getBaseNames();
+  SmallVector<SerializedSwiftName, 4> getBaseNames();
 
   /// Retrieve the set of entries associated with the given base name.
   ///
   /// \returns true if we found anything, false otherwise.
-  bool lookup(StringRef baseName,
+  bool lookup(SerializedSwiftName baseName,
               SmallVectorImpl<SwiftLookupTable::FullTableEntry> &entries);
 
   /// Retrieve the declaration IDs of the categories.
@@ -205,6 +205,15 @@
 };
 } // namespace swift
 
+DeclBaseName SerializedSwiftName::toDeclBaseName(ASTContext &Context) const {
+  switch (Kind) {
+  case DeclBaseName::Kind::Normal:
+    return Context.getIdentifier(Name);
+  case DeclBaseName::Kind::Subscript:
+    return DeclBaseName::createSubscript();
+  }
+}
+
 bool SwiftLookupTable::contextRequiresName(ContextKind kind) {
   switch (kind) {
   case ContextKind::ObjCClass:
@@ -305,9 +314,9 @@
 /// declaration context or typedef name.
 clang::NamedDecl *SwiftLookupTable::resolveContext(StringRef unresolvedName) {
   // Look for a context with the given Swift name.
-  for (auto entry : lookup(unresolvedName, 
-                           std::make_pair(ContextKind::TranslationUnit,
-                                          StringRef()))) {
+  for (auto entry :
+       lookup(SerializedSwiftName(unresolvedName),
+              std::make_pair(ContextKind::TranslationUnit, StringRef()))) {
     if (auto decl = entry.dyn_cast<clang::NamedDecl *>()) {
       if (isa<clang::TagDecl>(decl) ||
           isa<clang::ObjCInterfaceDecl>(decl) ||
@@ -488,7 +497,7 @@
   }
 
   // Populate cache from reader if necessary.
-  findOrCreate(name.getBaseIdentifier().str());
+  findOrCreate(name.getBaseName());
 
   auto context = *contextOpt;
 
@@ -499,7 +508,7 @@
   }
 
   // Find the list of entries for this base name.
-  auto &entries = LookupTable[name.getBaseIdentifier().str()];
+  auto &entries = LookupTable[name.getBaseName()];
   auto decl = newEntry.dyn_cast<clang::NamedDecl *>();
   auto macro = newEntry.dyn_cast<clang::MacroInfo *>();
   for (auto &entry : entries) {
@@ -520,8 +529,9 @@
   entries.push_back(entry);
 }
 
-auto SwiftLookupTable::findOrCreate(StringRef baseName) 
-  -> llvm::DenseMap<StringRef, SmallVector<FullTableEntry, 2>>::iterator {
+auto SwiftLookupTable::findOrCreate(SerializedSwiftName baseName)
+    -> llvm::DenseMap<SerializedSwiftName,
+                      SmallVector<FullTableEntry, 2>>::iterator {
   // If there is no base name, there is nothing to find.
   if (baseName.empty()) return LookupTable.end();
 
@@ -545,7 +555,7 @@
 }
 
 SmallVector<SwiftLookupTable::SingleEntry, 4>
-SwiftLookupTable::lookup(StringRef baseName,
+SwiftLookupTable::lookup(SerializedSwiftName baseName,
                          llvm::Optional<StoredContext> searchContext) {
   SmallVector<SwiftLookupTable::SingleEntry, 4> result;
 
@@ -634,7 +644,7 @@
 }
 
 SmallVector<SwiftLookupTable::SingleEntry, 4>
-SwiftLookupTable::lookup(StringRef baseName,
+SwiftLookupTable::lookup(SerializedSwiftName baseName,
                          EffectiveClangContext searchContext) {
   // Translate context.
   Optional<StoredContext> context;
@@ -646,12 +656,12 @@
   return lookup(baseName, context);
 }
 
-SmallVector<StringRef, 4> SwiftLookupTable::allBaseNames() {
+SmallVector<SerializedSwiftName, 4> SwiftLookupTable::allBaseNames() {
   // If we have a reader, enumerate its base names.
   if (Reader) return Reader->getBaseNames();
 
   // Otherwise, walk the lookup table.
-  SmallVector<StringRef, 4> result;
+  SmallVector<SerializedSwiftName, 4> result;
   for (const auto &entry : LookupTable) {
     result.push_back(entry.first);
   }
@@ -659,7 +669,7 @@
 }
 
 SmallVector<clang::NamedDecl *, 4>
-SwiftLookupTable::lookupObjCMembers(StringRef baseName) {
+SwiftLookupTable::lookupObjCMembers(SerializedSwiftName baseName) {
   SmallVector<clang::NamedDecl *, 4> result;
 
   // Find the lookup table entry for this base name.
@@ -805,14 +815,21 @@
 
 void SwiftLookupTable::dump() const {
   // Dump the base name -> full table entry mappings.
-  SmallVector<StringRef, 4> baseNames;
+  SmallVector<SerializedSwiftName, 4> baseNames;
   for (const auto &entry : LookupTable) {
     baseNames.push_back(entry.first);
   }
   llvm::array_pod_sort(baseNames.begin(), baseNames.end());
   llvm::errs() << "Base name -> entry mappings:\n";
   for (auto baseName : baseNames) {
-    llvm::errs() << "  " << baseName << ":\n";
+    switch (baseName.Kind) {
+    case DeclBaseName::Kind::Normal:
+      llvm::errs() << "  " << baseName.Name << ":\n";
+      break;
+    case DeclBaseName::Kind::Subscript:
+      llvm::errs() << "  subscript:\n";
+      break;
+    }
     const auto &entries = LookupTable.find(baseName)->second;
     for (const auto &entry : entries) {
       llvm::errs() << "    ";
@@ -915,11 +932,14 @@
   /// Trait used to write the on-disk hash table for the base name -> entities
   /// mapping.
   class BaseNameToEntitiesTableWriterInfo {
+    static_assert(sizeof(DeclBaseName::Kind) <= sizeof(uint8_t),
+                  "kind serialized as uint8_t");
+
     SwiftLookupTable &Table;
     clang::ASTWriter &Writer;
 
   public:
-    using key_type = StringRef;
+    using key_type = SerializedSwiftName;
     using key_type_ref = key_type;
     using data_type = SmallVector<SwiftLookupTable::FullTableEntry, 2>;
     using data_type_ref = data_type &;
@@ -933,14 +953,16 @@
     }
 
     hash_value_type ComputeHash(key_type_ref key) {
-      return llvm::HashString(key);
+      return llvm::DenseMapInfo<SerializedSwiftName>::getHashValue(key);
     }
 
     std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
                                                     key_type_ref key,
                                                     data_type_ref data) {
-      // The length of the key.
-      uint32_t keyLength = key.size();
+      uint32_t keyLength = sizeof(uint8_t); // For the flag of the name's kind
+      if (key.Kind == DeclBaseName::Kind::Normal) {
+        keyLength += key.Name.size(); // The name's length
+      }
 
       // # of entries
       uint32_t dataLength = sizeof(uint16_t);
@@ -968,7 +990,10 @@
     }
 
     void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
-      out << key;
+      endian::Writer<little> writer(out);
+      writer.write<uint8_t>((uint8_t)key.Kind);
+      if (key.Kind == swift::DeclBaseName::Kind::Normal)
+        writer.OS << key.Name;
     }
 
     void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
@@ -1089,7 +1114,7 @@
   SmallVector<uint64_t, 64> ScratchRecord;
 
   // First, gather the sorted list of base names.
-  SmallVector<StringRef, 2> baseNames;
+  SmallVector<SerializedSwiftName, 2> baseNames;
   for (const auto &entry : table.LookupTable)
     baseNames.push_back(entry.first);
   llvm::array_pod_sort(baseNames.begin(), baseNames.end());
@@ -1162,7 +1187,7 @@
   /// Used to deserialize the on-disk base name -> entities table.
   class BaseNameToEntitiesTableReaderInfo {
   public:
-    using internal_key_type = StringRef;
+    using internal_key_type = SerializedSwiftName;
     using external_key_type = internal_key_type;
     using data_type = SmallVector<SwiftLookupTable::FullTableEntry, 2>;
     using hash_value_type = uint32_t;
@@ -1177,7 +1202,7 @@
     }
 
     hash_value_type ComputeHash(internal_key_type key) {
-      return llvm::HashString(key);
+      return llvm::DenseMapInfo<SerializedSwiftName>::getHashValue(key);
     }
 
     static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
@@ -1192,7 +1217,18 @@
     }
 
     static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
-      return StringRef((const char *)data, length);
+      uint8_t kind = endian::readNext<uint8_t, little, unaligned>(data);
+      switch (kind) {
+      case (uint8_t)DeclBaseName::Kind::Normal: {
+        StringRef str(reinterpret_cast<const char *>(data),
+                      length - sizeof(uint8_t));
+        return SerializedSwiftName(str);
+      }
+      case (uint8_t)DeclBaseName::Kind::Subscript:
+        return SerializedSwiftName(DeclBaseName::Kind::Subscript);
+      default:
+        llvm_unreachable("Unknown kind for DeclBaseName");
+      }
     }
 
     static data_type ReadData(internal_key_type key, const uint8_t *data,
@@ -1447,9 +1483,9 @@
 
 }
 
-SmallVector<StringRef, 4> SwiftLookupTableReader::getBaseNames() {
+SmallVector<SerializedSwiftName, 4> SwiftLookupTableReader::getBaseNames() {
   auto table = static_cast<SerializedBaseNameToEntitiesTable*>(SerializedTable);
-  SmallVector<StringRef, 4> results;
+  SmallVector<SerializedSwiftName, 4> results;
   for (auto key : table->keys()) {
     results.push_back(key);
   }
@@ -1457,8 +1493,8 @@
 }
 
 bool SwiftLookupTableReader::lookup(
-       StringRef baseName,
-       SmallVectorImpl<SwiftLookupTable::FullTableEntry> &entries) {
+    SerializedSwiftName baseName,
+    SmallVectorImpl<SwiftLookupTable::FullTableEntry> &entries) {
   auto table = static_cast<SerializedBaseNameToEntitiesTable*>(SerializedTable);
 
   // Look for an entry with this base name.
@@ -1556,7 +1592,7 @@
     // Also add the subscript entry, if needed.
     if (importedName.isSubscriptAccessor())
       table.addEntry(DeclName(nameImporter.getContext(),
-                              nameImporter.getContext().Id_subscript,
+                              DeclBaseName::createSubscript(),
                               ArrayRef<Identifier>()),
                      named, importedName.getEffectiveContext());
 
diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h
index e09e7aa..e917275 100644
--- a/lib/ClangImporter/SwiftLookupTable.h
+++ b/lib/ClangImporter/SwiftLookupTable.h
@@ -45,6 +45,102 @@
 
 namespace swift {
 
+/// A name from a SwiftLookupTable that has not been deserialized into a
+/// DeclBaseName yet.
+struct SerializedSwiftName {
+  /// The kind of the name if it is a special name
+  DeclBaseName::Kind Kind;
+  /// The name of the idenifier if it is not a special name
+  StringRef Name;
+
+  SerializedSwiftName() : Kind(DeclBaseName::Kind::Normal), Name(StringRef()) {}
+
+  explicit SerializedSwiftName(DeclBaseName::Kind Kind)
+      : Kind(Kind), Name(StringRef()) {}
+
+  explicit SerializedSwiftName(StringRef Name)
+      : Kind(DeclBaseName::Kind::Normal), Name(Name) {}
+
+  SerializedSwiftName(DeclBaseName BaseName) {
+    Kind = BaseName.getKind();
+    if (BaseName.getKind() == DeclBaseName::Kind::Normal) {
+      Name = BaseName.getIdentifier().str();
+    }
+  }
+
+  /// Deserialize the name, adding it to the context's identifier table
+  DeclBaseName toDeclBaseName(ASTContext &Context) const;
+
+  bool empty() const {
+    return Kind == DeclBaseName::Kind::Normal && Name.empty();
+  }
+
+  /// Return a string representation of the name that can be used for sorting
+  StringRef userFacingName() const {
+    switch (Kind) {
+    case DeclBaseName::Kind::Normal:
+      return Name;
+    case DeclBaseName::Kind::Subscript:
+      return "subscript";
+    }
+  }
+
+  bool operator<(SerializedSwiftName RHS) const {
+    return userFacingName() < RHS.userFacingName();
+  }
+
+  bool operator==(SerializedSwiftName RHS) const {
+    if (Kind != RHS.Kind)
+      return false;
+
+    if (Kind == DeclBaseName::Kind::Normal) {
+      assert(RHS.Kind == DeclBaseName::Kind::Normal);
+      return Name == RHS.Name;
+    } else {
+      return true;
+    }
+  }
+};
+
+} // end namespace swift
+
+namespace llvm {
+
+using swift::SerializedSwiftName;
+
+// Inherit the DenseMapInfo from StringRef but add a few special cases for
+// special names
+template<> struct DenseMapInfo<SerializedSwiftName> {
+  static SerializedSwiftName getEmptyKey() {
+    return SerializedSwiftName(DenseMapInfo<StringRef>::getEmptyKey());
+  }
+  static SerializedSwiftName getTombstoneKey() {
+    return SerializedSwiftName(DenseMapInfo<StringRef>::getTombstoneKey());
+  }
+  static unsigned getHashValue(SerializedSwiftName Val) {
+    if (Val.Kind == swift::DeclBaseName::Kind::Normal) {
+      return DenseMapInfo<StringRef>::getHashValue(Val.Name);
+    } else {
+      return (unsigned)Val.Kind;
+    }
+  }
+  static bool isEqual(SerializedSwiftName LHS, SerializedSwiftName RHS) {
+    if (LHS.Kind != RHS.Kind)
+      return false;
+
+    if (LHS.Kind == swift::DeclBaseName::Kind::Normal) {
+      assert(RHS.Kind == swift::DeclBaseName::Kind::Normal);
+      return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name);
+    } else {
+      return LHS.Kind == RHS.Kind;
+    }
+  }
+};
+
+} // end namespace llvm
+
+namespace swift {
+
 /// The context into which a Clang declaration will be imported.
 ///
 /// When the context into which a declaration will be imported matches
@@ -170,7 +266,7 @@
 /// Lookup table minor version number.
 ///
 /// When the format changes IN ANY WAY, this number should be incremented.
-const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 14; // Swift 2 names
+const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 15; // Special names
 
 /// A lookup table that maps Swift names to the set of Clang
 /// declarations with that particular name.
@@ -276,7 +372,8 @@
 private:
   /// A table mapping from the base name of Swift entities to all of
   /// the C entities that have that name, in all contexts.
-  llvm::DenseMap<StringRef, SmallVector<FullTableEntry, 2>> LookupTable;
+  llvm::DenseMap<SerializedSwiftName, SmallVector<FullTableEntry, 2>>
+      LookupTable;
 
   /// The list of Objective-C categories and extensions.
   llvm::SmallVector<clang::ObjCCategoryDecl *, 4> Categories;
@@ -299,9 +396,9 @@
   friend class SwiftLookupTableReader;
   friend class SwiftLookupTableWriter;
 
-  /// Find or create the table entry for the given base name. 
-  llvm::DenseMap<StringRef, SmallVector<FullTableEntry, 2>>::iterator
-  findOrCreate(StringRef baseName);
+  /// Find or create the table entry for the given base name.
+  llvm::DenseMap<SerializedSwiftName, SmallVector<FullTableEntry, 2>>::iterator
+  findOrCreate(SerializedSwiftName baseName);
 
   /// Add the given entry to the list of entries, if it's not already
   /// present.
@@ -360,7 +457,8 @@
   /// entities should reside. This may be None to indicate that
   /// all results from all contexts should be produced.
   SmallVector<SingleEntry, 4>
-  lookup(StringRef baseName, llvm::Optional<StoredContext> searchContext);
+  lookup(SerializedSwiftName baseName,
+         llvm::Optional<StoredContext> searchContext);
 
   /// Retrieve the set of global declarations that are going to be
   /// imported as members into the given context.
@@ -379,15 +477,16 @@
   /// \param searchContext The context in which the resulting set of
   /// entities should reside. This may be None to indicate that
   /// all results from all contexts should be produced.
-  SmallVector<SingleEntry, 4>
-  lookup(StringRef baseName, EffectiveClangContext searchContext);
+  SmallVector<SingleEntry, 4> lookup(SerializedSwiftName baseName,
+                                     EffectiveClangContext searchContext);
 
   /// Retrieve the set of base names that are stored in the lookup table.
-  SmallVector<StringRef, 4> allBaseNames();
+  SmallVector<SerializedSwiftName, 4> allBaseNames();
 
   /// Lookup Objective-C members with the given base name, regardless
   /// of context.
-  SmallVector<clang::NamedDecl *, 4> lookupObjCMembers(StringRef baseName);
+  SmallVector<clang::NamedDecl *, 4>
+  lookupObjCMembers(SerializedSwiftName baseName);
 
   /// Retrieve the set of Objective-C categories and extensions.
   ArrayRef<clang::ObjCCategoryDecl *> categories();
diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp
index 1c8f443..bf9448d 100644
--- a/lib/IRGen/IRGenDebugInfo.cpp
+++ b/lib/IRGen/IRGenDebugInfo.cpp
@@ -400,8 +400,7 @@
         }
 
         SmallVector<char, 64> Buf;
-        // TODO: Handle special names
-        StringRef Name = (VD->getBaseName().getIdentifier().str() +
+        StringRef Name = (VD->getBaseName().userFacingName() +
                           Twine(Kind)).toStringRef(Buf);
         return BumpAllocatedString(Name);
       }
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index b15f047..238f473 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -5512,7 +5512,8 @@
   }
 
   // Build an AST for the subscript declaration.
-  DeclName name = DeclName(Context, Context.Id_subscript, argumentNames);
+  DeclName name = DeclName(Context, DeclBaseName::createSubscript(),
+                           argumentNames);
   auto *Subscript = new (Context) SubscriptDecl(name,
                                                 SubscriptLoc, Indices.get(),
                                                 ArrowLoc, ElementTy.get(),
diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp
index 7d2f8c6..96b5423 100644
--- a/lib/Parse/ParseSIL.cpp
+++ b/lib/Parse/ParseSIL.cpp
@@ -406,9 +406,6 @@
   case tok::kw_init:
     Result = P.Context.Id_init;
     break;
-  case tok::kw_subscript:
-    Result = P.Context.Id_subscript;
-    break;
   default:
     // If it's some other keyword, grab an identifier for it.
     if (P.Tok.isKeyword()) {
@@ -955,8 +952,8 @@
 }
 
 /// Find the top-level ValueDecl or Module given a name.
-static llvm::PointerUnion<ValueDecl*, ModuleDecl*> lookupTopDecl(Parser &P,
-             Identifier Name) {
+static llvm::PointerUnion<ValueDecl *, ModuleDecl *>
+lookupTopDecl(Parser &P, DeclBaseName Name) {
   // Use UnqualifiedLookup to look through all of the imports.
   // We have to lie and say we're done with parsing to make this happen.
   assert(P.SF.ASTStage == SourceFile::Parsing &&
@@ -970,7 +967,7 @@
 }
 
 /// Find the ValueDecl given an interface type and a member name.
-static ValueDecl *lookupMember(Parser &P, Type Ty, Identifier Name,
+static ValueDecl *lookupMember(Parser &P, Type Ty, DeclBaseName Name,
                                SourceLoc Loc,
                                SmallVectorImpl<ValueDecl *> &Lookup,
                                bool ExpectMultipleResults) {
@@ -1108,13 +1105,21 @@
                                    SmallVectorImpl<ValueDecl *> &values) {
   // Handle sil-dotted-path.
   Identifier Id;
-  SmallVector<Identifier, 4> FullName;
+  SmallVector<DeclBaseName, 4> FullName;
   SmallVector<SourceLoc, 4> Locs;
   do {
     Locs.push_back(P.Tok.getLoc());
-    if (parseSILIdentifier(Id, diag::expected_sil_constant))
-      return true;
-    FullName.push_back(Id);
+    switch (P.Tok.getKind()) {
+    case tok::kw_subscript:
+      P.consumeToken();
+      FullName.push_back(DeclBaseName::createSubscript());
+      break;
+    default:
+      if (parseSILIdentifier(Id, diag::expected_sil_constant))
+        return true;
+      FullName.push_back(Id);
+      break;
+    }
   } while (P.consumeIf(tok::period));
 
   // Look up ValueDecl from a dotted path.
diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp
index a1edd3d..c69a438 100644
--- a/lib/SIL/SILFunctionType.cpp
+++ b/lib/SIL/SILFunctionType.cpp
@@ -1575,9 +1575,13 @@
       // Getter selectors can belong to families if their name begins with the
       // wrong thing.
       if (FD->getAccessorStorageDecl()->isObjC() || c.isForeign) {
-        // TODO: Handle special names (subscript).
-        auto name = FD->getAccessorStorageDecl()->getBaseName().getIdentifier();
-        return getSelectorFamily(name);
+        auto declName = FD->getAccessorStorageDecl()->getBaseName();
+        switch (declName.getKind()) {
+        case DeclBaseName::Kind::Normal:
+          return getSelectorFamily(declName.getIdentifier());
+        case DeclBaseName::Kind::Subscript:
+          return SelectorFamily::None;
+        }
       }
       return SelectorFamily::None;
 
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 2bf4c2b..7fc669a 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -237,10 +237,13 @@
   printFullContext(Decl->getDeclContext(), OS);
   assert(Decl->hasName());
 
-  if (Decl->isOperator())
+  if (Decl->isOperator()) {
     OS << '"' << Decl->getBaseName() << '"';
-  else
+  } else if (Decl->getBaseName() == "subscript") {
+    OS << '`' << Decl->getBaseName() << '`';
+  } else {
     OS << Decl->getBaseName();
+  }
 }
 
 /// SILDeclRef uses sigil "#" and prints the fully qualified dotted path.
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index 2baecba..33b0fc9 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -2526,7 +2526,7 @@
     };
 
     // TODO: This should handle tuple member lookups, like x.1231 as well.
-    if (memberName.isSimpleName(CS->getASTContext().Id_subscript)) {
+    if (memberName.getBaseName().getKind() == DeclBaseName::Kind::Subscript) {
       diagnose(loc, diag::type_not_subscriptable, baseObjTy)
         .highlight(baseRange);
     } else if (auto metatypeTy = baseObjTy->getAs<MetatypeType>()) {
@@ -5699,7 +5699,7 @@
       CS->getConstraintLocator(SE, ConstraintLocator::SubscriptMember);
 
   return diagnoseMemberFailures(SE, baseExpr, ConstraintKind::ValueMember,
-                                CS->getASTContext().Id_subscript,
+                                DeclBaseName::createSubscript(),
                                 FunctionRefKind::DoubleApply, locator,
                                 callback);
 }
@@ -7540,7 +7540,7 @@
   };
 
   // Local function to perform name lookup for the current index.
-  auto performLookup = [&](Identifier componentName, SourceLoc componentNameLoc,
+  auto performLookup = [&](DeclBaseName componentName, SourceLoc componentNameLoc,
                            Type &lookupType) -> LookupResult {
     assert(currentType && "Non-beginning state must have a type");
     if (!currentType->mayHaveMembers())
@@ -7560,13 +7560,13 @@
 
   // Local function to print a component to the string.
   bool needDot = false;
-  auto printComponent = [&](Identifier component) {
+  auto printComponent = [&](DeclBaseName component) {
     if (needDot)
       keyPathOS << ".";
     else
       needDot = true;
 
-    keyPathOS << component.str();
+    keyPathOS << component;
   };
 
   bool isInvalid = false;
@@ -7574,7 +7574,7 @@
 
   for (auto &component : KPE->getComponents()) {
     auto componentNameLoc = component.getLoc();
-    Identifier componentName;
+    DeclBaseName componentName;
 
     switch (auto kind = component.getKind()) {
     case KeyPathExpr::Component::Kind::UnresolvedProperty: {
@@ -7584,7 +7584,7 @@
     }
 
     case KeyPathExpr::Component::Kind::UnresolvedSubscript:
-      componentName = TC.Context.Id_subscript;
+      componentName = DeclBaseName::createSubscript();
       break;
 
     case KeyPathExpr::Component::Kind::Invalid:
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index 3b54812..f7f4a47 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -1031,8 +1031,6 @@
                                  ValueDecl *declOrNull,
                                  ConstraintLocator *memberLocator = nullptr,
                                  ConstraintLocator *indexLocator = nullptr) {
-      ASTContext &Context = CS.getASTContext();
-
       // Locators used in this expression.
       if (!indexLocator)
         indexLocator
@@ -1128,7 +1126,7 @@
         CS.addBindOverloadConstraint(fnTy, choice, memberLocator,
                                      CurDC);
       } else {
-        CS.addValueMemberConstraint(baseTy, Context.Id_subscript,
+        CS.addValueMemberConstraint(baseTy, DeclBaseName::createSubscript(),
                                     fnTy, CurDC, FunctionRefKind::DoubleApply,
                                     memberLocator);
       }
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 3d152f3..1cee9e9 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -2888,7 +2888,8 @@
   result.OverallResult = MemberLookupResult::HasResults;
   
   // If we're looking for a subscript, consider key path operations.
-  if (memberName.isSimpleName(getASTContext().Id_subscript)) {
+  if (memberName.isSimpleName() &&
+      memberName.getBaseName().getKind() == DeclBaseName::Kind::Subscript) {
     result.ViableCandidates.push_back(
         OverloadChoice(baseTy, OverloadChoiceKind::KeyPathApplication));
   }
@@ -2897,7 +2898,7 @@
   // of the tuple.
   if (auto baseTuple = baseObjTy->getAs<TupleType>()) {
     // Tuples don't have compound-name members.
-    if (!memberName.isSimpleName())
+    if (!memberName.isSimpleName() || memberName.isSpecial())
       return result;  // No result.
 
     StringRef nameStr = memberName.getBaseIdentifier().str();
diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index 74d7608..34b6c47 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -1794,8 +1794,7 @@
       // don't currently pre-filter subscript overload sets by argument
       // keywords, so "subscript" is still the name that keypath subscripts
       // are looked up by.
-      auto &C = getBaseType()->getASTContext();
-      return DeclName(C.Id_subscript);
+      return DeclBaseName::createSubscript();
     }
     case OverloadChoiceKind::BaseType:
     case OverloadChoiceKind::TupleIndex:
diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp
index 64019f0..ef9d590 100644
--- a/lib/Sema/TypeCheckNameLookup.cpp
+++ b/lib/Sema/TypeCheckNameLookup.cpp
@@ -492,15 +492,22 @@
   // TODO: maybe ignore certain kinds of missing / present labels for the
   //   first argument label?
   // TODO: word-based rather than character-based?
-  // TODO: Handle special names
+  if (argName.getBaseName().getKind() != paramName.getBaseName().getKind()) {
+    return UnreasonableCallEditDistance;
+  }
+
+  if (argName.getBaseName().getKind() != DeclBaseName::Kind::Normal) {
+    return 0;
+  }
+  assert(argName.getBaseName().getKind() == DeclBaseName::Kind::Normal);
+
   StringRef argBase = argName.getBaseIdentifier().str();
   StringRef paramBase = paramName.getBaseIdentifier().str();
 
   unsigned distance = argBase.edit_distance(paramBase, maxEditDistance);
 
   // Bound the distance to UnreasonableCallEditDistance.
-  if (distance >= maxEditDistance ||
-      distance > (paramBase.size() + 2) / 3) {
+  if (distance >= maxEditDistance || distance > (paramBase.size() + 2) / 3) {
     return UnreasonableCallEditDistance;
   }
 
@@ -638,13 +645,11 @@
                         isa<FuncDecl>(decl) ? "method" :
                         "member");
 
-      // TODO: Handle special names
       return tc.diagnose(parentDecl, diag::note_typo_candidate_implicit_member,
                          decl->getBaseName().getIdentifier().str(), kind);
     }
   }
 
-  // TODO: Handle special names
   return tc.diagnose(decl, diag::note_typo_candidate,
                      decl->getBaseName().getIdentifier().str());
 }
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 961d0ba..433d1d0 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -5790,8 +5790,11 @@
       score = lhsFirstName.edit_distance(rhsFirstName.str(), true, limit);
     }
   } else {
-    // TODO: Handling of special names
-    score = 0;
+    if (lhs.getBaseName().getKind() == rhs.getBaseName().getKind()) {
+      score = 0;
+    } else {
+      return None;
+    }
   }
   if (score > limit) return None;
 
@@ -5921,8 +5924,7 @@
 /// argument labels.
 static unsigned getNameLength(DeclName name) {
   unsigned length = 0;
-  // TODO: Handle special names
-  if (!name.getBaseName().empty())
+  if (!name.getBaseName().empty() && !name.getBaseName().isSpecial())
     length += name.getBaseIdentifier().str().size();
   for (auto arg : name.getArgumentNames()) {
     if (!arg.empty())
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index f2bcb9b..22fc8a6 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -1201,7 +1201,7 @@
       XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
                                            isStatic);
 
-    Identifier name = getIdentifier(IID);
+    DeclBaseName name = getDeclBaseName(IID);
     pathTrace.addValue(name);
 
     Type filterTy = getType(TID);
@@ -1376,7 +1376,7 @@
     case XREF_VALUE_PATH_PIECE:
     case XREF_INITIALIZER_PATH_PIECE: {
       TypeID TID = 0;
-      Identifier memberName;
+      DeclBaseName memberName;
       Optional<swift::CtorInitializerKind> ctorInit;
       bool isType = false;
       bool inProtocolExt = false;
@@ -1385,7 +1385,7 @@
       case XREF_TYPE_PATH_PIECE: {
         IdentifierID IID;
         XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
-        memberName = getIdentifier(IID);
+        memberName = getDeclBaseName(IID);
         isType = true;
         break;
       }
@@ -1394,7 +1394,7 @@
         IdentifierID IID;
         XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
                                              isStatic);
-        memberName = getIdentifier(IID);
+        memberName = getDeclBaseName(IID);
         break;
       }
 
@@ -1613,11 +1613,24 @@
   return values.front();
 }
 
-Identifier ModuleFile::getIdentifier(IdentifierID IID) {
+DeclBaseName ModuleFile::getDeclBaseName(IdentifierID IID) {
   if (IID == 0)
     return Identifier();
 
-  size_t rawID = IID - NUM_SPECIAL_MODULES;
+  if (IID < NUM_SPECIAL_IDS) {
+    switch (static_cast<SpecialIdentifierID>(static_cast<uint8_t>(IID))) {
+    case BUILTIN_MODULE_ID:
+    case CURRENT_MODULE_ID:
+    case OBJC_HEADER_MODULE_ID:
+        llvm_unreachable("Cannot get DeclBaseName of special module id");
+    case SUBSCRIPT_ID:
+      return DeclBaseName::createSubscript();
+    case NUM_SPECIAL_IDS:
+      llvm_unreachable("implementation detail only");
+    }
+  }
+
+  size_t rawID = IID - NUM_SPECIAL_IDS;
   assert(rawID < Identifiers.size() && "invalid identifier ID");
   auto identRecord = Identifiers[rawID];
 
@@ -1634,6 +1647,12 @@
   return getContext().getIdentifier(rawStrPtr.slice(0, terminatorOffset));
 }
 
+Identifier ModuleFile::getIdentifier(IdentifierID IID) {
+  auto name = getDeclBaseName(IID);
+  assert(!name.isSpecial());
+  return name.getIdentifier();
+}
+
 DeclContext *ModuleFile::getLocalDeclContext(DeclContextID DCID) {
   assert(DCID != 0 && "invalid local DeclContext ID 0");
   auto &declContextOrOffset = LocalDeclContexts[DCID-1];
@@ -1776,8 +1795,8 @@
 }
 
 ModuleDecl *ModuleFile::getModule(ModuleID MID) {
-  if (MID < NUM_SPECIAL_MODULES) {
-    switch (static_cast<SpecialModuleID>(static_cast<uint8_t>(MID))) {
+  if (MID < NUM_SPECIAL_IDS) {
+    switch (static_cast<SpecialIdentifierID>(static_cast<uint8_t>(MID))) {
     case BUILTIN_MODULE_ID:
       return getContext().TheBuiltinModule;
     case CURRENT_MODULE_ID:
@@ -1787,7 +1806,9 @@
         static_cast<ClangImporter *>(getContext().getClangModuleLoader());
       return clangImporter->getImportedHeaderModule();
     }
-    case NUM_SPECIAL_MODULES:
+    case SUBSCRIPT_ID:
+      llvm_unreachable("Modules cannot be named with special names");
+    case NUM_SPECIAL_IDS:
       llvm_unreachable("implementation detail only");
     }
   }
@@ -3380,7 +3401,7 @@
     SmallVector<Identifier, 2> argNames;
     for (auto argNameID : argNameAndDependencyIDs.slice(0, numArgNames))
       argNames.push_back(getIdentifier(argNameID));
-    DeclName name(ctx, ctx.Id_subscript, argNames);
+    DeclName name(ctx, DeclBaseName::createSubscript(), argNames);
 
     Expected<Decl *> overridden = getDeclChecked(overriddenID);
     if (!overridden) {
diff --git a/lib/Serialization/DeserializationErrors.h b/lib/Serialization/DeserializationErrors.h
index 90dd72c..afe319a 100644
--- a/lib/Serialization/DeserializationErrors.h
+++ b/lib/Serialization/DeserializationErrors.h
@@ -150,7 +150,7 @@
 public:
   explicit XRefTracePath(ModuleDecl &M) : baseM(M) {}
 
-  void addValue(Identifier name) {
+  void addValue(DeclBaseName name) {
     path.push_back({ PathPiece::Kind::Value, name });
   }
 
diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp
index 9357e87..649a57d 100644
--- a/lib/Serialization/ModuleFile.cpp
+++ b/lib/Serialization/ModuleFile.cpp
@@ -299,19 +299,26 @@
 /// Used to deserialize entries in the on-disk decl hash table.
 class ModuleFile::DeclTableInfo {
 public:
-  using internal_key_type = StringRef;
+  using internal_key_type = std::pair<DeclBaseName::Kind, StringRef>;
   using external_key_type = DeclBaseName;
   using data_type = SmallVector<std::pair<uint8_t, DeclID>, 8>;
   using hash_value_type = uint32_t;
   using offset_type = unsigned;
 
   internal_key_type GetInternalKey(external_key_type ID) {
-    // TODO: Handle special names
-    return ID.getIdentifier().str();
+    if (ID.getKind() == DeclBaseName::Kind::Normal) {
+      return {DeclBaseName::Kind::Normal, ID.getIdentifier().str()};
+    } else {
+      return {ID.getKind(), StringRef()};
+    }
   }
 
   hash_value_type ComputeHash(internal_key_type key) {
-    return llvm::HashString(key);
+    if (key.first == DeclBaseName::Kind::Normal) {
+      return llvm::HashString(key.second);
+    } else {
+      return (hash_value_type)key.first;
+    }
   }
 
   static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
@@ -325,8 +332,18 @@
   }
 
   static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
-    // TODO: Handle special names
-    return StringRef(reinterpret_cast<const char *>(data), length);
+    uint8_t kind = endian::readNext<uint8_t, little, unaligned>(data);
+    switch (kind) {
+    case static_cast<uint8_t>(DeclNameKind::Normal): {
+      StringRef str(reinterpret_cast<const char *>(data),
+                    length - sizeof(uint8_t));
+      return {DeclBaseName::Kind::Normal, str};
+    }
+    case static_cast<uint8_t>(DeclNameKind::Subscript):
+      return {DeclBaseName::Kind::Subscript, StringRef()};
+    default:
+      llvm_unreachable("Unknown DeclNameKind");
+    }
   }
 
   static data_type ReadData(internal_key_type key, const uint8_t *data,
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 322f91f..517480e 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -85,16 +85,23 @@
     using offset_type = unsigned;
 
     hash_value_type ComputeHash(key_type_ref key) {
-      assert(!key.empty());
-      // TODO: Handle special names
-      return llvm::HashString(key.getIdentifier().str());
+      switch (key.getKind()) {
+        case DeclBaseName::Kind::Normal:
+          assert(!key.empty());
+          return llvm::HashString(key.getIdentifier().str());
+        case DeclBaseName::Kind::Subscript:
+          return static_cast<uint8_t>(DeclNameKind::Subscript);
+      }
     }
 
     std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
                                                     key_type_ref key,
                                                     data_type_ref data) {
-      // TODO: Handle special names
-      uint32_t keyLength = key.getIdentifier().str().size();
+      uint32_t keyLength = sizeof(uint8_t); // For the flag of the name's kind
+      if (key.getKind() == DeclBaseName::Kind::Normal) {
+        keyLength += key.getIdentifier().str().size(); // The name's length
+      }
+
       uint32_t dataLength = (sizeof(uint32_t) + 1) * data.size();
       endian::Writer<little> writer(out);
       writer.write<uint16_t>(keyLength);
@@ -103,8 +110,16 @@
     }
 
     void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
-      // TODO: Handle special names
-      out << key.getIdentifier().str();
+      endian::Writer<little> writer(out);
+      switch (key.getKind()) {
+      case DeclBaseName::Kind::Normal:
+        writer.write<uint8_t>(static_cast<uint8_t>(DeclNameKind::Normal));
+        writer.OS << key.getIdentifier().str();
+        break;
+      case DeclBaseName::Kind::Subscript:
+        writer.write<uint8_t>(static_cast<uint8_t>(DeclNameKind::Subscript));
+        break;
+      }
     }
 
     void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
@@ -479,16 +494,22 @@
 }
 
 IdentifierID Serializer::addDeclBaseNameRef(DeclBaseName ident) {
-  if (ident.empty())
-    return 0;
+  switch (ident.getKind()) {
+  case DeclBaseName::Kind::Normal: {
+    if (ident.empty())
+      return 0;
 
-  IdentifierID &id = IdentifierIDs[ident.getIdentifier()];
-  if (id != 0)
+    IdentifierID &id = IdentifierIDs[ident.getIdentifier()];
+    if (id != 0)
+      return id;
+
+    id = ++LastIdentifierID;
+    IdentifiersToWrite.push_back(ident.getIdentifier());
     return id;
-
-  id = ++LastIdentifierID;
-  IdentifiersToWrite.push_back(ident.getIdentifier());
-  return id;
+  }
+  case DeclBaseName::Kind::Subscript:
+    return SUBSCRIPT_ID;
+  }
 }
 
 IdentifierID Serializer::addModuleRef(const ModuleDecl *M) {
@@ -1708,12 +1729,9 @@
 
     abbrCode = DeclTypeAbbrCodes[XRefValuePathPieceLayout::Code];
     bool isProtocolExt = SD->getDeclContext()->getAsProtocolExtensionContext();
-    auto iid = addDeclBaseNameRef(SD->getBaseName().getIdentifier());
     XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
-                                         addTypeRef(ty),
-                                         iid,
-                                         isProtocolExt,
-                                         SD->isStatic());
+                                         addTypeRef(ty), SUBSCRIPT_ID,
+                                         isProtocolExt, SD->isStatic());
     break;
   }
       
@@ -4348,8 +4366,7 @@
         // Add operator methods.
         // Note that we don't have to add operators that are already in the
         // top-level list.
-        auto iid = memberValue->getBaseName().getIdentifier();
-        operatorMethodDecls[iid].push_back({
+        operatorMethodDecls[memberValue->getBaseName()].push_back({
           /*ignored*/0,
           S.addDeclRef(memberValue)
         });
diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h
index e65d04f..e885cfd 100644
--- a/lib/Serialization/Serialization.h
+++ b/lib/Serialization/Serialization.h
@@ -221,10 +221,10 @@
 
   /// The last assigned IdentifierID for types from this module.
   ///
-  /// Note that special module IDs must not be valid IdentifierIDs, except that
-  /// 0 will always represent the empty identifier.
+  /// Note that special module IDs and IDs of special names must not be valid
+  /// IdentifierIDs, except that 0 will always represent the empty identifier.
   uint32_t /*IdentifierID*/ LastIdentifierID =
-      serialization::NUM_SPECIAL_MODULES - 1;
+      serialization::NUM_SPECIAL_IDS - 1;
 
   /// The last assigned GenericEnvironmentID for generic environments from this
   /// module.
diff --git a/test/Interpreter/subscripting.swift b/test/Interpreter/subscripting.swift
new file mode 100644
index 0000000..f3151b5
--- /dev/null
+++ b/test/Interpreter/subscripting.swift
@@ -0,0 +1,17 @@
+// RUN: %target-run-simple-swift | %FileCheck %s
+// REQUIRES: executable_test
+
+// Check that subscripts and functions named subscript can exist side-by-side
+struct Foo {
+  subscript() -> String {
+    return "subscript"
+  }
+  
+  func `subscript`() -> String {
+    return "func"
+  }
+}
+
+let f = Foo()
+print(f[]) // CHECK: subscript
+print(f.subscript()) // CHECK: func
diff --git a/test/SIL/Parser/function_named_subscript.sil b/test/SIL/Parser/function_named_subscript.sil
new file mode 100644
index 0000000..3830d01
--- /dev/null
+++ b/test/SIL/Parser/function_named_subscript.sil
@@ -0,0 +1,23 @@
+// RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
+
+// Make sure that we can parse escaped subscripts (representing functions named "subscript") in vtables
+
+sil_stage raw
+
+import Builtin
+import Swift
+import SwiftShims
+
+class SubscriptAsFunction {
+  func `subscript`()
+}
+
+sil hidden @_T04test19SubscriptAsFunctionC9subscriptyyF : $@convention(method) (@guaranteed SubscriptAsFunction) -> () {
+bb0(%0 : $SubscriptAsFunction):
+  return undef : $()
+}
+
+sil_vtable SubscriptAsFunction {
+  // CHECK: #SubscriptAsFunction.`subscript`!1: (SubscriptAsFunction) -> () -> () : _T04test19SubscriptAsFunctionC9subscriptyyF
+  #SubscriptAsFunction.`subscript`!1: (SubscriptAsFunction) -> () -> () : _T04test19SubscriptAsFunctionC9subscriptyyF
+}
diff --git a/test/SILGen/vtables.swift b/test/SILGen/vtables.swift
index aee60e7..09517c7 100644
--- a/test/SILGen/vtables.swift
+++ b/test/SILGen/vtables.swift
@@ -171,3 +171,15 @@
 
 // CHECK-LABEL: sil_vtable DerivedWithoutDefaults {
 // CHECK:         #BaseWithDefaults.a!1: {{.*}} : _T07vtables22DerivedWithoutDefaultsC1a{{[_0-9a-zA-Z]*}}F
+
+
+
+// Escape identifiers that represent special names
+
+class SubscriptAsFunction {
+  func `subscript`() {}
+}
+
+// CHECK-LABEL: sil_vtable SubscriptAsFunction {
+// CHECK-NOT:     #SubscriptAsFunction.subscript
+// CHECK:         #SubscriptAsFunction.`subscript`!1
diff --git a/test/decl/protocol/conforms/fixit_stub.swift b/test/decl/protocol/conforms/fixit_stub.swift
index 776be7b..4224a08 100644
--- a/test/decl/protocol/conforms/fixit_stub.swift
+++ b/test/decl/protocol/conforms/fixit_stub.swift
@@ -192,3 +192,9 @@
   func bar2() {}
 }
 
+protocol ProtocolHasSubscriptFunction {
+  func `subscript`() // expected-note{{protocol requires function 'subscript()' with type '() -> ()'; do you want to add a stub?}} {{74-74=\n    func `subscript`() {\n        <#code#>\n    \}\n}}
+}
+class ProtocolHasSubscriptFunctionAdopter: ProtocolHasSubscriptFunction { // expected-error{{type 'ProtocolHasSubscriptFunctionAdopter' does not conform to protocol 'ProtocolHasSubscriptFunction'}}
+
+}
diff --git a/test/decl/subscript/subscripting.swift b/test/decl/subscript/subscripting.swift
index 88a7a91..32058f5 100644
--- a/test/decl/subscript/subscripting.swift
+++ b/test/decl/subscript/subscripting.swift
@@ -310,3 +310,12 @@
     }
   }
 }
+
+// SR-2575
+struct SR2575 {
+  subscript() -> Int {
+    return 1
+  }
+}
+
+SR2575().subscript() // expected-error{{type 'SR2575' has no member 'subscript'}}
diff --git a/test/expr/unary/selector/selector.swift b/test/expr/unary/selector/selector.swift
index 7eef1c0..127d1cf 100644
--- a/test/expr/unary/selector/selector.swift
+++ b/test/expr/unary/selector/selector.swift
@@ -115,7 +115,7 @@
 }
 
 func testParseErrors4() {
-  _ = #selector(C1.subscript) // expected-error{{type 'C1.Type' has no subscript members}}
+  _ = #selector(C1.subscript) // expected-error{{type 'C1' has no member 'subscript'}}
 }
 
 // SR-1827
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index 9cc803d..3533d1a 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -1091,13 +1091,30 @@
   return false;
 }
 
+/// Converts a DeclBaseName to a string by assigning special names strings and
+/// escaping identifiers that would clash with these strings using '`'
+static StringRef getEscapedName(DeclBaseName name) {
+  switch (name.getKind()) {
+  case DeclBaseName::Kind::Subscript:
+    return "subscript";
+  case DeclBaseName::Kind::Normal:
+    return llvm::StringSwitch<StringRef>(name.getIdentifier().str())
+        .Case("subscript", "`subscript`")
+        .Default(name.getIdentifier().str());
+  }
+}
+
 static StringRef getPrintedName(SDKContext &Ctx, ValueDecl *VD) {
   llvm::SmallString<32> Result;
   if (auto FD = dyn_cast<AbstractFunctionDecl>(VD)) {
     auto DM = FD->getFullName();
 
-    // TODO: Handle special names
-    Result.append(DM.getBaseName().empty() ? "_" :DM.getBaseIdentifier().str());
+    if (DM.getBaseName().empty()) {
+      Result.append("_");
+    } else {
+      Result.append(getEscapedName(DM.getBaseName()));
+    }
+
     Result.append("(");
     for (auto Arg : DM.getArgumentNames()) {
       Result.append(Arg.empty() ? "_" : Arg.str());
@@ -1107,8 +1124,7 @@
     return Ctx.buffer(Result.str());
   }
   auto DM = VD->getFullName();
-  // TODO: Handle special names
-  Result.append(DM.getBaseIdentifier().str());
+  Result.append(getEscapedName(DM.getBaseName()));
   return Ctx.buffer(Result.str());
 }
 
@@ -1147,9 +1163,8 @@
     TypeAttrs.push_back(TypeAttrKind::TAK_noescape);
 }
 
-// TODO: Handle special names
 SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD) : Ctx(Ctx),
-    Name(VD->hasName() ? VD->getBaseName().getIdentifier().str() : Ctx.buffer("_")),
+    Name(VD->hasName() ? getEscapedName(VD->getBaseName()) : Ctx.buffer("_")),
     PrintedName(getPrintedName(Ctx, VD)), DKind(VD->getKind()),
     USR(calculateUsr(Ctx, VD)), Location(calculateLocation(Ctx, VD)),
     ModuleName(VD->getModuleContext()->getName().str()),
diff --git a/validation-test/Sema/type_checker_crashers/rdar27017206.swift b/validation-test/Sema/type_checker_crashers/rdar27017206.swift
deleted file mode 100644
index 6d2857a..0000000
--- a/validation-test/Sema/type_checker_crashers/rdar27017206.swift
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: not --crash %target-swift-frontend %s -typecheck
-// REQUIRES: asserts
-
-var str = "Hello"
-String(str.characters.subscript(
-    str.characters.startIndex..<str.characters.endIndex))
diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar27017206.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar27017206.swift
new file mode 100644
index 0000000..77a067e
--- /dev/null
+++ b/validation-test/Sema/type_checker_crashers_fixed/rdar27017206.swift
@@ -0,0 +1,5 @@
+// RUN: not %target-swift-frontend %s -typecheck
+
+var str = "Hello"
+String(str.characters.subscript(
+    str.characters.startIndex..<str.characters.endIndex))