diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp | 1373 |
1 files changed, 667 insertions, 706 deletions
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index 8b68638..128935c 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/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()) |