diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:49:41 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:49:41 +0000 | 
| commit | 45b533945f0851ec234ca846e1af5ee1e4df0b6e (patch) | |
| tree | 0a5b74c0b9ca73aded34df95c91fcaf3815230d8 /lib/Serialization/ASTWriter.cpp | |
| parent | 7e86edd64bfae4e324224452e4ea879b3371a4bd (diff) | |
Notes
Diffstat (limited to 'lib/Serialization/ASTWriter.cpp')
| -rw-r--r-- | lib/Serialization/ASTWriter.cpp | 1373 | 
1 files changed, 667 insertions, 706 deletions
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 8b6863822c69a..128935c5c73bd 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1,4 +1,4 @@ -//===--- ASTWriter.cpp - AST File Writer ----------------------------------===// +//===--- ASTWriter.cpp - AST File Writer ------------------------*- C++ -*-===//  //  //                     The LLVM Compiler Infrastructure  // @@ -12,7 +12,10 @@  //===----------------------------------------------------------------------===//  #include "clang/Serialization/ASTWriter.h" +#include "clang/Serialization/ModuleFileExtension.h"  #include "ASTCommon.h" +#include "ASTReaderInternals.h" +#include "MultiOnDiskHashTable.h"  #include "clang/AST/ASTContext.h"  #include "clang/AST/Decl.h"  #include "clang/AST/DeclContextInternals.h" @@ -41,6 +44,7 @@  #include "clang/Sema/IdentifierResolver.h"  #include "clang/Sema/Sema.h"  #include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/SerializationDiagnostic.h"  #include "llvm/ADT/APFloat.h"  #include "llvm/ADT/APInt.h"  #include "llvm/ADT/Hashing.h" @@ -56,6 +60,7 @@  #include <cstdio>  #include <string.h>  #include <utility> +  using namespace clang;  using namespace clang::serialization; @@ -98,7 +103,7 @@ namespace {  #define ABSTRACT_TYPE(Class, Base)  #include "clang/AST/TypeNodes.def"    }; -} +} // end anonymous namespace  void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) {    llvm_unreachable("Built-in types are never serialized"); @@ -277,7 +282,7 @@ void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {  void ASTTypeWriter::VisitAutoType(const AutoType *T) {    Writer.AddTypeRef(T->getDeducedType(), Record); -  Record.push_back(T->isDecltypeAuto()); +  Record.push_back((unsigned)T->getKeyword());    if (T->getDeducedType().isNull())      Record.push_back(T->isDependentType());    Code = TYPE_AUTO; @@ -329,9 +334,8 @@ ASTTypeWriter::VisitTemplateSpecializationType(    Record.push_back(T->isDependentType());    Writer.AddTemplateName(T->getTemplateName(), Record);    Record.push_back(T->getNumArgs()); -  for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); -         ArgI != ArgE; ++ArgI) -    Writer.AddTemplateArgument(*ArgI, Record); +  for (const auto &ArgI : *T) +    Writer.AddTemplateArgument(ArgI, Record);    Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :                      T->isCanonicalUnqualified() ? QualType()                                                  : T->getCanonicalTypeInternal(), @@ -381,9 +385,8 @@ ASTTypeWriter::VisitDependentTemplateSpecializationType(    Writer.AddNestedNameSpecifier(T->getQualifier(), Record);    Writer.AddIdentifierRef(T->getIdentifier(), Record);    Record.push_back(T->getNumArgs()); -  for (DependentTemplateSpecializationType::iterator -         I = T->begin(), E = T->end(); I != E; ++I) -    Writer.AddTemplateArgument(*I, Record); +  for (const auto &I : *T) +    Writer.AddTemplateArgument(I, Record);    Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION;  } @@ -462,7 +465,7 @@ public:    void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc);  }; -} +} // end anonymous namespace  void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {    // nothing to do @@ -875,15 +878,17 @@ void ASTWriter::WriteBlockInfoBlock() {    RECORD(METADATA);    RECORD(SIGNATURE);    RECORD(MODULE_NAME); +  RECORD(MODULE_DIRECTORY);    RECORD(MODULE_MAP_FILE);    RECORD(IMPORTS); -  RECORD(KNOWN_MODULE_FILES); -  RECORD(LANGUAGE_OPTIONS); -  RECORD(TARGET_OPTIONS);    RECORD(ORIGINAL_FILE);    RECORD(ORIGINAL_PCH_DIR);    RECORD(ORIGINAL_FILE_ID);    RECORD(INPUT_FILE_OFFSETS); + +  BLOCK(OPTIONS_BLOCK); +  RECORD(LANGUAGE_OPTIONS); +  RECORD(TARGET_OPTIONS);    RECORD(DIAGNOSTIC_OPTIONS);    RECORD(FILE_SYSTEM_OPTIONS);    RECORD(HEADER_SEARCH_OPTIONS); @@ -902,17 +907,17 @@ void ASTWriter::WriteBlockInfoBlock() {    RECORD(SPECIAL_TYPES);    RECORD(STATISTICS);    RECORD(TENTATIVE_DEFINITIONS); -  RECORD(UNUSED_FILESCOPED_DECLS);    RECORD(SELECTOR_OFFSETS);    RECORD(METHOD_POOL);    RECORD(PP_COUNTER_VALUE);    RECORD(SOURCE_LOCATION_OFFSETS);    RECORD(SOURCE_LOCATION_PRELOADS);    RECORD(EXT_VECTOR_DECLS); +  RECORD(UNUSED_FILESCOPED_DECLS);    RECORD(PPD_ENTITIES_OFFSETS); +  RECORD(VTABLE_USES);    RECORD(REFERENCED_SELECTOR_POOL);    RECORD(TU_UPDATE_LEXICAL); -  RECORD(LOCAL_REDECLARATIONS_MAP);    RECORD(SEMA_DECL_REFS);    RECORD(WEAK_UNDECLARED_IDENTIFIERS);    RECORD(PENDING_IMPLICIT_INSTANTIATIONS); @@ -928,17 +933,20 @@ void ASTWriter::WriteBlockInfoBlock() {    RECORD(OPENCL_EXTENSIONS);    RECORD(DELEGATING_CTORS);    RECORD(KNOWN_NAMESPACES); -  RECORD(UNDEFINED_BUT_USED);    RECORD(MODULE_OFFSET_MAP);    RECORD(SOURCE_MANAGER_LINE_TABLE);    RECORD(OBJC_CATEGORIES_MAP);    RECORD(FILE_SORTED_DECLS);    RECORD(IMPORTED_MODULES); -  RECORD(LOCAL_REDECLARATIONS);    RECORD(OBJC_CATEGORIES);    RECORD(MACRO_OFFSET); +  RECORD(INTERESTING_IDENTIFIERS); +  RECORD(UNDEFINED_BUT_USED);    RECORD(LATE_PARSED_TEMPLATE);    RECORD(OPTIMIZE_PRAGMA_OPTIONS); +  RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES); +  RECORD(CXX_CTOR_INITIALIZERS_OFFSETS); +  RECORD(DELETE_EXPRS_TO_ANALYZE);    // SourceManager Block.    BLOCK(SOURCE_MANAGER_BLOCK); @@ -955,6 +963,29 @@ void ASTWriter::WriteBlockInfoBlock() {    RECORD(PP_MODULE_MACRO);    RECORD(PP_TOKEN); +  // Submodule Block. +  BLOCK(SUBMODULE_BLOCK); +  RECORD(SUBMODULE_METADATA); +  RECORD(SUBMODULE_DEFINITION); +  RECORD(SUBMODULE_UMBRELLA_HEADER); +  RECORD(SUBMODULE_HEADER); +  RECORD(SUBMODULE_TOPHEADER); +  RECORD(SUBMODULE_UMBRELLA_DIR); +  RECORD(SUBMODULE_IMPORTS); +  RECORD(SUBMODULE_EXPORTS); +  RECORD(SUBMODULE_REQUIRES); +  RECORD(SUBMODULE_EXCLUDED_HEADER); +  RECORD(SUBMODULE_LINK_LIBRARY); +  RECORD(SUBMODULE_CONFIG_MACRO); +  RECORD(SUBMODULE_CONFLICT); +  RECORD(SUBMODULE_PRIVATE_HEADER); +  RECORD(SUBMODULE_TEXTUAL_HEADER); +  RECORD(SUBMODULE_PRIVATE_TEXTUAL_HEADER); + +  // Comments Block. +  BLOCK(COMMENTS_BLOCK); +  RECORD(COMMENTS_RAW_COMMENT); +    // Decls and Types block.    BLOCK(DECLTYPES_BLOCK);    RECORD(TYPE_EXT_QUAL); @@ -998,6 +1029,7 @@ void ASTWriter::WriteBlockInfoBlock() {    RECORD(TYPE_ATOMIC);    RECORD(TYPE_DECAYED);    RECORD(TYPE_ADJUSTED); +  RECORD(LOCAL_REDECLARATIONS);    RECORD(DECL_TYPEDEF);    RECORD(DECL_TYPEALIAS);    RECORD(DECL_ENUM); @@ -1062,7 +1094,11 @@ void ASTWriter::WriteBlockInfoBlock() {    RECORD(PPD_MACRO_EXPANSION);    RECORD(PPD_MACRO_DEFINITION);    RECORD(PPD_INCLUSION_DIRECTIVE); -   + +  // Decls and Types block. +  BLOCK(EXTENSION_BLOCK); +  RECORD(EXTENSION_METADATA); +  #undef RECORD  #undef BLOCK    Stream.ExitBlock(); @@ -1074,14 +1110,8 @@ void ASTWriter::WriteBlockInfoBlock() {  /// \return \c true if the path was changed.  static bool cleanPathForOutput(FileManager &FileMgr,                                 SmallVectorImpl<char> &Path) { -  bool Changed = false; - -  if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { -    llvm::sys::fs::make_absolute(Path); -    Changed = true; -  } - -  return Changed | FileMgr.removeDotPaths(Path); +  bool Changed = FileMgr.makeAbsolutePath(Path); +  return Changed | llvm::sys::path::remove_dots(Path);  }  /// \brief Adjusts the given filename to only write out the portion of the @@ -1140,69 +1170,78 @@ static ASTFileSignature getSignature() {  }  /// \brief Write the control block. -void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, -                                  StringRef isysroot, -                                  const std::string &OutputFile) { +uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP, +                                      ASTContext &Context, +                                      StringRef isysroot, +                                      const std::string &OutputFile) { +  ASTFileSignature Signature = 0; +    using namespace llvm;    Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);    RecordData Record;    // Metadata -  BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev(); +  auto *MetadataAbbrev = new BitCodeAbbrev();    MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA));    MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major    MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor    MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj.    MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min.    MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable +  MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Timestamps    MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors    MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag    unsigned MetadataAbbrevCode = Stream.EmitAbbrev(MetadataAbbrev); -  Record.push_back(METADATA); -  Record.push_back(VERSION_MAJOR); -  Record.push_back(VERSION_MINOR); -  Record.push_back(CLANG_VERSION_MAJOR); -  Record.push_back(CLANG_VERSION_MINOR);    assert((!WritingModule || isysroot.empty()) &&           "writing module as a relocatable PCH?"); -  Record.push_back(!isysroot.empty()); -  Record.push_back(ASTHasCompilerErrors); -  Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, -                            getClangFullRepositoryVersion()); - +  { +    RecordData::value_type Record[] = {METADATA, VERSION_MAJOR, VERSION_MINOR, +                                       CLANG_VERSION_MAJOR, CLANG_VERSION_MINOR, +                                       !isysroot.empty(), IncludeTimestamps, +                                       ASTHasCompilerErrors}; +    Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, +                              getClangFullRepositoryVersion()); +  }    if (WritingModule) {      // For implicit modules we output a signature that we can use to ensure      // duplicate module builds don't collide in the cache as their output order      // is non-deterministic.      // FIXME: Remove this when output is deterministic.      if (Context.getLangOpts().ImplicitModules) { -      Record.clear(); -      Record.push_back(getSignature()); +      Signature = getSignature(); +      RecordData::value_type Record[] = {Signature};        Stream.EmitRecord(SIGNATURE, Record);      }      // Module name -    BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +    auto *Abbrev = new BitCodeAbbrev();      Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name      unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); -    RecordData Record; -    Record.push_back(MODULE_NAME); +    RecordData::value_type Record[] = {MODULE_NAME};      Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name);    }    if (WritingModule && WritingModule->Directory) { -    // Module directory. -    BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); -    Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY)); -    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory -    unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); -    RecordData Record; -    Record.push_back(MODULE_DIRECTORY); -      SmallString<128> BaseDir(WritingModule->Directory->getName());      cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir); -    Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir); + +    // If the home of the module is the current working directory, then we +    // want to pick up the cwd of the build process loading the module, not +    // our cwd, when we load this module. +    if (!PP.getHeaderSearchInfo() +             .getHeaderSearchOpts() +             .ModuleMapFileHomeIsCwd || +        WritingModule->Directory->getName() != StringRef(".")) { +      // Module directory. +      auto *Abbrev = new BitCodeAbbrev(); +      Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY)); +      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory +      unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + +      RecordData::value_type Record[] = {MODULE_DIRECTORY}; +      Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir); +    }      // Write out all other paths relative to the base directory if possible.      BaseDirectory.assign(BaseDir.begin(), BaseDir.end()); @@ -1246,22 +1285,16 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,        Record.push_back((unsigned)M->Kind); // FIXME: Stable encoding        AddSourceLocation(M->ImportLoc, Record);        Record.push_back(M->File->getSize()); -      Record.push_back(M->File->getModificationTime()); +      Record.push_back(getTimestampForOutput(M->File));        Record.push_back(M->Signature);        AddPath(M->FileName, Record);      }      Stream.EmitRecord(IMPORTS, Record); - -    // Also emit a list of known module files that were not imported, -    // but are made available by this module. -    // FIXME: Should we also include a signature here? -    Record.clear(); -    for (auto *E : Mgr.getAdditionalKnownModuleFiles()) -      AddPath(E->getName(), Record); -    if (!Record.empty()) -      Stream.EmitRecord(KNOWN_MODULE_FILES, Record);    } +  // Write the options block. +  Stream.EnterSubblock(OPTIONS_BLOCK_ID, 4); +    // Language options.    Record.clear();    const LangOptions &LangOpts = Context.getLangOpts(); @@ -1285,11 +1318,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,    // Comment options.    Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size()); -  for (CommentOptions::BlockCommandNamesTy::const_iterator -           I = LangOpts.CommentOpts.BlockCommandNames.begin(), -           IEnd = LangOpts.CommentOpts.BlockCommandNames.end(); -       I != IEnd; ++I) { -    AddString(*I, Record); +  for (const auto &I : LangOpts.CommentOpts.BlockCommandNames) { +    AddString(I, Record);    }    Record.push_back(LangOpts.CommentOpts.ParseAllComments); @@ -1332,8 +1362,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,    // File system options.    Record.clear(); -  const FileSystemOptions &FSOpts -    = Context.getSourceManager().getFileManager().getFileSystemOptions(); +  const FileSystemOptions &FSOpts = +      Context.getSourceManager().getFileManager().getFileSystemOpts();    AddString(FSOpts.WorkingDir, Record);    Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record); @@ -1401,10 +1431,13 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,    Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary));    Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record); +  // Leave the options block. +  Stream.ExitBlock(); +    // Original file name and file ID    SourceManager &SM = Context.getSourceManager();    if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { -    BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev(); +    auto *FileAbbrev = new BitCodeAbbrev();      FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE));      FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID      FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name @@ -1422,18 +1455,17 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,    // Original PCH directory    if (!OutputFile.empty() && OutputFile != "-") { -    BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +    auto *Abbrev = new BitCodeAbbrev();      Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name      unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);      SmallString<128> OutputPath(OutputFile); -    llvm::sys::fs::make_absolute(OutputPath); +    SM.getFileManager().makeAbsolutePath(OutputPath);      StringRef origDir = llvm::sys::path::parent_path(OutputPath); -    RecordData Record; -    Record.push_back(ORIGINAL_PCH_DIR); +    RecordData::value_type Record[] = {ORIGINAL_PCH_DIR};      Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);    } @@ -1441,6 +1473,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,                    PP.getHeaderSearchInfo().getHeaderSearchOpts(),                    PP.getLangOpts().Modules);    Stream.ExitBlock(); +  return Signature;  }  namespace  { @@ -1448,24 +1481,25 @@ namespace  {    struct InputFileEntry {      const FileEntry *File;      bool IsSystemFile; +    bool IsTransient;      bool BufferOverridden;    }; -} +} // end anonymous namespace  void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,                                  HeaderSearchOptions &HSOpts,                                  bool Modules) {    using namespace llvm;    Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); -  RecordData Record; -   +    // Create input-file abbreviation. -  BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev(); +  auto *IFAbbrev = new BitCodeAbbrev();    IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE));    IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID    IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size    IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time    IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden +  IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient    IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name    unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev); @@ -1487,6 +1521,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,      InputFileEntry Entry;      Entry.File = Cache->OrigEntry;      Entry.IsSystemFile = Cache->IsSystemFile; +    Entry.IsTransient = Cache->IsTransient;      Entry.BufferOverridden = Cache->BufferOverridden;      if (Cache->IsSystemFile)        SortedFiles.push_back(Entry); @@ -1497,10 +1532,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,    unsigned UserFilesNum = 0;    // Write out all of the input files.    std::vector<uint64_t> InputFileOffsets; -  for (std::deque<InputFileEntry>::iterator -         I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) { -    const InputFileEntry &Entry = *I; - +  for (const auto &Entry : SortedFiles) {      uint32_t &InputFileID = InputFileIDs[Entry.File];      if (InputFileID != 0)        continue; // already recorded this file. @@ -1513,16 +1545,15 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,      if (!Entry.IsSystemFile)        ++UserFilesNum; -    Record.clear(); -    Record.push_back(INPUT_FILE); -    Record.push_back(InputFileOffsets.size()); -      // Emit size/modification time for this file. -    Record.push_back(Entry.File->getSize()); -    Record.push_back(Entry.File->getModificationTime()); - -    // Whether this file was overridden. -    Record.push_back(Entry.BufferOverridden); +    // And whether this file was overridden. +    RecordData::value_type Record[] = { +        INPUT_FILE, +        InputFileOffsets.size(), +        (uint64_t)Entry.File->getSize(), +        (uint64_t)getTimestampForOutput(Entry.File), +        Entry.BufferOverridden, +        Entry.IsTransient};      EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());    } @@ -1530,7 +1561,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,    Stream.ExitBlock();    // Create input file offsets abbreviation. -  BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev(); +  auto *OffsetsAbbrev = new BitCodeAbbrev();    OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));    OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files    OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # non-system @@ -1539,10 +1570,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,    unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);    // Write input file offsets. -  Record.clear(); -  Record.push_back(INPUT_FILE_OFFSETS); -  Record.push_back(InputFileOffsets.size()); -  Record.push_back(UserFilesNum); +  RecordData::value_type Record[] = {INPUT_FILE_OFFSETS, +                                     InputFileOffsets.size(), UserFilesNum};    Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, bytes(InputFileOffsets));  } @@ -1554,7 +1583,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,  /// file.  static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location @@ -1572,7 +1602,8 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {  /// buffer.  static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location @@ -1586,7 +1617,8 @@ static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {  /// buffer's blob.  static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_BLOB));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob    return Stream.EmitAbbrev(Abbrev); @@ -1596,7 +1628,8 @@ static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) {  /// expansion.  static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) {    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_ENTRY));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location @@ -1631,27 +1664,25 @@ namespace {      typedef unsigned hash_value_type;      typedef unsigned offset_type; -    static hash_value_type ComputeHash(key_type_ref key) { +    hash_value_type ComputeHash(key_type_ref key) {        // The hash is based only on size/time of the file, so that the reader can        // match even when symlinking or excess path elements ("foo/../", "../")        // change the form of the name. However, complete path is still the key. -      // -      // FIXME: Using the mtime here will cause problems for explicit module -      // imports.        return llvm::hash_combine(key.FE->getSize(), -                                key.FE->getModificationTime()); +                                Writer.getTimestampForOutput(key.FE));      }      std::pair<unsigned,unsigned>      EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {        using namespace llvm::support; -      endian::Writer<little> Writer(Out); +      endian::Writer<little> LE(Out);        unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8; -      Writer.write<uint16_t>(KeyLen); +      LE.write<uint16_t>(KeyLen);        unsigned DataLen = 1 + 2 + 4 + 4; -      if (Data.isModuleHeader) -        DataLen += 4; -      Writer.write<uint8_t>(DataLen); +      for (auto ModInfo : HS.getModuleMap().findAllModulesForHeader(key.FE)) +        if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) +          DataLen += 4; +      LE.write<uint8_t>(DataLen);        return std::make_pair(KeyLen, DataLen);      } @@ -1660,7 +1691,7 @@ namespace {        endian::Writer<little> LE(Out);        LE.write<uint64_t>(key.FE->getSize());        KeyLen -= 8; -      LE.write<uint64_t>(key.FE->getModificationTime()); +      LE.write<uint64_t>(Writer.getTimestampForOutput(key.FE));        KeyLen -= 8;        Out.write(key.Filename, KeyLen);      } @@ -1671,11 +1702,9 @@ namespace {        endian::Writer<little> LE(Out);        uint64_t Start = Out.tell(); (void)Start; -      unsigned char Flags = (Data.HeaderRole << 6) -                          | (Data.isImport << 5) -                          | (Data.isPragmaOnce << 4) -                          | (Data.DirInfo << 2) -                          | (Data.Resolved << 1) +      unsigned char Flags = (Data.isImport << 4) +                          | (Data.isPragmaOnce << 3) +                          | (Data.DirInfo << 1)                            | Data.IndexHeaderMapHeader;        LE.write<uint8_t>(Flags);        LE.write<uint16_t>(Data.NumIncludes); @@ -1702,9 +1731,15 @@ namespace {        }        LE.write<uint32_t>(Offset); -      if (Data.isModuleHeader) { -        Module *Mod = HS.findModuleForHeader(key.FE).getModule(); -        LE.write<uint32_t>(Writer.getExistingSubmoduleID(Mod)); +      // FIXME: If the header is excluded, we should write out some +      // record of that fact. +      for (auto ModInfo : HS.getModuleMap().findAllModulesForHeader(key.FE)) { +        if (uint32_t ModID = +                Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) { +          uint32_t Value = (ModID << 2) | (unsigned)ModInfo.getRole(); +          assert((Value >> 2) == ModID && "overflow in header module info"); +          LE.write<uint32_t>(Value); +        }        }        assert(Out.tell() - Start == DataLen && "Wrong data length"); @@ -1734,12 +1769,15 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {      if (!File)        continue; -    // Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo -    // from the external source if it was not provided already. -    HeaderFileInfo HFI; -    if (!HS.tryGetFileInfo(File, HFI) || -        (HFI.External && Chain) || -        (HFI.isModuleHeader && !HFI.isCompilingModuleHeader)) +    // Get the file info. This will load info from the external source if +    // necessary. Skip emitting this file if we have no information on it +    // as a header file (in which case HFI will be null) or if it hasn't +    // changed since it was loaded. Also skip it if it's for a modular header +    // from a different module; in that case, we rely on the module(s) +    // containing the header to provide this information. +    const HeaderFileInfo *HFI = +        HS.getExistingFileInfo(File, /*WantExternal*/!Chain); +    if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader))        continue;      // Massage the file path into an appropriate form. @@ -1753,7 +1791,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {      }      HeaderFileInfoTrait::key_type key = { File, Filename }; -    Generator.insert(key, HFI, GeneratorTrait); +    Generator.insert(key, *HFI, GeneratorTrait);      ++NumHeaderSearchEntries;    } @@ -1770,7 +1808,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {    // Create a blob abbreviation    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); @@ -1779,11 +1818,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {    unsigned TableAbbrev = Stream.EmitAbbrev(Abbrev);    // Write the header search table -  RecordData Record; -  Record.push_back(HEADER_SEARCH_TABLE); -  Record.push_back(BucketOffset); -  Record.push_back(NumHeaderSearchEntries); -  Record.push_back(TableData.size()); +  RecordData::value_type Record[] = {HEADER_SEARCH_TABLE, BucketOffset, +                                     NumHeaderSearchEntries, TableData.size()};    TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end());    Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData); @@ -1871,9 +1907,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,          Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record); -        if (Content->BufferOverridden) { -          Record.clear(); -          Record.push_back(SM_SLOC_BUFFER_BLOB); +        if (Content->BufferOverridden || Content->IsTransient) { +          RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB};            const llvm::MemoryBuffer *Buffer              = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());            Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, @@ -1892,8 +1927,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,          const char *Name = Buffer->getBufferIdentifier();          Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,                                    StringRef(Name, strlen(Name) + 1)); -        Record.clear(); -        Record.push_back(SM_SLOC_BUFFER_BLOB); +        RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB};          Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,                                    StringRef(Buffer->getBufferStart(),                                                    Buffer->getBufferSize() + 1)); @@ -1927,19 +1961,20 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,    // Write the source-location offsets table into the AST block. This    // table is used for lazily loading source-location information.    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets    unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); - -  Record.clear(); -  Record.push_back(SOURCE_LOCATION_OFFSETS); -  Record.push_back(SLocEntryOffsets.size()); -  Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy -  Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, bytes(SLocEntryOffsets)); - +  { +    RecordData::value_type Record[] = { +        SOURCE_LOCATION_OFFSETS, SLocEntryOffsets.size(), +        SourceMgr.getNextLocalOffset() - 1 /* skip dummy */}; +    Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, +                              bytes(SLocEntryOffsets)); +  }    // Write the source location entry preloads array, telling the AST    // reader which source locations entries it should load eagerly.    Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs); @@ -1950,33 +1985,40 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,      LineTableInfo &LineTable = SourceMgr.getLineTable();      Record.clear(); -    // Emit the file names. -    Record.push_back(LineTable.getNumFilenames()); -    for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) -      AddPath(LineTable.getFilename(I), Record); + +    // Emit the needed file names. +    llvm::DenseMap<int, int> FilenameMap; +    for (const auto &L : LineTable) { +      if (L.first.ID < 0) +        continue; +      for (auto &LE : L.second) { +        if (FilenameMap.insert(std::make_pair(LE.FilenameID, +                                              FilenameMap.size())).second) +          AddPath(LineTable.getFilename(LE.FilenameID), Record); +      } +    } +    Record.push_back(0);      // Emit the line entries -    for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end(); -         L != LEnd; ++L) { +    for (const auto &L : LineTable) {        // Only emit entries for local files. -      if (L->first.ID < 0) +      if (L.first.ID < 0)          continue;        // Emit the file ID -      Record.push_back(L->first.ID); +      Record.push_back(L.first.ID);        // Emit the line entries -      Record.push_back(L->second.size()); -      for (std::vector<LineEntry>::iterator LE = L->second.begin(), -                                         LEEnd = L->second.end(); -           LE != LEEnd; ++LE) { -        Record.push_back(LE->FileOffset); -        Record.push_back(LE->LineNo); -        Record.push_back(LE->FilenameID); -        Record.push_back((unsigned)LE->FileKind); -        Record.push_back(LE->IncludeOffset); +      Record.push_back(L.second.size()); +      for (const auto &LE : L.second) { +        Record.push_back(LE.FileOffset); +        Record.push_back(LE.LineNo); +        Record.push_back(FilenameMap[LE.FilenameID]); +        Record.push_back((unsigned)LE.FileKind); +        Record.push_back(LE.IncludeOffset);        }      } +      Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record);    }  } @@ -2015,19 +2057,17 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {    // If the preprocessor __COUNTER__ value has been bumped, remember it.    if (PP.getCounterValue() != 0) { -    Record.push_back(PP.getCounterValue()); +    RecordData::value_type Record[] = {PP.getCounterValue()};      Stream.EmitRecord(PP_COUNTER_VALUE, Record); -    Record.clear();    }    // Enter the preprocessor block.    Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);    // If the AST file contains __DATE__ or __TIME__ emit a warning about this. -  // FIXME: use diagnostics subsystem for localization etc. +  // FIXME: Include a location for the use, and say which one was used.    if (PP.SawDateOrTime()) -    fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n"); - +    PP.Diag(SourceLocation(), diag::warn_module_uses_date_time) << IsModule;    // Loop over all the macro directives that are live at the end of the file,    // emitting each to the PP section. @@ -2177,6 +2217,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {    // Write the offsets table for macro IDs.    using namespace llvm; +    auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros @@ -2184,12 +2225,11 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));    unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(Abbrev); -  Record.clear(); -  Record.push_back(MACRO_OFFSET); -  Record.push_back(MacroOffsets.size()); -  Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS); -  Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, -                            bytes(MacroOffsets)); +  { +    RecordData::value_type Record[] = {MACRO_OFFSET, MacroOffsets.size(), +                                       FirstMacroID - NUM_PREDEF_MACRO_IDS}; +    Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, bytes(MacroOffsets)); +  }  }  void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { @@ -2208,7 +2248,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {    // Set up the abbreviation for     unsigned InclusionAbbrev = 0;    { -    BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +    auto *Abbrev = new BitCodeAbbrev();      Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes @@ -2232,7 +2272,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {      PreprocessedEntityOffsets.push_back(          PPEntityOffset((*E)->getSourceRange(), Stream.GetCurrentBitNo())); -    if (MacroDefinitionRecord *MD = dyn_cast<MacroDefinitionRecord>(*E)) { +    if (auto *MD = dyn_cast<MacroDefinitionRecord>(*E)) {        // Record this macro definition's ID.        MacroDefinitions[MD] = NextPreprocessorEntityID; @@ -2241,7 +2281,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {        continue;      } -    if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) { +    if (auto *ME = dyn_cast<MacroExpansion>(*E)) {        Record.push_back(ME->isBuiltinMacro());        if (ME->isBuiltinMacro())          AddIdentifierRef(ME->getName(), Record); @@ -2251,7 +2291,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {        continue;      } -    if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) { +    if (auto *ID = dyn_cast<InclusionDirective>(*E)) {        Record.push_back(PPD_INCLUSION_DIRECTIVE);        Record.push_back(ID->getFileName().size());        Record.push_back(ID->wasInQuotes()); @@ -2277,46 +2317,50 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {      // Write the offsets table for identifier IDs.      using namespace llvm; -    BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +    auto *Abbrev = new BitCodeAbbrev();      Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(Abbrev); -    Record.clear(); -    Record.push_back(PPD_ENTITIES_OFFSETS); -    Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS); +    RecordData::value_type Record[] = {PPD_ENTITIES_OFFSETS, +                                       FirstPreprocessorEntityID - +                                           NUM_PREDEF_PP_ENTITY_IDS};      Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record,                                bytes(PreprocessedEntityOffsets));    }  } -unsigned ASTWriter::getSubmoduleID(Module *Mod) { +unsigned ASTWriter::getLocalOrImportedSubmoduleID(Module *Mod) { +  if (!Mod) +    return 0; +    llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod);    if (Known != SubmoduleIDs.end())      return Known->second; -   -  return SubmoduleIDs[Mod] = NextSubmoduleID++; -} -unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const { -  if (!Mod) +  if (Mod->getTopLevelModule() != WritingModule)      return 0; -  llvm::DenseMap<Module *, unsigned>::const_iterator -    Known = SubmoduleIDs.find(Mod); -  if (Known != SubmoduleIDs.end()) -    return Known->second; +  return SubmoduleIDs[Mod] = NextSubmoduleID++; +} -  return 0; +unsigned ASTWriter::getSubmoduleID(Module *Mod) { +  // FIXME: This can easily happen, if we have a reference to a submodule that +  // did not result in us loading a module file for that submodule. For +  // instance, a cross-top-level-module 'conflict' declaration will hit this. +  unsigned ID = getLocalOrImportedSubmoduleID(Mod); +  assert((ID || !Mod) && +         "asked for module ID for non-local, non-imported module"); +  return ID;  }  /// \brief Compute the number of modules within the given tree (including the  /// given module).  static unsigned getNumberOfModules(Module *Mod) {    unsigned ChildModules = 0; -  for (Module::submodule_iterator Sub = Mod->submodule_begin(), -                               SubEnd = Mod->submodule_end(); +  for (auto Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end();         Sub != SubEnd; ++Sub)      ChildModules += getNumberOfModules(*Sub); @@ -2329,7 +2373,8 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {    // Write the abbreviations needed for the submodules block.    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent @@ -2408,9 +2453,9 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {    unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev);    // Write the submodule metadata block. -  RecordData Record; -  Record.push_back(getNumberOfModules(WritingModule)); -  Record.push_back(FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS); +  RecordData::value_type Record[] = {getNumberOfModules(WritingModule), +                                     FirstSubmoduleID - +                                         NUM_PREDEF_SUBMODULE_IDS};    Stream.EmitRecord(SUBMODULE_METADATA, Record);    // Write all of the submodules. @@ -2420,46 +2465,37 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {      Module *Mod = Q.front();      Q.pop();      unsigned ID = getSubmoduleID(Mod); -     -    // Emit the definition of the block. -    Record.clear(); -    Record.push_back(SUBMODULE_DEFINITION); -    Record.push_back(ID); + +    uint64_t ParentID = 0;      if (Mod->Parent) {        assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?"); -      Record.push_back(SubmoduleIDs[Mod->Parent]); -    } else { -      Record.push_back(0); +      ParentID = SubmoduleIDs[Mod->Parent];      } -    Record.push_back(Mod->IsFramework); -    Record.push_back(Mod->IsExplicit); -    Record.push_back(Mod->IsSystem); -    Record.push_back(Mod->IsExternC); -    Record.push_back(Mod->InferSubmodules); -    Record.push_back(Mod->InferExplicitSubmodules); -    Record.push_back(Mod->InferExportWildcard); -    Record.push_back(Mod->ConfigMacrosExhaustive); -    Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); -     + +    // Emit the definition of the block. +    { +      RecordData::value_type Record[] = { +          SUBMODULE_DEFINITION, ID, ParentID, Mod->IsFramework, Mod->IsExplicit, +          Mod->IsSystem, Mod->IsExternC, Mod->InferSubmodules, +          Mod->InferExplicitSubmodules, Mod->InferExportWildcard, +          Mod->ConfigMacrosExhaustive}; +      Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); +    } +      // Emit the requirements. -    for (unsigned I = 0, N = Mod->Requirements.size(); I != N; ++I) { -      Record.clear(); -      Record.push_back(SUBMODULE_REQUIRES); -      Record.push_back(Mod->Requirements[I].second); -      Stream.EmitRecordWithBlob(RequiresAbbrev, Record, -                                Mod->Requirements[I].first); +    for (const auto &R : Mod->Requirements) { +      RecordData::value_type Record[] = {SUBMODULE_REQUIRES, R.second}; +      Stream.EmitRecordWithBlob(RequiresAbbrev, Record, R.first);      }      // Emit the umbrella header, if there is one.      if (auto UmbrellaHeader = Mod->getUmbrellaHeader()) { -      Record.clear(); -      Record.push_back(SUBMODULE_UMBRELLA_HEADER); +      RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_HEADER};        Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record,                                  UmbrellaHeader.NameAsWritten);      } else if (auto UmbrellaDir = Mod->getUmbrellaDir()) { -      Record.clear(); -      Record.push_back(SUBMODULE_UMBRELLA_DIR); -      Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record,  +      RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_DIR}; +      Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record,                                  UmbrellaDir.NameAsWritten);      } @@ -2477,8 +2513,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {        {SUBMODULE_EXCLUDED_HEADER, ExcludedHeaderAbbrev, Module::HK_Excluded}      };      for (auto &HL : HeaderLists) { -      Record.clear(); -      Record.push_back(HL.RecordKind); +      RecordData::value_type Record[] = {HL.RecordKind};        for (auto &H : Mod->Headers[HL.HeaderKind])          Stream.EmitRecordWithBlob(HL.Abbrev, Record, H.NameAsWritten);      } @@ -2486,35 +2521,27 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {      // Emit the top headers.      {        auto TopHeaders = Mod->getTopHeaders(PP->getFileManager()); -      Record.clear(); -      Record.push_back(SUBMODULE_TOPHEADER); +      RecordData::value_type Record[] = {SUBMODULE_TOPHEADER};        for (auto *H : TopHeaders)          Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, H->getName());      }      // Emit the imports.       if (!Mod->Imports.empty()) { -      Record.clear(); -      for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) { -        unsigned ImportedID = getSubmoduleID(Mod->Imports[I]); -        assert(ImportedID && "Unknown submodule!"); -        Record.push_back(ImportedID); -      } +      RecordData Record; +      for (auto *I : Mod->Imports) +        Record.push_back(getSubmoduleID(I));        Stream.EmitRecord(SUBMODULE_IMPORTS, Record);      }      // Emit the exports.       if (!Mod->Exports.empty()) { -      Record.clear(); -      for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) { -        if (Module *Exported = Mod->Exports[I].getPointer()) { -          unsigned ExportedID = getSubmoduleID(Exported); -          Record.push_back(ExportedID); -        } else { -          Record.push_back(0); -        } -         -        Record.push_back(Mod->Exports[I].getInt()); +      RecordData Record; +      for (const auto &E : Mod->Exports) { +        // FIXME: This may fail; we don't require that all exported modules +        // are local or imported. +        Record.push_back(getSubmoduleID(E.getPointer())); +        Record.push_back(E.getInt());        }        Stream.EmitRecord(SUBMODULE_EXPORTS, Record);      } @@ -2524,45 +2551,34 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {      // module itself.      // Emit the link libraries. -    for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) { -      Record.clear(); -      Record.push_back(SUBMODULE_LINK_LIBRARY); -      Record.push_back(Mod->LinkLibraries[I].IsFramework); -      Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record, -                                Mod->LinkLibraries[I].Library); +    for (const auto &LL : Mod->LinkLibraries) { +      RecordData::value_type Record[] = {SUBMODULE_LINK_LIBRARY, +                                         LL.IsFramework}; +      Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record, LL.Library);      }      // Emit the conflicts. -    for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) { -      Record.clear(); -      Record.push_back(SUBMODULE_CONFLICT); -      unsigned OtherID = getSubmoduleID(Mod->Conflicts[I].Other); -      assert(OtherID && "Unknown submodule!"); -      Record.push_back(OtherID); -      Stream.EmitRecordWithBlob(ConflictAbbrev, Record, -                                Mod->Conflicts[I].Message); +    for (const auto &C : Mod->Conflicts) { +      // FIXME: This may fail; we don't require that all conflicting modules +      // are local or imported. +      RecordData::value_type Record[] = {SUBMODULE_CONFLICT, +                                         getSubmoduleID(C.Other)}; +      Stream.EmitRecordWithBlob(ConflictAbbrev, Record, C.Message);      }      // Emit the configuration macros. -    for (unsigned I = 0, N =  Mod->ConfigMacros.size(); I != N; ++I) { -      Record.clear(); -      Record.push_back(SUBMODULE_CONFIG_MACRO); -      Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record, -                                Mod->ConfigMacros[I]); +    for (const auto &CM : Mod->ConfigMacros) { +      RecordData::value_type Record[] = {SUBMODULE_CONFIG_MACRO}; +      Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record, CM);      }      // Queue up the submodules of this module. -    for (Module::submodule_iterator Sub = Mod->submodule_begin(), -                                 SubEnd = Mod->submodule_end(); -         Sub != SubEnd; ++Sub) -      Q.push(*Sub); +    for (auto *M : Mod->submodules()) +      Q.push(M);    }    Stream.ExitBlock(); -  // FIXME: This can easily happen, if we have a reference to a submodule that -  // did not result in us loading a module file for that submodule. For -  // instance, a cross-top-level-module 'conflict' declaration will hit this.    assert((NextSubmoduleID - FirstSubmoduleID ==            getNumberOfModules(WritingModule)) &&           "Wrong # of submodules; found a reference to a non-local, " @@ -2614,11 +2630,10 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,      if (DiagStateID == 0) {        DiagStateID = ++CurrID; -      for (DiagnosticsEngine::DiagState::const_iterator -             I = point.State->begin(), E = point.State->end(); I != E; ++I) { -        if (I->second.isPragma()) { -          Record.push_back(I->first); -          Record.push_back((unsigned)I->second.getSeverity()); +      for (const auto &I : *(point.State)) { +        if (I.second.isPragma()) { +          Record.push_back(I.first); +          Record.push_back((unsigned)I.second.getSeverity());          }        }        Record.push_back(-1); // mark the end of the diag/map pairs for this @@ -2634,21 +2649,18 @@ void ASTWriter::WriteCXXCtorInitializersOffsets() {    if (CXXCtorInitializersOffsets.empty())      return; -  RecordData Record; -    // Create a blob abbreviation for the C++ ctor initializer offsets.    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(CXX_CTOR_INITIALIZERS_OFFSETS));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));    unsigned CtorInitializersOffsetAbbrev = Stream.EmitAbbrev(Abbrev);    // Write the base specifier offsets table. -  Record.clear(); -  Record.push_back(CXX_CTOR_INITIALIZERS_OFFSETS); -  Record.push_back(CXXCtorInitializersOffsets.size()); +  RecordData::value_type Record[] = {CXX_CTOR_INITIALIZERS_OFFSETS, +                                     CXXCtorInitializersOffsets.size()};    Stream.EmitRecordWithBlob(CtorInitializersOffsetAbbrev, Record,                              bytes(CXXCtorInitializersOffsets));  } @@ -2657,21 +2669,18 @@ void ASTWriter::WriteCXXBaseSpecifiersOffsets() {    if (CXXBaseSpecifiersOffsets.empty())      return; -  RecordData Record; -    // Create a blob abbreviation for the C++ base specifiers offsets.    using namespace llvm; -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));    unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);    // Write the base specifier offsets table. -  Record.clear(); -  Record.push_back(CXX_BASE_SPECIFIER_OFFSETS); -  Record.push_back(CXXBaseSpecifiersOffsets.size()); +  RecordData::value_type Record[] = {CXX_BASE_SPECIFIER_OFFSETS, +                                     CXXBaseSpecifiersOffsets.size()};    Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record,                              bytes(CXXBaseSpecifiersOffsets));  } @@ -2742,33 +2751,34 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,      return 0;    uint64_t Offset = Stream.GetCurrentBitNo(); -  RecordData Record; -  Record.push_back(DECL_CONTEXT_LEXICAL); -  SmallVector<KindDeclIDPair, 64> Decls; -  for (const auto *D : DC->decls()) -    Decls.push_back(std::make_pair(D->getKind(), GetDeclRef(D))); +  SmallVector<uint32_t, 128> KindDeclPairs; +  for (const auto *D : DC->decls()) { +    KindDeclPairs.push_back(D->getKind()); +    KindDeclPairs.push_back(GetDeclRef(D)); +  }    ++NumLexicalDeclContexts; -  Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, bytes(Decls)); +  RecordData::value_type Record[] = {DECL_CONTEXT_LEXICAL}; +  Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, +                            bytes(KindDeclPairs));    return Offset;  }  void ASTWriter::WriteTypeDeclOffsets() {    using namespace llvm; -  RecordData Record;    // Write the type offsets array -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block    unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev); -  Record.clear(); -  Record.push_back(TYPE_OFFSET); -  Record.push_back(TypeOffsets.size()); -  Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS); -  Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets)); +  { +    RecordData::value_type Record[] = {TYPE_OFFSET, TypeOffsets.size(), +                                       FirstTypeID - NUM_PREDEF_TYPE_IDS}; +    Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets)); +  }    // Write the declaration offsets array    Abbrev = new BitCodeAbbrev(); @@ -2777,16 +2787,15 @@ void ASTWriter::WriteTypeDeclOffsets() {    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base decl ID    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block    unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev); -  Record.clear(); -  Record.push_back(DECL_OFFSET); -  Record.push_back(DeclOffsets.size()); -  Record.push_back(FirstDeclID - NUM_PREDEF_DECL_IDS); -  Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets)); +  { +    RecordData::value_type Record[] = {DECL_OFFSET, DeclOffsets.size(), +                                       FirstDeclID - NUM_PREDEF_DECL_IDS}; +    Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets)); +  }  }  void ASTWriter::WriteFileDeclIDsMap() {    using namespace llvm; -  RecordData Record;    SmallVector<std::pair<FileID, DeclIDInFileInfo *>, 64> SortedFileDeclIDs(        FileDeclIDs.begin(), FileDeclIDs.end()); @@ -2802,13 +2811,13 @@ void ASTWriter::WriteFileDeclIDsMap() {        FileGroupedDeclIDs.push_back(LocDeclEntry.second);    } -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));    unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); -  Record.push_back(FILE_SORTED_DECLS); -  Record.push_back(FileGroupedDeclIDs.size()); +  RecordData::value_type Record[] = {FILE_SORTED_DECLS, +                                     FileGroupedDeclIDs.size()};    Stream.EmitRecordWithBlob(AbbrevCode, Record, bytes(FileGroupedDeclIDs));  } @@ -2816,14 +2825,12 @@ void ASTWriter::WriteComments() {    Stream.EnterSubblock(COMMENTS_BLOCK_ID, 3);    ArrayRef<RawComment *> RawComments = Context->Comments.getComments();    RecordData Record; -  for (ArrayRef<RawComment *>::iterator I = RawComments.begin(), -                                        E = RawComments.end(); -       I != E; ++I) { +  for (const auto *I : RawComments) {      Record.clear(); -    AddSourceRange((*I)->getSourceRange(), Record); -    Record.push_back((*I)->getKind()); -    Record.push_back((*I)->isTrailingComment()); -    Record.push_back((*I)->isAlmostTrailingComment()); +    AddSourceRange(I->getSourceRange(), Record); +    Record.push_back(I->getKind()); +    Record.push_back(I->isTrailingComment()); +    Record.push_back(I->isAlmostTrailingComment());      Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record);    }    Stream.ExitBlock(); @@ -3010,7 +3017,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {      }      // Create a blob abbreviation -    BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +    auto *Abbrev = new BitCodeAbbrev();      Abbrev->Add(BitCodeAbbrevOp(METHOD_POOL));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); @@ -3018,11 +3025,11 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {      unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev);      // Write the method pool -    RecordData Record; -    Record.push_back(METHOD_POOL); -    Record.push_back(BucketOffset); -    Record.push_back(NumTableEntries); -    Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool); +    { +      RecordData::value_type Record[] = {METHOD_POOL, BucketOffset, +                                         NumTableEntries}; +      Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool); +    }      // Create a blob abbreviation for the selector table offsets.      Abbrev = new BitCodeAbbrev(); @@ -3033,12 +3040,13 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {      unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev);      // Write the selector offsets table. -    Record.clear(); -    Record.push_back(SELECTOR_OFFSETS); -    Record.push_back(SelectorOffsets.size()); -    Record.push_back(FirstSelectorID - NUM_PREDEF_SELECTOR_IDS); -    Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, -                              bytes(SelectorOffsets)); +    { +      RecordData::value_type Record[] = { +          SELECTOR_OFFSETS, SelectorOffsets.size(), +          FirstSelectorID - NUM_PREDEF_SELECTOR_IDS}; +      Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, +                                bytes(SelectorOffsets)); +    }    }  } @@ -3102,18 +3110,20 @@ class ASTIdentifierTableTrait {    ASTWriter &Writer;    Preprocessor &PP;    IdentifierResolver &IdResolver; +  bool IsModule; +  bool NeedDecls; +  ASTWriter::RecordData *InterestingIdentifierOffsets;    /// \brief Determines whether this is an "interesting" identifier that needs a    /// full IdentifierInfo structure written into the hash table. Notably, this    /// doesn't check whether the name has macros defined; use PublicMacroIterator    /// to check that. -  bool isInterestingIdentifier(IdentifierInfo *II, uint64_t MacroOffset) { +  bool isInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset) {      if (MacroOffset ||          II->isPoisoned() || -        II->isExtensionToken() || -        II->getObjCOrBuiltinID() || +        (IsModule ? II->hasRevertedBuiltin() : II->getObjCOrBuiltinID()) ||          II->hasRevertedTokenIDToIdentifier() || -        II->getFETokenInfo<void>()) +        (NeedDecls && II->getFETokenInfo<void>()))        return true;      return false; @@ -3130,13 +3140,24 @@ public:    typedef unsigned offset_type;    ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, -                          IdentifierResolver &IdResolver) -      : Writer(Writer), PP(PP), IdResolver(IdResolver) {} +                          IdentifierResolver &IdResolver, bool IsModule, +                          ASTWriter::RecordData *InterestingIdentifierOffsets) +      : Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule), +        NeedDecls(!IsModule || !Writer.getLangOpts().CPlusPlus), +        InterestingIdentifierOffsets(InterestingIdentifierOffsets) {}    static hash_value_type ComputeHash(const IdentifierInfo* II) {      return llvm::HashString(II->getName());    } +  bool isInterestingIdentifier(const IdentifierInfo *II) { +    auto MacroOffset = Writer.getMacroDirectivesOffset(II); +    return isInterestingIdentifier(II, MacroOffset); +  } +  bool isInterestingNonMacroIdentifier(const IdentifierInfo *II) { +    return isInterestingIdentifier(II, 0); +  } +    std::pair<unsigned,unsigned>    EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {      unsigned KeyLen = II->getLength() + 1; @@ -3148,10 +3169,12 @@ public:        if (MacroOffset)          DataLen += 4; // MacroDirectives offset. -      for (IdentifierResolver::iterator D = IdResolver.begin(II), -                                     DEnd = IdResolver.end(); -           D != DEnd; ++D) -        DataLen += 4; +      if (NeedDecls) { +        for (IdentifierResolver::iterator D = IdResolver.begin(II), +                                       DEnd = IdResolver.end(); +             D != DEnd; ++D) +          DataLen += 4; +      }      }      using namespace llvm::support;      endian::Writer<little> LE(Out); @@ -3170,6 +3193,12 @@ public:      // Record the location of the key data.  This is used when generating      // the mapping from persistent IDs to strings.      Writer.SetIdentifierOffset(II, Out.tell()); + +    // Emit the offset of the key/data length information to the interesting +    // identifiers table if necessary. +    if (InterestingIdentifierOffsets && isInterestingIdentifier(II)) +      InterestingIdentifierOffsets->push_back(Out.tell() - 4); +      Out.write(II->getNameStart(), KeyLen);    } @@ -3193,6 +3222,7 @@ public:      Bits = (Bits << 1) | unsigned(HadMacroDefinition);      Bits = (Bits << 1) | unsigned(II->isExtensionToken());      Bits = (Bits << 1) | unsigned(II->isPoisoned()); +    Bits = (Bits << 1) | unsigned(II->hasRevertedBuiltin());      Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());      Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());      LE.write<uint16_t>(Bits); @@ -3200,18 +3230,21 @@ public:      if (HadMacroDefinition)        LE.write<uint32_t>(MacroOffset); -    // Emit the declaration IDs in reverse order, because the -    // IdentifierResolver provides the declarations as they would be -    // visible (e.g., the function "stat" would come before the struct -    // "stat"), but the ASTReader adds declarations to the end of the list -    // (so we need to see the struct "stat" before the function "stat"). -    // Only emit declarations that aren't from a chained PCH, though. -    SmallVector<NamedDecl *, 16> Decls(IdResolver.begin(II), IdResolver.end()); -    for (SmallVectorImpl<NamedDecl *>::reverse_iterator D = Decls.rbegin(), -                                                        DEnd = Decls.rend(); -         D != DEnd; ++D) -      LE.write<uint32_t>( -          Writer.getDeclID(getDeclForLocalLookup(PP.getLangOpts(), *D))); +    if (NeedDecls) { +      // Emit the declaration IDs in reverse order, because the +      // IdentifierResolver provides the declarations as they would be +      // visible (e.g., the function "stat" would come before the struct +      // "stat"), but the ASTReader adds declarations to the end of the list +      // (so we need to see the struct "stat" before the function "stat"). +      // Only emit declarations that aren't from a chained PCH, though. +      SmallVector<NamedDecl *, 16> Decls(IdResolver.begin(II), +                                         IdResolver.end()); +      for (SmallVectorImpl<NamedDecl *>::reverse_iterator D = Decls.rbegin(), +                                                          DEnd = Decls.rend(); +           D != DEnd; ++D) +        LE.write<uint32_t>( +            Writer.getDeclID(getDeclForLocalLookup(PP.getLangOpts(), *D))); +    }    }  };  } // end anonymous namespace @@ -3226,11 +3259,15 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,                                       bool IsModule) {    using namespace llvm; +  RecordData InterestingIdents; +    // Create and write out the blob that contains the identifier    // strings.    {      llvm::OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator; -    ASTIdentifierTableTrait Trait(*this, PP, IdResolver); +    ASTIdentifierTableTrait Trait( +        *this, PP, IdResolver, IsModule, +        (getLangOpts().CPlusPlus && IsModule) ? &InterestingIdents : nullptr);      // Look for any identifiers that were named while processing the      // headers, but are otherwise not needed. We add these to the hash @@ -3238,21 +3275,20 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,      // where the user adds new macro definitions when building the AST      // file.      SmallVector<const IdentifierInfo *, 128> IIs; -    for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), -                                IDEnd = PP.getIdentifierTable().end(); -         ID != IDEnd; ++ID) -      IIs.push_back(ID->second); +    for (const auto &ID : PP.getIdentifierTable()) +      IIs.push_back(ID.second);      // Sort the identifiers lexicographically before getting them references so      // that their order is stable.      std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>());      for (const IdentifierInfo *II : IIs) -      getIdentifierRef(II); +      if (Trait.isInterestingNonMacroIdentifier(II)) +        getIdentifierRef(II);      // Create the on-disk hash table representation. We only store offsets      // for identifiers that appear here for the first time.      IdentifierOffsets.resize(NextIdentID - FirstIdentID);      for (auto IdentIDPair : IdentifierIDs) { -      IdentifierInfo *II = const_cast<IdentifierInfo *>(IdentIDPair.first); +      auto *II = const_cast<IdentifierInfo *>(IdentIDPair.first);        IdentID ID = IdentIDPair.second;        assert(II && "NULL identifier in identifier table");        if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) @@ -3271,21 +3307,19 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,      }      // Create a blob abbreviation -    BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +    auto *Abbrev = new BitCodeAbbrev();      Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_TABLE));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);      // Write the identifier table -    RecordData Record; -    Record.push_back(IDENTIFIER_TABLE); -    Record.push_back(BucketOffset); +    RecordData::value_type Record[] = {IDENTIFIER_TABLE, BucketOffset};      Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable);    }    // Write the offsets table for identifier IDs. -  BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID @@ -3296,13 +3330,17 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,    for (unsigned I = 0, N = IdentifierOffsets.size(); I != N; ++I)      assert(IdentifierOffsets[I] && "Missing identifier offset?");  #endif -   -  RecordData Record; -  Record.push_back(IDENTIFIER_OFFSET); -  Record.push_back(IdentifierOffsets.size()); -  Record.push_back(FirstIdentID - NUM_PREDEF_IDENT_IDS); + +  RecordData::value_type Record[] = {IDENTIFIER_OFFSET, +                                     IdentifierOffsets.size(), +                                     FirstIdentID - NUM_PREDEF_IDENT_IDS};    Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record,                              bytes(IdentifierOffsets)); + +  // In C++, write the list of interesting identifiers (those that are +  // defined as macros, poisoned, or similar unusual things). +  if (!InterestingIdents.empty()) +    Stream.EmitRecord(INTERESTING_IDENTIFIERS, InterestingIdents);  }  //===----------------------------------------------------------------------===// @@ -3313,12 +3351,14 @@ namespace {  // Trait used for the on-disk hash table used in the method pool.  class ASTDeclContextNameLookupTrait {    ASTWriter &Writer; +  llvm::SmallVector<DeclID, 64> DeclIDs;  public: -  typedef DeclarationName key_type; +  typedef DeclarationNameKey key_type;    typedef key_type key_type_ref; -  typedef DeclContext::lookup_result data_type; +  /// A start and end index into DeclIDs, representing a sequence of decls. +  typedef std::pair<unsigned, unsigned> data_type;    typedef const data_type& data_type_ref;    typedef unsigned hash_value_type; @@ -3326,42 +3366,47 @@ public:    explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { } -  hash_value_type ComputeHash(DeclarationName Name) { -    llvm::FoldingSetNodeID ID; -    ID.AddInteger(Name.getNameKind()); - -    switch (Name.getNameKind()) { -    case DeclarationName::Identifier: -      ID.AddString(Name.getAsIdentifierInfo()->getName()); -      break; -    case DeclarationName::ObjCZeroArgSelector: -    case DeclarationName::ObjCOneArgSelector: -    case DeclarationName::ObjCMultiArgSelector: -      ID.AddInteger(serialization::ComputeHash(Name.getObjCSelector())); -      break; -    case DeclarationName::CXXConstructorName: -    case DeclarationName::CXXDestructorName: -    case DeclarationName::CXXConversionFunctionName: -      break; -    case DeclarationName::CXXOperatorName: -      ID.AddInteger(Name.getCXXOverloadedOperator()); -      break; -    case DeclarationName::CXXLiteralOperatorName: -      ID.AddString(Name.getCXXLiteralIdentifier()->getName()); -    case DeclarationName::CXXUsingDirective: -      break; +  template<typename Coll> +  data_type getData(const Coll &Decls) { +    unsigned Start = DeclIDs.size(); +    for (NamedDecl *D : Decls) { +      DeclIDs.push_back( +          Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), D)));      } +    return std::make_pair(Start, DeclIDs.size()); +  } -    return ID.ComputeHash(); +  data_type ImportData(const reader::ASTDeclContextNameLookupTrait::data_type &FromReader) { +    unsigned Start = DeclIDs.size(); +    for (auto ID : FromReader) +      DeclIDs.push_back(ID); +    return std::make_pair(Start, DeclIDs.size());    } -  std::pair<unsigned,unsigned> -    EmitKeyDataLength(raw_ostream& Out, DeclarationName Name, -                      data_type_ref Lookup) { +  static bool EqualKey(key_type_ref a, key_type_ref b) { +    return a == b; +  } + +  hash_value_type ComputeHash(DeclarationNameKey Name) { +    return Name.getHash(); +  } + +  void EmitFileRef(raw_ostream &Out, ModuleFile *F) const { +    assert(Writer.hasChain() && +           "have reference to loaded module file but no chain?"); + +    using namespace llvm::support; +    endian::Writer<little>(Out) +        .write<uint32_t>(Writer.getChain()->getModuleFileID(F)); +  } + +  std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &Out, +                                                  DeclarationNameKey Name, +                                                  data_type_ref Lookup) {      using namespace llvm::support;      endian::Writer<little> LE(Out);      unsigned KeyLen = 1; -    switch (Name.getNameKind()) { +    switch (Name.getKind()) {      case DeclarationName::Identifier:      case DeclarationName::ObjCZeroArgSelector:      case DeclarationName::ObjCOneArgSelector: @@ -3380,33 +3425,33 @@ public:      }      LE.write<uint16_t>(KeyLen); -    // 2 bytes for num of decls and 4 for each DeclID. -    unsigned DataLen = 2 + 4 * Lookup.size(); +    // 4 bytes for each DeclID. +    unsigned DataLen = 4 * (Lookup.second - Lookup.first); +    assert(uint16_t(DataLen) == DataLen && +           "too many decls for serialized lookup result");      LE.write<uint16_t>(DataLen);      return std::make_pair(KeyLen, DataLen);    } -  void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) { +  void EmitKey(raw_ostream &Out, DeclarationNameKey Name, unsigned) {      using namespace llvm::support;      endian::Writer<little> LE(Out); -    LE.write<uint8_t>(Name.getNameKind()); -    switch (Name.getNameKind()) { +    LE.write<uint8_t>(Name.getKind()); +    switch (Name.getKind()) {      case DeclarationName::Identifier: -      LE.write<uint32_t>(Writer.getIdentifierRef(Name.getAsIdentifierInfo())); +    case DeclarationName::CXXLiteralOperatorName: +      LE.write<uint32_t>(Writer.getIdentifierRef(Name.getIdentifier()));        return;      case DeclarationName::ObjCZeroArgSelector:      case DeclarationName::ObjCOneArgSelector:      case DeclarationName::ObjCMultiArgSelector: -      LE.write<uint32_t>(Writer.getSelectorRef(Name.getObjCSelector())); +      LE.write<uint32_t>(Writer.getSelectorRef(Name.getSelector()));        return;      case DeclarationName::CXXOperatorName: -      assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS && +      assert(Name.getOperatorKind() < NUM_OVERLOADED_OPERATORS &&               "Invalid operator?"); -      LE.write<uint8_t>(Name.getCXXOverloadedOperator()); -      return; -    case DeclarationName::CXXLiteralOperatorName: -      LE.write<uint32_t>(Writer.getIdentifierRef(Name.getCXXLiteralIdentifier())); +      LE.write<uint8_t>(Name.getOperatorKind());        return;      case DeclarationName::CXXConstructorName:      case DeclarationName::CXXDestructorName: @@ -3418,17 +3463,13 @@ public:      llvm_unreachable("Invalid name kind?");    } -  void EmitData(raw_ostream& Out, key_type_ref, -                data_type Lookup, unsigned DataLen) { +  void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup, +                unsigned DataLen) {      using namespace llvm::support;      endian::Writer<little> LE(Out);      uint64_t Start = Out.tell(); (void)Start; -    LE.write<uint16_t>(Lookup.size()); -    for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end(); -         I != E; ++I) -      LE.write<uint32_t>( -          Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), *I))); - +    for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) +      LE.write<uint32_t>(DeclIDs[I]);      assert(Out.tell() - Start == DataLen && "Data length is wrong");    }  }; @@ -3448,7 +3489,7 @@ bool ASTWriter::isLookupResultEntirelyExternal(StoredDeclsList &Result,    return true;  } -uint32_t +void  ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,                                     llvm::SmallVectorImpl<char> &LookupTable) {    assert(!ConstDC->HasLazyLocalLexicalLookups && @@ -3456,12 +3497,12 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,           "must call buildLookups first");    // FIXME: We need to build the lookups table, which is logically const. -  DeclContext *DC = const_cast<DeclContext*>(ConstDC); +  auto *DC = const_cast<DeclContext*>(ConstDC);    assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table");    // Create the on-disk hash table representation. -  llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> -      Generator; +  MultiOnDiskHashTableGenerator<reader::ASTDeclContextNameLookupTrait, +                                ASTDeclContextNameLookupTrait> Generator;    ASTDeclContextNameLookupTrait Trait(*this);    // The first step is to collect the declaration names which we need to @@ -3477,11 +3518,11 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,      auto &Name = Lookup.first;      auto &Result = Lookup.second; -    // If there are no local declarations in our lookup result, we don't -    // need to write an entry for the name at all unless we're rewriting -    // the decl context. If we can't write out a lookup set without -    // performing more deserialization, just skip this entry. -    if (isLookupResultExternal(Result, DC) && !isRewritten(cast<Decl>(DC)) && +    // If there are no local declarations in our lookup result, we +    // don't need to write an entry for the name at all. If we can't +    // write out a lookup set without performing more deserialization, +    // just skip this entry. +    if (isLookupResultExternal(Result, DC) &&          isLookupResultEntirelyExternal(Result, DC))        continue; @@ -3596,7 +3637,7 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,      switch (Name.getNameKind()) {      default: -      Generator.insert(Name, Result, Trait); +      Generator.insert(Name, Trait.getData(Result), Trait);        break;      case DeclarationName::CXXConstructorName: @@ -3614,17 +3655,15 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,    // the key, only the kind of name is used.    if (!ConstructorDecls.empty())      Generator.insert(ConstructorDecls.front()->getDeclName(), -                     DeclContext::lookup_result(ConstructorDecls), Trait); +                     Trait.getData(ConstructorDecls), Trait);    if (!ConversionDecls.empty())      Generator.insert(ConversionDecls.front()->getDeclName(), -                     DeclContext::lookup_result(ConversionDecls), Trait); +                     Trait.getData(ConversionDecls), Trait); -  // Create the on-disk hash table in a buffer. -  llvm::raw_svector_ostream Out(LookupTable); -  // Make sure that no bucket is at offset 0 -  using namespace llvm::support; -  endian::Writer<little>(Out).write<uint32_t>(0); -  return Generator.Emit(Out, Trait); +  // Create the on-disk hash table. Also emit the existing imported and +  // merged table if there is one. +  auto *Lookups = Chain ? Chain->getLoadedLookupTables(DC) : nullptr; +  Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr);  }  /// \brief Write the block containing all of the declaration IDs @@ -3640,7 +3679,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,    if (isa<NamespaceDecl>(DC) && Chain &&        Chain->getKeyDeclaration(cast<Decl>(DC))->isFromASTFile()) {      // Only do this once, for the first local declaration of the namespace. -    for (NamespaceDecl *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev; +    for (auto *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev;           Prev = Prev->getPreviousDecl())        if (!Prev->isFromASTFile())          return 0; @@ -3707,12 +3746,10 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,    // Create the on-disk hash table in a buffer.    SmallString<4096> LookupTable; -  uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); +  GenerateNameLookupTable(DC, LookupTable);    // Write the lookup table -  RecordData Record; -  Record.push_back(DECL_CONTEXT_VISIBLE); -  Record.push_back(BucketOffset); +  RecordData::value_type Record[] = {DECL_CONTEXT_VISIBLE};    Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record,                              LookupTable);    ++NumVisibleDeclContexts; @@ -3732,7 +3769,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {    // Create the on-disk hash table in a buffer.    SmallString<4096> LookupTable; -  uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); +  GenerateNameLookupTable(DC, LookupTable);    // If we're updating a namespace, select a key declaration as the key for the    // update record; those are the only ones that will be checked on reload. @@ -3740,17 +3777,13 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {      DC = cast<DeclContext>(Chain->getKeyDeclaration(cast<Decl>(DC)));    // Write the lookup table -  RecordData Record; -  Record.push_back(UPDATE_VISIBLE); -  Record.push_back(getDeclID(cast<Decl>(DC))); -  Record.push_back(BucketOffset); +  RecordData::value_type Record[] = {UPDATE_VISIBLE, getDeclID(cast<Decl>(DC))};    Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable);  }  /// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions.  void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) { -  RecordData Record; -  Record.push_back(Opts.fp_contract); +  RecordData::value_type Record[] = {Opts.fp_contract};    Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record);  } @@ -3766,81 +3799,6 @@ void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) {    Stream.EmitRecord(OPENCL_EXTENSIONS, Record);  } -void ASTWriter::WriteRedeclarations() { -  RecordData LocalRedeclChains; -  SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap; - -  for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) { -    const Decl *Key = Redeclarations[I]; -    assert((Chain ? Chain->getKeyDeclaration(Key) == Key -                  : Key->isFirstDecl()) && -           "not the key declaration"); - -    const Decl *First = Key->getCanonicalDecl(); -    const Decl *MostRecent = First->getMostRecentDecl(); - -    assert((getDeclID(First) >= NUM_PREDEF_DECL_IDS || First == Key) && -           "should not have imported key decls for predefined decl"); - -    // If we only have a single declaration, there is no point in storing -    // a redeclaration chain. -    if (First == MostRecent) -      continue; -     -    unsigned Offset = LocalRedeclChains.size(); -    unsigned Size = 0; -    LocalRedeclChains.push_back(0); // Placeholder for the size. - -    // Collect the set of local redeclarations of this declaration. -    for (const Decl *Prev = MostRecent; Prev; -         Prev = Prev->getPreviousDecl()) {  -      if (!Prev->isFromASTFile() && Prev != Key) { -        AddDeclRef(Prev, LocalRedeclChains); -        ++Size; -      } -    } - -    LocalRedeclChains[Offset] = Size; - -    // Reverse the set of local redeclarations, so that we store them in -    // order (since we found them in reverse order). -    std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end()); - -    // Add the mapping from the first ID from the AST to the set of local -    // declarations. -    LocalRedeclarationsInfo Info = { getDeclID(Key), Offset }; -    LocalRedeclsMap.push_back(Info); - -    assert(N == Redeclarations.size() &&  -           "Deserialized a declaration we shouldn't have"); -  } - -  if (LocalRedeclChains.empty()) -    return; - -  // Sort the local redeclarations map by the first declaration ID, -  // since the reader will be performing binary searches on this information. -  llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end()); -   -  // Emit the local redeclarations map. -  using namespace llvm; -  llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); -  Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP)); -  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries -  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); -  unsigned AbbrevID = Stream.EmitAbbrev(Abbrev); -   -  RecordData Record; -  Record.push_back(LOCAL_REDECLARATIONS_MAP); -  Record.push_back(LocalRedeclsMap.size()); -  Stream.EmitRecordWithBlob(AbbrevID, Record,  -    reinterpret_cast<char*>(LocalRedeclsMap.data()), -    LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo)); - -  // Emit the redeclaration chains. -  Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains); -} -  void ASTWriter::WriteObjCCategories() {    SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;    RecordData Categories; @@ -3877,19 +3835,18 @@ void ASTWriter::WriteObjCCategories() {    // Emit the categories map.    using namespace llvm; -  llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + +  auto *Abbrev = new BitCodeAbbrev();    Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP));    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));    unsigned AbbrevID = Stream.EmitAbbrev(Abbrev); -   -  RecordData Record; -  Record.push_back(OBJC_CATEGORIES_MAP); -  Record.push_back(CategoriesMap.size()); -  Stream.EmitRecordWithBlob(AbbrevID, Record,  -                            reinterpret_cast<char*>(CategoriesMap.data()), + +  RecordData::value_type Record[] = {OBJC_CATEGORIES_MAP, CategoriesMap.size()}; +  Stream.EmitRecordWithBlob(AbbrevID, Record, +                            reinterpret_cast<char *>(CategoriesMap.data()),                              CategoriesMap.size() * sizeof(ObjCCategoriesInfo)); -   +    // Emit the category lists.    Stream.EmitRecord(OBJC_CATEGORIES, Categories);  } @@ -3908,10 +3865,8 @@ void ASTWriter::WriteLateParsedTemplates(Sema &SemaRef) {      AddDeclRef(LPT->D, Record);      Record.push_back(LPT->Toks.size()); -    for (CachedTokens::iterator TokIt = LPT->Toks.begin(), -                                TokEnd = LPT->Toks.end(); -         TokIt != TokEnd; ++TokIt) { -      AddToken(*TokIt, Record); +    for (const auto &Tok : LPT->Toks) { +      AddToken(Tok, Record);      }    }    Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record); @@ -3925,6 +3880,41 @@ void ASTWriter::WriteOptimizePragmaOptions(Sema &SemaRef) {    Stream.EmitRecord(OPTIMIZE_PRAGMA_OPTIONS, Record);  } +void ASTWriter::WriteModuleFileExtension(Sema &SemaRef, +                                         ModuleFileExtensionWriter &Writer) { +  // Enter the extension block. +  Stream.EnterSubblock(EXTENSION_BLOCK_ID, 4); + +  // Emit the metadata record abbreviation. +  auto *Abv = new llvm::BitCodeAbbrev(); +  Abv->Add(llvm::BitCodeAbbrevOp(EXTENSION_METADATA)); +  Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); +  Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); +  Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); +  Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); +  Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); +  unsigned Abbrev = Stream.EmitAbbrev(Abv); + +  // Emit the metadata record. +  RecordData Record; +  auto Metadata = Writer.getExtension()->getExtensionMetadata(); +  Record.push_back(EXTENSION_METADATA); +  Record.push_back(Metadata.MajorVersion); +  Record.push_back(Metadata.MinorVersion); +  Record.push_back(Metadata.BlockName.size()); +  Record.push_back(Metadata.UserInfo.size()); +  SmallString<64> Buffer; +  Buffer += Metadata.BlockName; +  Buffer += Metadata.UserInfo; +  Stream.EmitRecordWithBlob(Abbrev, Record, Buffer); + +  // Emit the contents of the extension block. +  Writer.writeExtensionContents(SemaRef, Stream); + +  // Exit the extension block. +  Stream.ExitBlock(); +} +  //===----------------------------------------------------------------------===//  // General Serialization Routines  //===----------------------------------------------------------------------===// @@ -3933,9 +3923,7 @@ void ASTWriter::WriteOptimizePragmaOptions(Sema &SemaRef) {  void ASTWriter::WriteAttributes(ArrayRef<const Attr*> Attrs,                                  RecordDataImpl &Record) {    Record.push_back(Attrs.size()); -  for (ArrayRef<const Attr *>::iterator i = Attrs.begin(), -                                        e = Attrs.end(); i != e; ++i){ -    const Attr *A = *i; +  for (const auto *A : Attrs) {      Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs      AddSourceRange(A->getRange(), Record); @@ -3986,7 +3974,7 @@ void ASTWriter::AddPath(StringRef Path, RecordDataImpl &Record) {    AddString(FilePath, Record);  } -void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataImpl &Record, +void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataRef Record,                                     StringRef Path) {    SmallString<128> FilePath(Path);    PreparePathForOutput(FilePath); @@ -4028,28 +4016,35 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {    SelectorOffsets[ID - FirstSelectorID] = Offset;  } -ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) +ASTWriter::ASTWriter( +  llvm::BitstreamWriter &Stream, +  ArrayRef<llvm::IntrusiveRefCntPtr<ModuleFileExtension>> Extensions, +  bool IncludeTimestamps)      : Stream(Stream), Context(nullptr), PP(nullptr), Chain(nullptr), -      WritingModule(nullptr), WritingAST(false), -      DoneWritingDeclsAndTypes(false), ASTHasCompilerErrors(false), -      FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID), -      FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID), -      FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID), -      FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID), -      FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS), +      WritingModule(nullptr), IncludeTimestamps(IncludeTimestamps), +      WritingAST(false), DoneWritingDeclsAndTypes(false), +      ASTHasCompilerErrors(false), FirstDeclID(NUM_PREDEF_DECL_IDS), +      NextDeclID(FirstDeclID), FirstTypeID(NUM_PREDEF_TYPE_IDS), +      NextTypeID(FirstTypeID), FirstIdentID(NUM_PREDEF_IDENT_IDS), +      NextIdentID(FirstIdentID), FirstMacroID(NUM_PREDEF_MACRO_IDS), +      NextMacroID(FirstMacroID), FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS),        NextSubmoduleID(FirstSubmoduleID),        FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID),        CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0),        NumLexicalDeclContexts(0), NumVisibleDeclContexts(0),        NextCXXBaseSpecifiersID(1), NextCXXCtorInitializersID(1), -      TypeExtQualAbbrev(0), -      TypeFunctionProtoAbbrev(0), DeclParmVarAbbrev(0), +      TypeExtQualAbbrev(0), TypeFunctionProtoAbbrev(0), DeclParmVarAbbrev(0),        DeclContextLexicalAbbrev(0), DeclContextVisibleLookupAbbrev(0),        UpdateVisibleAbbrev(0), DeclRecordAbbrev(0), DeclTypedefAbbrev(0),        DeclVarAbbrev(0), DeclFieldAbbrev(0), DeclEnumAbbrev(0),        DeclObjCIvarAbbrev(0), DeclCXXMethodAbbrev(0), DeclRefExprAbbrev(0),        CharacterLiteralAbbrev(0), IntegerLiteralAbbrev(0), -      ExprImplicitCastAbbrev(0) {} +      ExprImplicitCastAbbrev(0) { +  for (const auto &Ext : Extensions) { +    if (auto Writer = Ext->createExtensionWriter(*this)) +      ModuleFileExtensionWriters.push_back(std::move(Writer)); +  } +}  ASTWriter::~ASTWriter() {    llvm::DeleteContainerSeconds(FileDeclIDs); @@ -4060,12 +4055,15 @@ const LangOptions &ASTWriter::getLangOpts() const {    return Context->getLangOpts();  } -void ASTWriter::WriteAST(Sema &SemaRef, -                         const std::string &OutputFile, -                         Module *WritingModule, StringRef isysroot, -                         bool hasErrors) { +time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const { +  return IncludeTimestamps ? E->getModificationTime() : 0; +} + +uint64_t ASTWriter::WriteAST(Sema &SemaRef, const std::string &OutputFile, +                             Module *WritingModule, StringRef isysroot, +                             bool hasErrors) {    WritingAST = true; -   +    ASTHasCompilerErrors = hasErrors;    // Emit the file header. @@ -4079,13 +4077,15 @@ void ASTWriter::WriteAST(Sema &SemaRef,    Context = &SemaRef.Context;    PP = &SemaRef.PP;    this->WritingModule = WritingModule; -  WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule); +  ASTFileSignature Signature = +      WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule);    Context = nullptr;    PP = nullptr;    this->WritingModule = nullptr;    this->BaseDirectory.clear();    WritingAST = false; +  return Signature;  }  template<typename Vector> @@ -4097,10 +4097,9 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,    }  } -void ASTWriter::WriteASTCore(Sema &SemaRef, -                             StringRef isysroot, -                             const std::string &OutputFile,  -                             Module *WritingModule) { +uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, +                                 const std::string &OutputFile, +                                 Module *WritingModule) {    using namespace llvm;    bool isModule = WritingModule != nullptr; @@ -4117,8 +4116,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,      if (D) {        assert(D->isCanonicalDecl() && "predefined decl is not canonical");        DeclIDs[D] = ID; -      if (D->getMostRecentDecl() != D) -        Redeclarations.push_back(D);      }    };    RegisterPredefDecl(Context.getTranslationUnitDecl(), @@ -4133,7 +4130,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    RegisterPredefDecl(Context.ObjCInstanceTypeDecl,                       PREDEF_DECL_OBJC_INSTANCETYPE_ID);    RegisterPredefDecl(Context.BuiltinVaListDecl, PREDEF_DECL_BUILTIN_VA_LIST_ID); +  RegisterPredefDecl(Context.VaListTagDecl, PREDEF_DECL_VA_LIST_TAG); +  RegisterPredefDecl(Context.BuiltinMSVaListDecl, +                     PREDEF_DECL_BUILTIN_MS_VA_LIST_ID);    RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID); +  RegisterPredefDecl(Context.MakeIntegerSeqDecl, +                     PREDEF_DECL_MAKE_INTEGER_SEQ_ID);    // Build a record containing all of the tentative definitions in this file, in    // TentativeDefinitions order.  Generally, this record will be empty for @@ -4187,11 +4189,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    // Build a record containing all of pending implicit instantiations.    RecordData PendingInstantiations; -  for (std::deque<Sema::PendingImplicitInstantiation>::iterator -         I = SemaRef.PendingInstantiations.begin(), -         N = SemaRef.PendingInstantiations.end(); I != N; ++I) { -    AddDeclRef(I->first, PendingInstantiations); -    AddSourceLocation(I->second, PendingInstantiations); +  for (const auto &I : SemaRef.PendingInstantiations) { +    AddDeclRef(I.first, PendingInstantiations); +    AddSourceLocation(I.second, PendingInstantiations);    }    assert(SemaRef.PendingLocalImplicitInstantiations.empty() &&           "There are local ones at end of translation unit!"); @@ -4210,12 +4210,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    // Build a record containing all of the known namespaces.    RecordData KnownNamespaces; -  for (llvm::MapVector<NamespaceDecl*, bool>::iterator -            I = SemaRef.KnownNamespaces.begin(), -         IEnd = SemaRef.KnownNamespaces.end(); -       I != IEnd; ++I) { -    if (!I->second) -      AddDeclRef(I->first, KnownNamespaces); +  for (const auto &I : SemaRef.KnownNamespaces) { +    if (!I.second) +      AddDeclRef(I.first, KnownNamespaces);    }    // Build a record of all used, undefined objects that require definitions. @@ -4223,10 +4220,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;    SemaRef.getUndefinedButUsed(Undefined); -  for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator -         I = Undefined.begin(), E = Undefined.end(); I != E; ++I) { -    AddDeclRef(I->first, UndefinedButUsed); -    AddSourceLocation(I->second, UndefinedButUsed); +  for (const auto &I : Undefined) { +    AddDeclRef(I.first, UndefinedButUsed); +    AddSourceLocation(I.second, UndefinedButUsed);    }    // Build a record containing all delete-expressions that we would like to @@ -4244,41 +4240,43 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    }    // Write the control block -  WriteControlBlock(PP, Context, isysroot, OutputFile); +  uint64_t Signature = WriteControlBlock(PP, Context, isysroot, OutputFile);    // Write the remaining AST contents. -  RecordData Record;    Stream.EnterSubblock(AST_BLOCK_ID, 5);    // This is so that older clang versions, before the introduction    // of the control block, can read and reject the newer PCH format. -  Record.clear(); -  Record.push_back(VERSION_MAJOR); -  Stream.EmitRecord(METADATA_OLD_FORMAT, Record); +  { +    RecordData Record = {VERSION_MAJOR}; +    Stream.EmitRecord(METADATA_OLD_FORMAT, Record); +  }    // Create a lexical update block containing all of the declarations in the    // translation unit that do not come from other AST files.    const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); -  SmallVector<KindDeclIDPair, 64> NewGlobalDecls; -  for (const auto *I : TU->noload_decls()) { -    if (!I->isFromASTFile()) -      NewGlobalDecls.push_back(std::make_pair(I->getKind(), GetDeclRef(I))); +  SmallVector<uint32_t, 128> NewGlobalKindDeclPairs; +  for (const auto *D : TU->noload_decls()) { +    if (!D->isFromASTFile()) { +      NewGlobalKindDeclPairs.push_back(D->getKind()); +      NewGlobalKindDeclPairs.push_back(GetDeclRef(D)); +    }    } -  llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev(); +  auto *Abv = new llvm::BitCodeAbbrev();    Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL));    Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));    unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(Abv); -  Record.clear(); -  Record.push_back(TU_UPDATE_LEXICAL); -  Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, -                            bytes(NewGlobalDecls)); -   +  { +    RecordData::value_type Record[] = {TU_UPDATE_LEXICAL}; +    Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, +                              bytes(NewGlobalKindDeclPairs)); +  } +    // And a visible updates block for the translation unit.    Abv = new llvm::BitCodeAbbrev();    Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE));    Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); -  Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32));    Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));    UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv);    WriteDeclContextVisibleUpdate(TU); @@ -4310,29 +4308,27 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    // Make sure visible decls, added to DeclContexts previously loaded from    // an AST file, are registered for serialization. -  for (SmallVectorImpl<const Decl *>::iterator -         I = UpdatingVisibleDecls.begin(), -         E = UpdatingVisibleDecls.end(); I != E; ++I) { -    GetDeclRef(*I); +  for (const auto *I : UpdatingVisibleDecls) { +    GetDeclRef(I);    }    // Make sure all decls associated with an identifier are registered for -  // serialization. -  llvm::SmallVector<const IdentifierInfo*, 256> IIs; -  for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), -                              IDEnd = PP.getIdentifierTable().end(); -       ID != IDEnd; ++ID) { -    const IdentifierInfo *II = ID->second; -    if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) -      IIs.push_back(II); -  } -  // Sort the identifiers to visit based on their name. -  std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>()); -  for (const IdentifierInfo *II : IIs) { -    for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II), -                                   DEnd = SemaRef.IdResolver.end(); -         D != DEnd; ++D) { -      GetDeclRef(*D); +  // serialization, if we're storing decls with identifiers. +  if (!WritingModule || !getLangOpts().CPlusPlus) { +    llvm::SmallVector<const IdentifierInfo*, 256> IIs; +    for (const auto &ID : PP.getIdentifierTable()) { +      const IdentifierInfo *II = ID.second; +      if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) +        IIs.push_back(II); +    } +    // Sort the identifiers to visit based on their name. +    std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>()); +    for (const IdentifierInfo *II : IIs) { +      for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II), +                                     DEnd = SemaRef.IdResolver.end(); +           D != DEnd; ++D) { +        GetDeclRef(*D); +      }      }    } @@ -4363,7 +4359,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,      //   c++-base-specifiers-id:i32      //   type-id:i32)      //  -    llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); +    auto *Abbrev = new BitCodeAbbrev();      Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP));      Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev); @@ -4402,8 +4398,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,          writeBaseIDOrNone(M->BaseTypeIndex, M->LocalNumTypes);        }      } -    Record.clear(); -    Record.push_back(MODULE_OFFSET_MAP); +    RecordData::value_type Record[] = {MODULE_OFFSET_MAP};      Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,                                Buffer.data(), Buffer.size());    } @@ -4415,10 +4410,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5);    WriteTypeAbbrevs();    WriteDeclAbbrevs(); -  for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(), -                                  E = DeclsToRewrite.end(); -       I != E; ++I) -    DeclTypesToEmit.push(const_cast<Decl*>(*I));    do {      WriteDeclUpdatesBlocks(DeclUpdatesOffsetsRecord);      while (!DeclTypesToEmit.empty()) { @@ -4442,12 +4433,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    WriteCXXCtorInitializersOffsets();    WriteFileDeclIDsMap();    WriteSourceManagerBlock(Context.getSourceManager(), PP); -    WriteComments();    WritePreprocessor(PP, isModule);    WriteHeaderSearch(PP.getHeaderSearchInfo());    WriteSelectors(SemaRef);    WriteReferencedSelectorsPool(SemaRef); +  WriteLateParsedTemplates(SemaRef);    WriteIdentifierTable(PP, SemaRef.IdResolver, isModule);    WriteFPPragmaOptions(SemaRef.getFPOptions());    WriteOpenCLExtensions(SemaRef); @@ -4561,20 +4552,21 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,    }    WriteDeclReplacementsBlock(); -  WriteRedeclarations();    WriteObjCCategories(); -  WriteLateParsedTemplates(SemaRef);    if(!WritingModule)      WriteOptimizePragmaOptions(SemaRef);    // Some simple statistics -  Record.clear(); -  Record.push_back(NumStatements); -  Record.push_back(NumMacros); -  Record.push_back(NumLexicalDeclContexts); -  Record.push_back(NumVisibleDeclContexts); +  RecordData::value_type Record[] = { +      NumStatements, NumMacros, NumLexicalDeclContexts, NumVisibleDeclContexts};    Stream.EmitRecord(STATISTICS, Record);    Stream.ExitBlock(); + +  // Write the module file extension blocks. +  for (const auto &ExtWriter : ModuleFileExtensionWriters) +    WriteModuleFileExtension(SemaRef, *ExtWriter); + +  return Signature;  }  void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { @@ -4586,8 +4578,6 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {    for (auto &DeclUpdate : LocalUpdates) {      const Decl *D = DeclUpdate.first; -    if (isRewritten(D)) -      continue; // The decl will be written completely,no need to store updates.      bool HasUpdatedBody = false;      RecordData Record; @@ -4699,7 +4689,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {      }      if (HasUpdatedBody) { -      const FunctionDecl *Def = cast<FunctionDecl>(D); +      const auto *Def = cast<FunctionDecl>(D);        Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);        Record.push_back(Def->isInlined());        AddSourceLocation(Def->getInnerLocStart(), Record); @@ -4720,11 +4710,10 @@ void ASTWriter::WriteDeclReplacementsBlock() {      return;    RecordData Record; -  for (SmallVectorImpl<ReplacedDeclInfo>::iterator -         I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) { -    Record.push_back(I->ID); -    Record.push_back(I->Offset); -    Record.push_back(I->Loc); +  for (const auto &I : ReplacedDecls) { +    Record.push_back(I.ID); +    Record.push_back(I.Offset); +    Record.push_back(I.Loc);    }    Stream.EmitRecord(DECL_REPLACEMENTS, Record);  } @@ -5247,9 +5236,8 @@ void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) {    case TemplateName::OverloadedTemplate: {      OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate();      Record.push_back(OvT->size()); -    for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end(); -           I != E; ++I) -      AddDeclRef(*I, Record); +    for (const auto &I : *OvT) +      AddDeclRef(I, Record);      break;    } @@ -5339,10 +5327,8 @@ ASTWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams,    AddSourceLocation(TemplateParams->getLAngleLoc(), Record);    AddSourceLocation(TemplateParams->getRAngleLoc(), Record);    Record.push_back(TemplateParams->size()); -  for (TemplateParameterList::const_iterator -         P = TemplateParams->begin(), PEnd = TemplateParams->end(); -         P != PEnd; ++P) -    AddDeclRef(*P, Record); +  for (const auto &P : *TemplateParams) +    AddDeclRef(P, Record);  }  /// \brief Emit a template argument list. @@ -5657,7 +5643,7 @@ void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {  void ASTWriter::CompletedTagDefinition(const TagDecl *D) {    assert(D->isCompleteDefinition());    assert(!WritingAST && "Already writing the AST!"); -  if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { +  if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {      // We are interested when a PCH decl is modified.      if (RD->isFromASTFile()) {        // A forward reference was mutated into a definition. Rewrite it. @@ -5671,26 +5657,52 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) {    }  } +static bool isImportedDeclContext(ASTReader *Chain, const Decl *D) { +  if (D->isFromASTFile()) +    return true; + +  // If we've not loaded any modules, this can't be imported. +  if (!Chain || !Chain->getModuleManager().size()) +    return false; + +  // The predefined __va_list_tag struct is imported if we imported any decls. +  // FIXME: This is a gross hack. +  return D == D->getASTContext().getVaListTagDecl(); +} +  void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {    // TU and namespaces are handled elsewhere.    if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC))      return; -  if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile())) -    return; // Not a source decl added to a DeclContext from PCH. +  // We're only interested in cases where a local declaration is added to an +  // imported context. +  if (D->isFromASTFile() || !isImportedDeclContext(Chain, cast<Decl>(DC))) +    return; +  assert(DC == DC->getPrimaryContext() && "added to non-primary context");    assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!");    assert(!WritingAST && "Already writing the AST!"); -  UpdatedDeclContexts.insert(DC); +  if (UpdatedDeclContexts.insert(DC) && !cast<Decl>(DC)->isFromASTFile()) { +    // We're adding a visible declaration to a predefined decl context. Ensure +    // that we write out all of its lookup results so we don't get a nasty +    // surprise when we try to emit its lookup table. +    for (auto *Child : DC->decls()) +      UpdatingVisibleDecls.push_back(Child); +  }    UpdatingVisibleDecls.push_back(D);  }  void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {    assert(D->isImplicit()); -  if (!(!D->isFromASTFile() && RD->isFromASTFile())) -    return; // Not a source member added to a class from PCH. + +  // We're only interested in cases where a local declaration is added to an +  // imported context. +  if (D->isFromASTFile() || !isImportedDeclContext(Chain, RD)) +    return; +    if (!isa<CXXMethodDecl>(D)) -    return; // We are interested in lazily declared implicit methods. +    return;    // A decl coming from PCH was modified.    assert(RD->isCompleteDefinition()); @@ -5698,42 +5710,6 @@ void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {    DeclUpdates[RD].push_back(DeclUpdate(UPD_CXX_ADDED_IMPLICIT_MEMBER, D));  } -void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, -                                     const ClassTemplateSpecializationDecl *D) { -  // The specializations set is kept in the canonical template. -  TD = TD->getCanonicalDecl(); -  if (!(!D->isFromASTFile() && TD->isFromASTFile())) -    return; // Not a source specialization added to a template from PCH. - -  assert(!WritingAST && "Already writing the AST!"); -  DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, -                                       D)); -} - -void ASTWriter::AddedCXXTemplateSpecialization( -    const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { -  // The specializations set is kept in the canonical template. -  TD = TD->getCanonicalDecl(); -  if (!(!D->isFromASTFile() && TD->isFromASTFile())) -    return; // Not a source specialization added to a template from PCH. - -  assert(!WritingAST && "Already writing the AST!"); -  DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, -                                       D)); -} - -void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, -                                               const FunctionDecl *D) { -  // The specializations set is kept in the canonical template. -  TD = TD->getCanonicalDecl(); -  if (!(!D->isFromASTFile() && TD->isFromASTFile())) -    return; // Not a source specialization added to a template from PCH. - -  assert(!WritingAST && "Already writing the AST!"); -  DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, -                                       D)); -} -  void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) {    assert(!DoneWritingDeclsAndTypes && "Already done writing updates!");    if (!Chain) return; @@ -5807,21 +5783,6 @@ void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,      const_cast<ObjCInterfaceDecl *>(IFD->getDefinition()));  } - -void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop, -                                          const ObjCPropertyDecl *OrigProp, -                                          const ObjCCategoryDecl *ClassExt) { -  const ObjCInterfaceDecl *D = ClassExt->getClassInterface(); -  if (!D) -    return; - -  assert(!WritingAST && "Already writing the AST!"); -  if (!D->isFromASTFile()) -    return; // Declaration not imported from PCH. - -  RewriteDecl(D); -} -  void ASTWriter::DeclarationMarkedUsed(const Decl *D) {    assert(!WritingAST && "Already writing the AST!");    if (!D->isFromASTFile())  | 
