diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 85ed3ba7db0b9cd2d587df08fa0dee2b8feadd98..d6778ecf397fed5f117b8463a32c60fed924302d 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -610,11 +610,8 @@ void NamedDecl::ClearLinkageCache() {
 }
 
 Linkage NamedDecl::getLinkage() const {
-  if (HasCachedLinkage) {
-    assert(Linkage(CachedLinkage) ==
-           getLVForDecl(this, true).linkage());
+  if (HasCachedLinkage)
     return Linkage(CachedLinkage);
-  }
 
   CachedLinkage = getLVForDecl(this, true).linkage();
   HasCachedLinkage = 1;
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index c2ace3078298f3c43074ebc3269748611313335f..64b33b066b0790e866eebeaa7b689cc21825177c 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -526,6 +526,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
   FD->HasImplicitReturnZero = Record[Idx++];
   FD->IsConstexpr = Record[Idx++];
   FD->HasSkippedBody = Record[Idx++];
+  FD->HasCachedLinkage = true;
+  FD->CachedLinkage = Record[Idx++];
   FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
 
   switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
@@ -908,6 +910,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
   VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
   VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
   VD->VarDeclBits.IsConstexpr = Record[Idx++];
+  VD->HasCachedLinkage = true;
+  VD->CachedLinkage = Record[Idx++];
   
   // Only true variables (not parameters or implicit parameters) can be merged.
   if (VD->getKind() == Decl::Var)
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index c2e1513586fa6c8c20f02baf5695f7a9f54f93d4..3795e21bdf674f4d5501b356ab71bea0063bd9dd 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -330,6 +330,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
   Record.push_back(D->hasImplicitReturnZero());
   Record.push_back(D->isConstexpr());
   Record.push_back(D->HasSkippedBody);
+  Record.push_back(D->getLinkage());
   Writer.AddSourceLocation(D->getLocEnd(), Record);
 
   Record.push_back(D->getTemplatedKind());
@@ -682,6 +683,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
   Record.push_back(D->isCXXForRangeDecl());
   Record.push_back(D->isARCPseudoStrong());
   Record.push_back(D->isConstexpr());
+  Record.push_back(D->getLinkage());
 
   if (D->getInit()) {
     Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
@@ -1505,6 +1507,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
   Abv->Add(BitCodeAbbrevOp(0));                       // isCXXForRangeDecl
   Abv->Add(BitCodeAbbrevOp(0));                       // isARCPseudoStrong
   Abv->Add(BitCodeAbbrevOp(0));                       // isConstexpr
+  Abv->Add(BitCodeAbbrevOp(0));                       // Linkage
   Abv->Add(BitCodeAbbrevOp(0));                       // HasInit
   Abv->Add(BitCodeAbbrevOp(0));                   // HasMemberSpecializationInfo
   // ParmVarDecl
@@ -1584,6 +1587,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
   Abv->Add(BitCodeAbbrevOp(0));                         // isConstexpr
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Linkage
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
   // Type Source Info
diff --git a/test/Modules/Inputs/cxx-linkage-cache.h b/test/Modules/Inputs/cxx-linkage-cache.h
new file mode 100644
index 0000000000000000000000000000000000000000..df829279761ae7d7c01c1c108841dfbd223673fa
--- /dev/null
+++ b/test/Modules/Inputs/cxx-linkage-cache.h
@@ -0,0 +1,11 @@
+// Reduced from a crash encountered with a modularized libc++, where
+// we would try to compute the linkage of a declaration before we
+// finish loading the relevant pieces of it.
+inline namespace D {
+  template<class>
+  struct U {
+    friend bool f(const U &);
+  };
+
+  template class U<int>;
+}
diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map
index f219036e21d6caacf7f857bcb0e0951a6a01ce78..53f2fd65d34ced73de8b22123cfeda467285117e 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -179,3 +179,7 @@ module cxx_many_overloads {
 module cxx_inline_namespace {
   header "cxx-inline-namespace.h"
 }
+
+module cxx_linkage_cache {
+  header "cxx-linkage-cache.h"
+}
diff --git a/test/Modules/cxx-linkage-cache.cpp b/test/Modules/cxx-linkage-cache.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..296cc8034f5ada9a476580a41e192120c27e46f8
--- /dev/null
+++ b/test/Modules/cxx-linkage-cache.cpp
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+
+@import cxx_linkage_cache;
+
+T x; // expected-error {{unknown type name 'T'}}
+D::U<int> u;
+bool b = f(u);