Various minor fixes to PCH reading and writing, with general
cleanup. Aside from a minor tweak to the PCH file format, no
functionality change. 


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68793 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index be34942..62783b1 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -519,6 +519,13 @@
   return decl_iterator(); 
 }
 
+bool DeclContext::decls_empty(ASTContext &Context) const {
+  if (hasExternalLexicalStorage())
+    LoadLexicalDeclsFromExternalStorage(Context);
+
+  return !FirstDecl;
+}
+
 void DeclContext::addDecl(ASTContext &Context, Decl *D) {
   assert(D->getLexicalDeclContext() == this &&
          "Decl inserted into wrong lexical context");
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 01a79b4..0e5b6ee 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -192,95 +192,12 @@
   }
 }
 
-/// \brief Read the type-offsets block.
-bool PCHReader::ReadTypeOffsets() {
-  if (Stream.EnterSubBlock(pch::TYPE_OFFSETS_BLOCK_ID))
-    return Error("Malformed block record");
-
-  RecordData Record;
-  while (true) {
-    unsigned Code = Stream.ReadCode();
-    if (Code == llvm::bitc::END_BLOCK) {
-      if (Stream.ReadBlockEnd())
-        return Error("Error at end of TYPE_OFFSETS block");
-      return false;
-    }
-    
-    if (Code == llvm::bitc::ENTER_SUBBLOCK) {
-      // No known subblocks, always skip them.
-      Stream.ReadSubBlockID();
-      if (Stream.SkipBlock())
-        return Error("Malformed block record");
-      continue;
-    }
-    
-    if (Code == llvm::bitc::DEFINE_ABBREV) {
-      Stream.ReadAbbrevRecord();
-      continue;
-    }
-    
-    // Read a record.
-    Record.clear();
-    switch (Stream.ReadRecord(Code, Record)) {
-    default:  // Default behavior: ignore.
-      break;
-    case pch::TYPE_OFFSET:
-      if (!TypeOffsets.empty())
-        return Error("Duplicate TYPE_OFFSETS block");
-      TypeOffsets.swap(Record);
-      TypeAlreadyLoaded.resize(TypeOffsets.size(), false);
-      break;
-    }
-  }
-}
-
-/// \brief Read the decl-offsets block.
-bool PCHReader::ReadDeclOffsets() {
-  if (Stream.EnterSubBlock(pch::DECL_OFFSETS_BLOCK_ID))
-    return Error("Malformed block record");
-
-  RecordData Record;
-  while (true) {
-    unsigned Code = Stream.ReadCode();
-    if (Code == llvm::bitc::END_BLOCK) {
-      if (Stream.ReadBlockEnd())
-        return Error("Error at end of DECL_OFFSETS block");
-      return false;
-    }
-    
-    if (Code == llvm::bitc::ENTER_SUBBLOCK) {
-      // No known subblocks, always skip them.
-      Stream.ReadSubBlockID();
-      if (Stream.SkipBlock())
-        return Error("Malformed block record");
-      continue;
-    }
-    
-    if (Code == llvm::bitc::DEFINE_ABBREV) {
-      Stream.ReadAbbrevRecord();
-      continue;
-    }
-    
-    // Read a record.
-    Record.clear();
-    switch (Stream.ReadRecord(Code, Record)) {
-    default:  // Default behavior: ignore.
-      break;
-    case pch::DECL_OFFSET:
-      if (!DeclOffsets.empty())
-        return Error("Duplicate DECL_OFFSETS block");
-      DeclOffsets.swap(Record);
-      DeclAlreadyLoaded.resize(DeclOffsets.size(), false);
-      break;
-    }
-  }
-}
-
 bool PCHReader::ReadPCHBlock() {
   if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID))
     return Error("Malformed block record");
 
   // Read all of the records and blocks for the PCH file.
+  RecordData Record;
   while (!Stream.AtEndOfStream()) {
     unsigned Code = Stream.ReadCode();
     if (Code == llvm::bitc::END_BLOCK) {
@@ -302,17 +219,34 @@
         if (ReadSourceManagerBlock())
           return Error("Malformed source manager block");
         break;
-
-      case pch::TYPE_OFFSETS_BLOCK_ID:
-        if (ReadTypeOffsets())
-          return Error("Malformed type-offsets block");
-        break;
-
-      case pch::DECL_OFFSETS_BLOCK_ID:
-        if (ReadDeclOffsets())
-          return Error("Malformed decl-offsets block");
-        break;
       }
+      continue;
+    }
+
+    if (Code == llvm::bitc::DEFINE_ABBREV) {
+      Stream.ReadAbbrevRecord();
+      continue;
+    }
+
+    // Read and process a record.
+    Record.clear();
+    switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record)) {
+    default:  // Default behavior: ignore.
+      break;
+
+    case pch::TYPE_OFFSET:
+      if (!TypeOffsets.empty())
+        return Error("Duplicate TYPE_OFFSET record in PCH file");
+      TypeOffsets.swap(Record);
+      TypeAlreadyLoaded.resize(TypeOffsets.size(), false);
+      break;
+
+    case pch::DECL_OFFSET:
+      if (!DeclOffsets.empty())
+        return Error("Duplicate DECL_OFFSET record in PCH file");
+      DeclOffsets.swap(Record);
+      DeclAlreadyLoaded.resize(DeclOffsets.size(), false);
+      break;
     }
   }
 
