When serializing a DeclRefExpr, always store the number of explicit template
arguments at the same offset, since it's needed when creating the empty
DeclRefExpr when deserializing. Fixes a memory corruption issue that would lead
to random bugs and crashes.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127125 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 9bf417c..e39fe3b 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -423,21 +423,21 @@
 
   bool HasQualifier = Record[Idx++];
   bool HasExplicitTemplateArgs = Record[Idx++];
-  
+  unsigned NumTemplateArgs = 0;
+  if (HasExplicitTemplateArgs)
+    NumTemplateArgs = Record[Idx++];
+
   E->DecoratedD.setInt((HasQualifier? DeclRefExpr::HasQualifierFlag : 0) |
       (HasExplicitTemplateArgs 
          ? DeclRefExpr::HasExplicitTemplateArgumentListFlag : 0));
   
-  if (HasQualifier) {
+  if (HasQualifier)
     E->getNameQualifier()->QualifierLoc
       = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
-  }
 
-  if (HasExplicitTemplateArgs) {
-    unsigned NumTemplateArgs = Record[Idx++];
+  if (HasExplicitTemplateArgs)
     ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
                                      NumTemplateArgs);
-  }
 
   E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++])));
   E->setLocation(ReadSourceLocation(Record, Idx));
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 21f1d51..a0ecf27 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -382,15 +382,17 @@
   Record.push_back(E->hasQualifier());
   Record.push_back(E->hasExplicitTemplateArgs());
 
-  if (E->hasQualifier())
-    Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
-
   if (E->hasExplicitTemplateArgs()) {
     unsigned NumTemplateArgs = E->getNumTemplateArgs();
     Record.push_back(NumTemplateArgs);
-    AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs());
   }
 
+  if (E->hasQualifier())
+    Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
+
+  if (E->hasExplicitTemplateArgs())
+    AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs());
+
   Writer.AddDeclRef(E->getDecl(), Record);
   Writer.AddSourceLocation(E->getLocation(), Record);
   Writer.AddDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName(), Record);
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index cd48666..982fc67 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -43,3 +43,22 @@
 namespace ZeroLengthExplicitTemplateArgs {
   template void f<X>(X*);
 }
+
+// This used to overwrite memory and crash.
+namespace Test1 {
+  struct StringHasher {
+    template<typename T, char Converter(T)> static inline unsigned createHash(const T*, unsigned) {
+      return 0;
+    }
+  };
+
+  struct CaseFoldingHash {
+    static inline char foldCase(char) {
+      return 0;
+    }
+
+    static unsigned hash(const char* data, unsigned length) {
+      return StringHasher::createHash<char, foldCase>(data, length);
+    }
+  };
+}