Пример #1
0
static bool enterTopLevelModuleBlock(llvm::BitstreamCursor &cursor,
                                     unsigned ID,
                                     bool shouldReadBlockInfo = true) {
  auto next = cursor.advance();

  if (next.Kind != llvm::BitstreamEntry::SubBlock)
    return false;

  if (next.ID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
    if (shouldReadBlockInfo) {
      if (cursor.ReadBlockInfoBlock())
        return false;
    } else {
      if (cursor.SkipBlock())
        return false;
    }
    return enterTopLevelModuleBlock(cursor, ID, false);
  }

  if (next.ID != ID)
    return false;

  cursor.EnterSubBlock(ID);
  return true;
}
Пример #2
0
LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
  if (Stream.EnterSubBlock(lfort::serialized_diags::BLOCK_META)) {
    reportInvalidFile("Malformed metadata block");
    return Failure;
  }

  bool versionChecked = false;
  
  while (true) {
    unsigned blockOrCode = 0;
    StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
                                               blockOrCode);
    
    switch(Res) {
      case Read_EndOfStream:
        llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
      case Read_Failure:
        return Failure;
      case Read_Record:
        break;
      case Read_BlockBegin:
        if (Stream.SkipBlock()) {
          reportInvalidFile("Malformed metadata block");
          return Failure;
        }
      case Read_BlockEnd:
        if (!versionChecked) {
          reportInvalidFile("Diagnostics file does not contain version"
                            " information");
          return Failure;
        }
        return Success;
    }
    
    RecordData Record;
    const char *Blob;
    unsigned BlobLen;
    unsigned recordID = Stream.ReadRecord(blockOrCode, Record, &Blob, &BlobLen);
    
    if (recordID == serialized_diags::RECORD_VERSION) {
      if (Record.size() < 1) {
        reportInvalidFile("malformed VERSION identifier in diagnostics file");
        return Failure;
      }
      if (Record[0] > MaxSupportedVersion) {
        reportInvalidFile("diagnosics file is a newer version than the one "
                          "supported");
        return Failure;
      }
      versionChecked = true;
    }
  }
}
Пример #3
0
/// Populate \p extendedInfo with the data from the options block.
///
/// Returns true on success.
static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
                             SmallVectorImpl<uint64_t> &scratch,
                             ExtendedValidationInfo &extendedInfo) {
  auto next = cursor.advance();
  while (next.Kind != llvm::BitstreamEntry::EndBlock) {
    if (next.Kind == llvm::BitstreamEntry::Error)
      return false;

    if (next.Kind == llvm::BitstreamEntry::SubBlock) {
      // Unknown metadata sub-block, possibly for use by a future version of
      // the module format.
      if (cursor.SkipBlock())
        return false;
      next = cursor.advance();
      continue;
    }

    scratch.clear();
    StringRef blobData;
    unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
    switch (kind) {
    case options_block::SDK_PATH:
      extendedInfo.setSDKPath(blobData);
      break;
    case options_block::XCC:
      extendedInfo.addExtraClangImporterOption(blobData);
      break;
    case options_block::IS_SIB:
      bool IsSIB;
      options_block::IsSIBLayout::readRecord(scratch, IsSIB);
      extendedInfo.setIsSIB(IsSIB);
      break;
    case options_block::IS_TESTABLE:
      extendedInfo.setIsTestable(true);
      break;
    case options_block::IS_RESILIENT:
      extendedInfo.setIsResilient(true);
      break;
    default:
      // Unknown options record, possibly for use by a future version of the
      // module format.
      break;
    }

    next = cursor.advance();
  }

  return true;
}
Пример #4
0
bool ModuleFile::readCommentBlock(llvm::BitstreamCursor &cursor) {
  cursor.EnterSubBlock(COMMENT_BLOCK_ID);

  SmallVector<uint64_t, 4> scratch;
  StringRef blobData;

  while (true) {
    auto next = cursor.advance();
    switch (next.Kind) {
    case llvm::BitstreamEntry::EndBlock:
      return true;

    case llvm::BitstreamEntry::Error:
      return false;

    case llvm::BitstreamEntry::SubBlock:
      // Unknown sub-block, which this version of the compiler won't use.
      if (cursor.SkipBlock())
        return false;
      break;

    case llvm::BitstreamEntry::Record:
      scratch.clear();
      unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);

      switch (kind) {
      case comment_block::DECL_COMMENTS:
        DeclCommentTable = readDeclCommentTable(scratch, blobData);
        break;
      case comment_block::GROUP_NAMES:
        GroupNamesMap = readGroupTable(scratch, blobData);
        break;
      default:
        // Unknown index kind, which this version of the compiler won't use.
        break;
      }
      break;
    }
  }
}
Пример #5
0
std::error_code
SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META))
    return SDError::MalformedMetadataBlock;

  bool VersionChecked = false;

  while (true) {
    unsigned BlockOrCode = 0;
    llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
    if (!Res)
      Res.getError();

    switch (Res.get()) {
    case Cursor::Record:
      break;
    case Cursor::BlockBegin:
      if (Stream.SkipBlock())
        return SDError::MalformedMetadataBlock;
    case Cursor::BlockEnd:
      if (!VersionChecked)
        return SDError::MissingVersion;
      return std::error_code();
    }

    SmallVector<uint64_t, 1> Record;
    unsigned RecordID = Stream.readRecord(BlockOrCode, Record);

    if (RecordID == RECORD_VERSION) {
      if (Record.size() < 1)
        return SDError::MissingVersion;
      if (Record[0] > VersionNumber)
        return SDError::VersionMismatch;
      VersionChecked = true;
    }
  }
}
Пример #6
0
bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) {
  cursor.EnterSubBlock(INDEX_BLOCK_ID);

  SmallVector<uint64_t, 4> scratch;
  StringRef blobData;

  while (true) {
    auto next = cursor.advance();
    switch (next.Kind) {
    case llvm::BitstreamEntry::EndBlock:
      return true;

    case llvm::BitstreamEntry::Error:
      return false;

    case llvm::BitstreamEntry::SubBlock:
      // Unknown sub-block, which this version of the compiler won't use.
      if (cursor.SkipBlock())
        return false;
      break;

    case llvm::BitstreamEntry::Record:
      scratch.clear();
      blobData = {};
      unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);

      switch (kind) {
      case index_block::DECL_OFFSETS:
        assert(blobData.empty());
        Decls.assign(scratch.begin(), scratch.end());
        break;
      case index_block::DECL_CONTEXT_OFFSETS:
        assert(blobData.empty());
        DeclContexts.assign(scratch.begin(), scratch.end());
        break;
      case index_block::TYPE_OFFSETS:
        assert(blobData.empty());
        Types.assign(scratch.begin(), scratch.end());
        break;
      case index_block::IDENTIFIER_OFFSETS:
        assert(blobData.empty());
        Identifiers.assign(scratch.begin(), scratch.end());
        break;
      case index_block::TOP_LEVEL_DECLS:
        TopLevelDecls = readDeclTable(scratch, blobData);
        break;
      case index_block::OPERATORS:
        OperatorDecls = readDeclTable(scratch, blobData);
        break;
      case index_block::EXTENSIONS:
        ExtensionDecls = readDeclTable(scratch, blobData);
        break;
      case index_block::CLASS_MEMBERS:
        ClassMembersByName = readDeclTable(scratch, blobData);
        break;
      case index_block::OPERATOR_METHODS:
        OperatorMethodDecls = readDeclTable(scratch, blobData);
        break;
      case index_block::OBJC_METHODS:
        ObjCMethods = readObjCMethodTable(scratch, blobData);
        break;
      case index_block::ENTRY_POINT:
        assert(blobData.empty());
        setEntryPointClassID(scratch.front());
        break;
      case index_block::LOCAL_TYPE_DECLS:
        LocalTypeDecls = readLocalDeclTable(scratch, blobData);
        break;
      case index_block::LOCAL_DECL_CONTEXT_OFFSETS:
        assert(blobData.empty());
        LocalDeclContexts.assign(scratch.begin(), scratch.end());
        break;
      case index_block::NORMAL_CONFORMANCE_OFFSETS:
        assert(blobData.empty());
        NormalConformances.assign(scratch.begin(), scratch.end());
        break;

      default:
        // Unknown index kind, which this version of the compiler won't use.
        break;
      }
      break;
    }
  }
}
Пример #7
0
static ValidationInfo
validateControlBlock(llvm::BitstreamCursor &cursor,
                     SmallVectorImpl<uint64_t> &scratch,
                     ExtendedValidationInfo *extendedInfo) {
  // The control block is malformed until we've at least read a major version
  // number.
  ValidationInfo result;
  bool versionSeen = false;

  auto next = cursor.advance();
  while (next.Kind != llvm::BitstreamEntry::EndBlock) {
    if (next.Kind == llvm::BitstreamEntry::Error) {
      result.status = Status::Malformed;
      return result;
    }

    if (next.Kind == llvm::BitstreamEntry::SubBlock) {
      if (next.ID == OPTIONS_BLOCK_ID && extendedInfo) {
        cursor.EnterSubBlock(OPTIONS_BLOCK_ID);
        if (!readOptionsBlock(cursor, scratch, *extendedInfo)) {
          result.status = Status::Malformed;
          return result;
        }
      } else {
        // Unknown metadata sub-block, possibly for use by a future version of
        // the module format.
        if (cursor.SkipBlock()) {
          result.status = Status::Malformed;
          return result;
        }
      }
      next = cursor.advance();
      continue;
    }

    scratch.clear();
    StringRef blobData;
    unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
    switch (kind) {
    case control_block::METADATA: {
      if (versionSeen) {
        result.status = Status::Malformed;
        break;
      }

      uint16_t versionMajor = scratch[0];
      if (versionMajor > VERSION_MAJOR)
        result.status = Status::FormatTooNew;
      else if (versionMajor < VERSION_MAJOR)
        result.status = Status::FormatTooOld;
      else
        result.status = Status::Valid;

      // Major version 0 does not have stable minor versions.
      if (versionMajor == 0) {
        uint16_t versionMinor = scratch[1];
        if (versionMinor != VERSION_MINOR) {
          if (versionMinor < VERSION_MINOR)
            result.status = Status::FormatTooOld;
          else
            result.status = Status::FormatTooNew;
        }
      }

      versionSeen = true;
      break;
    }
    case control_block::MODULE_NAME:
      result.name = blobData;
      break;
    case control_block::TARGET:
      result.targetTriple = blobData;
      break;
    default:
      // Unknown metadata record, possibly for use by a future version of the
      // module format.
      break;
    }

    next = cursor.advance();
  }

  return result;
}
Пример #8
0
GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer,
                                     llvm::BitstreamCursor Cursor)
    : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(),
      NumIdentifierLookupHits() {
  // Read the global index.
  bool InGlobalIndexBlock = false;
  bool Done = false;
  while (!Done) {
    llvm::BitstreamEntry Entry = Cursor.advance();

    switch (Entry.Kind) {
    case llvm::BitstreamEntry::Error:
      return;

    case llvm::BitstreamEntry::EndBlock:
      if (InGlobalIndexBlock) {
        InGlobalIndexBlock = false;
        Done = true;
        continue;
      }
      return;


    case llvm::BitstreamEntry::Record:
      // Entries in the global index block are handled below.
      if (InGlobalIndexBlock)
        break;

      return;

    case llvm::BitstreamEntry::SubBlock:
      if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {
        if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))
          return;

        InGlobalIndexBlock = true;
      } else if (Cursor.SkipBlock()) {
        return;
      }
      continue;
    }

    SmallVector<uint64_t, 64> Record;
    StringRef Blob;
    switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) {
    case INDEX_METADATA:
      // Make sure that the version matches.
      if (Record.size() < 1 || Record[0] != CurrentVersion)
        return;
      break;

    case MODULE: {
      unsigned Idx = 0;
      unsigned ID = Record[Idx++];

      // Make room for this module's information.
      if (ID == Modules.size())
        Modules.push_back(ModuleInfo());
      else
        Modules.resize(ID + 1);

      // Size/modification time for this module file at the time the
      // global index was built.
      Modules[ID].Size = Record[Idx++];
      Modules[ID].ModTime = Record[Idx++];

      // File name.
      unsigned NameLen = Record[Idx++];
      Modules[ID].FileName.assign(Record.begin() + Idx,
                                  Record.begin() + Idx + NameLen);
      Idx += NameLen;

      // Dependencies
      unsigned NumDeps = Record[Idx++];
      Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),
                                      Record.begin() + Idx,
                                      Record.begin() + Idx + NumDeps);
      Idx += NumDeps;

      // Make sure we're at the end of the record.
      assert(Idx == Record.size() && "More module info?");

      // Record this module as an unresolved module.
      // FIXME: this doesn't work correctly for module names containing path
      // separators.
      StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName);
      // Remove the -<hash of ModuleMapPath>
      ModuleName = ModuleName.rsplit('-').first;
      UnresolvedModules[ModuleName] = ID;
      break;
    }

    case IDENTIFIER_INDEX:
      // Wire up the identifier index.
      if (Record[0]) {
        IdentifierIndex = IdentifierIndexTable::Create(
            (const unsigned char *)Blob.data() + Record[0],
            (const unsigned char *)Blob.data() + sizeof(uint32_t),
            (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait());
      }
      break;
    }
  }
}
Пример #9
0
std::error_code
SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG))
    return SDError::MalformedDiagnosticBlock;

  std::error_code EC;
  if ((EC = visitStartOfDiagnostic()))
    return EC;

  SmallVector<uint64_t, 16> Record;
  while (true) {
    unsigned BlockOrCode = 0;
    llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
    if (!Res)
      Res.getError();

    switch (Res.get()) {
    case Cursor::BlockBegin:
      // The only blocks we care about are subdiagnostics.
      if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
        if ((EC = readDiagnosticBlock(Stream)))
          return EC;
      } else if (!Stream.SkipBlock())
        return SDError::MalformedSubBlock;
      continue;
    case Cursor::BlockEnd:
      if ((EC = visitEndOfDiagnostic()))
        return EC;
      return std::error_code();
    case Cursor::Record:
      break;
    }

    // Read the record.
    Record.clear();
    StringRef Blob;
    unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob);

    if (RecID < serialized_diags::RECORD_FIRST ||
        RecID > serialized_diags::RECORD_LAST)
      continue;

    switch ((RecordIDs)RecID) {
    case RECORD_CATEGORY:
      // A category has ID and name size.
      if (Record.size() != 2)
        return SDError::MalformedDiagnosticRecord;
      if ((EC = visitCategoryRecord(Record[0], Blob)))
        return EC;
      continue;
    case RECORD_DIAG:
      // A diagnostic has severity, location (4), category, flag, and message
      // size.
      if (Record.size() != 8)
        return SDError::MalformedDiagnosticRecord;
      if ((EC = visitDiagnosticRecord(
               Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
               Record[5], Record[6], Blob)))
        return EC;
      continue;
    case RECORD_DIAG_FLAG:
      // A diagnostic flag has ID and name size.
      if (Record.size() != 2)
        return SDError::MalformedDiagnosticRecord;
      if ((EC = visitDiagFlagRecord(Record[0], Blob)))
        return EC;
      continue;
    case RECORD_FILENAME:
      // A filename has ID, size, timestamp, and name size. The size and
      // timestamp are legacy fields that are always zero these days.
      if (Record.size() != 4)
        return SDError::MalformedDiagnosticRecord;
      if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
        return EC;
      continue;
    case RECORD_FIXIT:
      // A fixit has two locations (4 each) and message size.
      if (Record.size() != 9)
        return SDError::MalformedDiagnosticRecord;
      if ((EC = visitFixitRecord(
               Location(Record[0], Record[1], Record[2], Record[3]),
               Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
        return EC;
      continue;
    case RECORD_SOURCE_RANGE:
      // A source range is two locations (4 each).
      if (Record.size() != 8)
        return SDError::MalformedDiagnosticRecord;
      if ((EC = visitSourceRangeRecord(
               Location(Record[0], Record[1], Record[2], Record[3]),
               Location(Record[4], Record[5], Record[6], Record[7]))))
        return EC;
      continue;
    case RECORD_VERSION:
      // A version is just a number.
      if (Record.size() != 1)
        return SDError::MalformedDiagnosticRecord;
      if ((EC = visitVersionRecord(Record[0])))
        return EC;
      continue;
    }
  }
}
Пример #10
0
GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr,
                                     llvm::MemoryBuffer *Buffer,
                                     llvm::BitstreamCursor Cursor)
  : Buffer(Buffer), IdentifierIndex(),
    NumIdentifierLookups(), NumIdentifierLookupHits()
{
  typedef llvm::DenseMap<unsigned, LoadedModuleInfo> LoadedModulesMap;
  LoadedModulesMap LoadedModules;
  
  // Read the global index.
  unsigned LargestID = 0;
  bool InGlobalIndexBlock = false;
  bool Done = false;
  bool AnyOutOfDate = false;
  while (!Done) {
    llvm::BitstreamEntry Entry = Cursor.advance();

    switch (Entry.Kind) {
    case llvm::BitstreamEntry::Error:
      return;

    case llvm::BitstreamEntry::EndBlock:
      if (InGlobalIndexBlock) {
        InGlobalIndexBlock = false;
        Done = true;
        continue;
      }
      return;


    case llvm::BitstreamEntry::Record:
      // Entries in the global index block are handled below.
      if (InGlobalIndexBlock)
        break;

      return;

    case llvm::BitstreamEntry::SubBlock:
      if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {
        if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))
          return;

        InGlobalIndexBlock = true;
      } else if (Cursor.SkipBlock()) {
        return;
      }
      continue;
    }

    SmallVector<uint64_t, 64> Record;
    StringRef Blob;
    switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) {
    case INDEX_METADATA:
      // Make sure that the version matches.
      if (Record.size() < 1 || Record[0] != CurrentVersion)
        return;
      break;

    case MODULE: {
      unsigned Idx = 0;
      unsigned ID = Record[Idx++];
      if (ID > LargestID)
        LargestID = ID;
      
      off_t Size = Record[Idx++];
      time_t ModTime = Record[Idx++];

      // File name.
      unsigned NameLen = Record[Idx++];
      llvm::SmallString<64> FileName(Record.begin() + Idx,
                                     Record.begin() + Idx + NameLen);
      Idx += NameLen;

      // Dependencies
      unsigned NumDeps = Record[Idx++];
      llvm::SmallVector<unsigned, 2>
        Dependencies(Record.begin() + Idx, Record.begin() + Idx + NumDeps);

      // Find the file. If we can't find it, ignore it.
      const FileEntry *File = FileMgr.getFile(FileName);
      if (!File) {
        AnyOutOfDate = true;
        break;
      }

      // If the module file is newer than the index, ignore it.
      if (File->getSize() != Size || File->getModificationTime() != ModTime) {
        AnyOutOfDate = true;
        break;
      }

      // Record this module. The dependencies will be resolved later.
      LoadedModuleInfo &Info = LoadedModules[ID];
      Info.File = File;
      Info.Dependencies.swap(Dependencies);
      break;
    }

    case IDENTIFIER_INDEX:
      // Wire up the identifier index.
      if (Record[0]) {
        IdentifierIndex = IdentifierIndexTable::Create(
                            (const unsigned char *)Blob.data() + Record[0],
                            (const unsigned char *)Blob.data(),
                            IdentifierIndexReaderTrait());
      }
      break;
    }
  }

  // If there are any modules that have gone out-of-date, prune out any modules
  // that depend on them.
  if (AnyOutOfDate) {
    // First, build back links in the module dependency graph.
    SmallVector<unsigned, 4> Stack;
    for (LoadedModulesMap::iterator LM = LoadedModules.begin(),
                                    LMEnd = LoadedModules.end();
         LM != LMEnd; ++LM) {
      unsigned ID = LM->first;

      // If this module is out-of-date, push it onto the stack.
      if (LM->second.File == 0)
        Stack.push_back(ID);

      for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) {
        unsigned DepID = LM->second.Dependencies[I];
        LoadedModulesMap::iterator Known = LoadedModules.find(DepID);
        if (Known == LoadedModules.end() || !Known->second.File) {
          // The dependency was out-of-date, so mark us as out of date.
          // This is just an optimization.
          if (LM->second.File)
            Stack.push_back(ID);

          LM->second.File = 0;
          continue;
        }

        // Record this reverse dependency.
        Known->second.ImportedBy.push_back(ID);
      }
    }

    // Second, walk the back links from out-of-date modules to those modules
    // that depend on them, making those modules out-of-date as well.
    while (!Stack.empty()) {
      unsigned ID = Stack.back();
      Stack.pop_back();

      LoadedModuleInfo &Info = LoadedModules[ID];
      for (unsigned I = 0, N = Info.ImportedBy.size(); I != N; ++I) {
        unsigned FromID = Info.ImportedBy[I];
        if (LoadedModules[FromID].File) {
          LoadedModules[FromID].File = 0;
          Stack.push_back(FromID);
        }
      }
    }
  }

  // Allocate the vector containing information about all of the modules.
  Modules.resize(LargestID + 1);
  for (LoadedModulesMap::iterator LM = LoadedModules.begin(),
                                  LMEnd = LoadedModules.end();
       LM != LMEnd; ++LM) {
    if (!LM->second.File)
      continue;
    
    Modules[LM->first].File = LM->second.File;

    // Resolve dependencies. Drop any we can't resolve due to out-of-date
    // module files.
    for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) {
      unsigned DepID = LM->second.Dependencies[I];
      LoadedModulesMap::iterator Known = LoadedModules.find(DepID);
      if (Known == LoadedModules.end() || !Known->second.File)
        continue;

      Modules[LM->first].Dependencies.push_back(Known->second.File);
    }
  }
}
Пример #11
0
LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
                                           CXDiagnosticSetImpl &Diags,
                                           CXLoadedDiagnosticSetImpl &TopDiags){

  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
    reportInvalidFile("malformed diagnostic block");
    return Failure;
  }
  
  OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
  RecordData Record;
  
  while (true) {
    unsigned blockOrCode = 0;
    StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
                                               blockOrCode);
    switch (Res) {
      case Read_EndOfStream:
        llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
      case Read_Failure:
        return Failure;
      case Read_BlockBegin: {
        // The only blocks we care about are subdiagnostics.
        if (blockOrCode != serialized_diags::BLOCK_DIAG) {
          if (!Stream.SkipBlock()) {
            reportInvalidFile("Invalid subblock in Diagnostics block");
            return Failure;
          }
        } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
                                       TopDiags)) {
          return Failure;
        }

        continue;
      }
      case Read_BlockEnd:
        Diags.appendDiagnostic(D.take());        
        return Success;
      case Read_Record:
        break;
    }
    
    // Read the record.
    Record.clear();
    StringRef Blob;
    unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob);
    
    if (recID < serialized_diags::RECORD_FIRST ||
        recID > serialized_diags::RECORD_LAST)
      continue;
    
    switch ((serialized_diags::RecordIDs)recID) {  
      case serialized_diags::RECORD_VERSION:
        continue;
      case serialized_diags::RECORD_CATEGORY:
        if (readString(TopDiags, TopDiags.Categories, "category", Record,
                       Blob, /* allowEmptyString */ true))
          return Failure;
        continue;
      
      case serialized_diags::RECORD_DIAG_FLAG:
        if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
                       Blob))
          return Failure;
        continue;
        
      case serialized_diags::RECORD_FILENAME: {
        if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
                       Blob))
          return Failure;

        if (Record.size() < 3) {
          reportInvalidFile("Invalid file entry");
          return Failure;
        }
        
        const FileEntry *FE =
          TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
                                            /* size */ Record[1],
                                            /* time */ Record[2]);
        
        TopDiags.Files[Record[0]] = FE;
        continue;
      }

      case serialized_diags::RECORD_SOURCE_RANGE: {
        CXSourceRange SR;
        if (readRange(TopDiags, Record, 0, SR))
          return Failure;
        D->Ranges.push_back(SR);
        continue;
      }
      
      case serialized_diags::RECORD_FIXIT: {
        CXSourceRange SR;
        if (readRange(TopDiags, Record, 0, SR))
          return Failure;
        llvm::StringRef RetStr;
        if (readString(TopDiags, RetStr, "FIXIT", Record, Blob,
                       /* allowEmptyString */ true))
          return Failure;
        D->FixIts.push_back(std::make_pair(SR, createCXString(RetStr, false)));
        continue;
      }
        
      case serialized_diags::RECORD_DIAG: {
        D->severity = Record[0];
        unsigned offset = 1;
        if (readLocation(TopDiags, Record, offset, D->DiagLoc))
          return Failure;
        D->category = Record[offset++];
        unsigned diagFlag = Record[offset++];
        D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
        D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
        D->Spelling = TopDiags.makeString(Blob);
        continue;
      }
    }
  }
}