@@ -426,7 +360,7 @@
 
     // FIXME: Several other kinds of types to deserialize here!
   default:
-    assert("Unable to deserialize this type");
+    assert(false && "Unable to deserialize this type");
     break;
   }
 
@@ -500,7 +434,7 @@
   return D;
 }
 
-QualType PCHReader::GetType(unsigned ID) {
+QualType PCHReader::GetType(pch::TypeID ID) {
   unsigned Quals = ID & 0x07; 
   unsigned Index = ID >> 3;
 
@@ -550,7 +484,7 @@
   return QualType(reinterpret_cast<Type *>(TypeOffsets[Index]), Quals);
 }
 
-Decl *PCHReader::GetDecl(unsigned ID) {
+Decl *PCHReader::GetDecl(pch::DeclID ID) {
   if (ID == 0)
     return 0;
 
@@ -563,7 +497,7 @@
 }
 
 bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
-                                     llvm::SmallVectorImpl<unsigned> &Decls) {
+                                  llvm::SmallVectorImpl<pch::DeclID> &Decls) {
   assert(DC->hasExternalLexicalStorage() && 
          "DeclContext has no lexical decls in storage");
   uint64_t Offset = DeclContextOffsets[DC].first;
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 1986b59..f80d46a 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -490,7 +490,7 @@
 
 /// \brief Write the representation of a type to the PCH stream.
 void PCHWriter::WriteType(const Type *T) {
-  pch::ID &ID = TypeIDs[T];
+  pch::TypeID &ID = TypeIDs[T];
   if (ID == 0) // we haven't seen this type before.
     ID = NextTypeID++;
   
@@ -547,10 +547,8 @@
   // Exit the types block
   S.ExitBlock();
 
-  // Write the type offsets block
-  S.EnterSubblock(pch::TYPE_OFFSETS_BLOCK_ID, 2);
+  // Write the type offsets record
   S.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);
-  S.ExitBlock();
 }
 
 /// \brief Write the block containing all of the declaration IDs
@@ -560,7 +558,7 @@
 /// bistream, or 0 if no block was written.
 uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context, 
                                                  DeclContext *DC) {
-  if (DC->decls_begin(Context) == DC->decls_end(Context))
+  if (DC->decls_empty(Context))
     return 0;
 
   uint64_t Offset = S.GetCurrentBitNo();
@@ -638,7 +636,7 @@
     }
 
     // Determine the ID for this declaration
-    pch::ID ID = DeclIDs[D];
+    pch::DeclID ID = DeclIDs[D];
     if (ID == 0)
       ID = DeclIDs.size();
 
@@ -664,10 +662,8 @@
   // Exit the declarations block
   S.ExitBlock();
 
-  // Write the declaration offsets block
-  S.EnterSubblock(pch::DECL_OFFSETS_BLOCK_ID, 2);
+  // Write the declaration offsets record
   S.EmitRecord(pch::DECL_OFFSET, DeclOffsets);
-  S.ExitBlock();
 }
 
 PCHWriter::PCHWriter(llvm::BitstreamWriter &S) 
@@ -720,7 +716,7 @@
   }
 
   if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) {
-    pch::ID ID;
+    pch::TypeID ID;
     switch (BT->getKind()) {
     case BuiltinType::Void:       ID = pch::PREDEF_TYPE_VOID_ID;       break;
     case BuiltinType::Bool:       ID = pch::PREDEF_TYPE_BOOL_ID;       break;
@@ -748,7 +744,7 @@
     return;
   }
 
-  pch::ID &ID = TypeIDs[T.getTypePtr()];
+  pch::TypeID &ID = TypeIDs[T.getTypePtr()];
   if (ID == 0) // we haven't seen this type before
     ID = NextTypeID++;
 
@@ -762,7 +758,7 @@
     return;
   }
 
-  pch::ID &ID = DeclIDs[D];
+  pch::DeclID &ID = DeclIDs[D];
   if (ID == 0) { 
     // We haven't seen this declaration before. Give it a new ID and
     // enqueue it in the list of declarations to emit.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b024d36..4f87b48 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -526,6 +526,16 @@
 
   // __builtin_va_list gets redeclared in the built-in definitions
   // buffer when using PCH. Don't complain about such redefinitions.
+  //
+  // FIXME: The problem here is that the __builtin_va_list declaration
+  // comes in as target-specific text in the predefines buffer, both
+  // in the generation of the PCH file and in the source file. Thus,
+  // we end up with two typedefs for the same type, which is an error
+  // in C. Our hackish solution is to allow redundant typedefs *to the
+  // same type* if the types are defined in the predefined buffer. We
+  // would like to eliminate this ugliness, perhaps by making
+  // __builtin_va_list a real, Sema-supplied declaration rather than
+  // putting its text into the predefines buffer.
   if (Context.getExternalSource() && 
       strcmp(SourceMgr.getBufferName(New->getLocation()), "<built-in>") == 0)
     return false;