diff options
Diffstat (limited to 'lib/Serialization')
-rw-r--r-- | lib/Serialization/ASTCommon.cpp | 134 | ||||
-rw-r--r-- | lib/Serialization/ASTCommon.h | 17 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 2238 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 200 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderInternals.h | 128 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 55 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 974 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 78 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 13 | ||||
-rw-r--r-- | lib/Serialization/CMakeLists.txt | 3 | ||||
-rw-r--r-- | lib/Serialization/GeneratePCH.cpp | 10 | ||||
-rw-r--r-- | lib/Serialization/GlobalModuleIndex.cpp | 820 | ||||
-rw-r--r-- | lib/Serialization/Module.cpp | 6 | ||||
-rw-r--r-- | lib/Serialization/ModuleManager.cpp | 316 |
14 files changed, 3495 insertions, 1497 deletions
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 0ec03cf..7bbe6b1 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -12,8 +12,9 @@ //===----------------------------------------------------------------------===// #include "ASTCommon.h" -#include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/AST/DeclObjC.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Serialization/ASTDeserializationListener.h" #include "llvm/ADT/StringExtras.h" using namespace clang; @@ -60,6 +61,14 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break; case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break; case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break; + case BuiltinType::OCLImage1d: ID = PREDEF_TYPE_IMAGE1D_ID; break; + case BuiltinType::OCLImage1dArray: ID = PREDEF_TYPE_IMAGE1D_ARR_ID; break; + case BuiltinType::OCLImage1dBuffer: ID = PREDEF_TYPE_IMAGE1D_BUFF_ID; break; + case BuiltinType::OCLImage2d: ID = PREDEF_TYPE_IMAGE2D_ID; break; + case BuiltinType::OCLImage2dArray: ID = PREDEF_TYPE_IMAGE2D_ARR_ID; break; + case BuiltinType::OCLImage3d: ID = PREDEF_TYPE_IMAGE3D_ID; break; + case BuiltinType::OCLSampler: ID = PREDEF_TYPE_SAMPLER_ID; break; + case BuiltinType::OCLEvent: ID = PREDEF_TYPE_EVENT_ID; break; case BuiltinType::BuiltinFn: ID = PREDEF_TYPE_BUILTIN_FN; break; @@ -78,3 +87,126 @@ unsigned serialization::ComputeHash(Selector Sel) { R = llvm::HashString(II->getName(), R); return R; } + +const DeclContext * +serialization::getDefinitiveDeclContext(const DeclContext *DC) { + switch (DC->getDeclKind()) { + // These entities may have multiple definitions. + case Decl::TranslationUnit: + case Decl::Namespace: + case Decl::LinkageSpec: + return 0; + + // C/C++ tag types can only be defined in one place. + case Decl::Enum: + case Decl::Record: + if (const TagDecl *Def = cast<TagDecl>(DC)->getDefinition()) + return Def; + return 0; + + // FIXME: These can be defined in one place... except special member + // functions and out-of-line definitions. + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + return 0; + + // Each function, method, and block declaration is its own DeclContext. + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::ObjCMethod: + case Decl::Block: + // Objective C categories, category implementations, and class + // implementations can only be defined in one place. + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + return DC; + + case Decl::ObjCProtocol: + if (const ObjCProtocolDecl *Def + = cast<ObjCProtocolDecl>(DC)->getDefinition()) + return Def; + return 0; + + // FIXME: These are defined in one place, but properties in class extensions + // end up being back-patched into the main interface. See + // Sema::HandlePropertyInClassExtension for the offending code. + case Decl::ObjCInterface: + return 0; + + default: + llvm_unreachable("Unhandled DeclContext in AST reader"); + } + + llvm_unreachable("Unhandled decl kind"); +} + +bool serialization::isRedeclarableDeclKind(unsigned Kind) { + switch (static_cast<Decl::Kind>(Kind)) { + case Decl::TranslationUnit: // Special case of a "merged" declaration. + case Decl::Namespace: + case Decl::NamespaceAlias: // FIXME: Not yet redeclarable, but will be. + case Decl::Typedef: + case Decl::TypeAlias: + case Decl::Enum: + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::Var: + case Decl::FunctionTemplate: + case Decl::ClassTemplate: + case Decl::TypeAliasTemplate: + case Decl::ObjCProtocol: + case Decl::ObjCInterface: + case Decl::Empty: + return true; + + // Never redeclarable. + case Decl::UsingDirective: + case Decl::Label: + case Decl::UnresolvedUsingTypename: + case Decl::TemplateTypeParm: + case Decl::EnumConstant: + case Decl::UnresolvedUsingValue: + case Decl::IndirectField: + case Decl::Field: + case Decl::ObjCIvar: + case Decl::ObjCAtDefsField: + case Decl::ImplicitParam: + case Decl::ParmVar: + case Decl::NonTypeTemplateParm: + case Decl::TemplateTemplateParm: + case Decl::Using: + case Decl::UsingShadow: + case Decl::ObjCMethod: + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::ObjCProperty: + case Decl::ObjCCompatibleAlias: + case Decl::LinkageSpec: + case Decl::ObjCPropertyImpl: + case Decl::FileScopeAsm: + case Decl::AccessSpec: + case Decl::Friend: + case Decl::FriendTemplate: + case Decl::StaticAssert: + case Decl::Block: + case Decl::ClassScopeFunctionSpecialization: + case Decl::Import: + case Decl::OMPThreadPrivate: + return false; + } + + llvm_unreachable("Unhandled declaration kind"); +} diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h index eacb39d..76ef904 100644 --- a/lib/Serialization/ASTCommon.h +++ b/lib/Serialization/ASTCommon.h @@ -14,8 +14,8 @@ #ifndef LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H #define LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H -#include "clang/Serialization/ASTBitCodes.h" #include "clang/AST/ASTContext.h" +#include "clang/Serialization/ASTBitCodes.h" namespace clang { @@ -58,6 +58,21 @@ TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) { unsigned ComputeHash(Selector Sel); +/// \brief Retrieve the "definitive" declaration that provides all of the +/// visible entries for the given declaration context, if there is one. +/// +/// The "definitive" declaration is the only place where we need to look to +/// find information about the declarations within the given declaration +/// context. For example, C++ and Objective-C classes, C structs/unions, and +/// Objective-C protocols, categories, and extensions are all defined in a +/// single place in the source code, so they have definitive declarations +/// associated with them. C++ namespaces, on the other hand, can have +/// multiple definitions. +const DeclContext *getDefinitiveDeclContext(const DeclContext *DC); + +/// \brief Determine whether the given declaration kind is redeclarable. +bool isRedeclarableDeclKind(unsigned Kind); + } // namespace serialization } // namespace clang diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index deba302..d984415 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1,4 +1,4 @@ -//===--- ASTReader.cpp - AST File Reader ------------------------*- C++ -*-===// +//===--- ASTReader.cpp - AST File Reader ----------------------------------===// // // The LLVM Compiler Infrastructure // @@ -12,13 +12,8 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTReader.h" -#include "clang/Serialization/ASTDeserializationListener.h" -#include "clang/Serialization/ModuleManager.h" -#include "clang/Serialization/SerializationDiagnostic.h" #include "ASTCommon.h" #include "ASTReaderInternals.h" -#include "clang/Sema/Sema.h" -#include "clang/Sema/Scope.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" @@ -27,37 +22,42 @@ #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/PreprocessorOptions.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/HeaderSearchOptions.h" -#include "clang/Basic/OnDiskHashTable.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" #include "clang/Basic/VersionTuple.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/Sema.h" +#include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/GlobalModuleIndex.h" +#include "clang/Serialization/ModuleManager.h" +#include "clang/Serialization/SerializationDiagnostic.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/system_error.h" #include <algorithm> -#include <iterator> #include <cstdio> -#include <sys/stat.h> +#include <iterator> using namespace clang; using namespace clang::serialization; using namespace clang::serialization::reader; +using llvm::BitstreamCursor; //===----------------------------------------------------------------------===// // PCH validator implementation @@ -109,6 +109,14 @@ static bool checkLanguageOptions(const LangOptions &LangOpts, return true; } + if (ExistingLangOpts.CommentOpts.BlockCommandNames != + LangOpts.CommentOpts.BlockCommandNames) { + if (Diags) + Diags->Report(diag::err_pch_langopt_value_mismatch) + << "block command names"; + return true; + } + return false; } @@ -440,22 +448,32 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, return Result; } -unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) { - return llvm::HashString(StringRef(a.first, a.second)); +unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) { + return llvm::HashString(a); } std::pair<unsigned, unsigned> -ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) { +ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) { using namespace clang::io; unsigned DataLen = ReadUnalignedLE16(d); unsigned KeyLen = ReadUnalignedLE16(d); return std::make_pair(KeyLen, DataLen); } -std::pair<const char*, unsigned> -ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) { +ASTIdentifierLookupTraitBase::internal_key_type +ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) { assert(n >= 2 && d[n-1] == '\0'); - return std::make_pair((const char*) d, n-1); + return StringRef((const char*) d, n-1); +} + +/// \brief Whether the given identifier is "interesting". +static bool isInterestingIdentifier(IdentifierInfo &II) { + return II.isPoisoned() || + II.isExtensionToken() || + II.getObjCOrBuiltinID() || + II.hasRevertedTokenIDToIdentifier() || + II.hadMacroDefinition() || + II.getFETokenInfo<void>(); } IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, @@ -474,12 +492,17 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, // and associate it with the persistent ID. IdentifierInfo *II = KnownII; if (!II) { - II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); + II = &Reader.getIdentifierTable().getOwn(k); KnownII = II; } Reader.SetIdentifierInfo(ID, II); - II->setIsFromAST(); - Reader.markIdentifierUpToDate(II); + if (!II->isFromAST()) { + bool WasInteresting = isInterestingIdentifier(*II); + II->setIsFromAST(); + if (WasInteresting) + II->setChangedSinceDeserialization(); + } + Reader.markIdentifierUpToDate(II); return II; } @@ -493,6 +516,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, Bits >>= 1; bool ExtensionToken = Bits & 0x01; Bits >>= 1; + bool hasSubmoduleMacros = Bits & 0x01; + Bits >>= 1; bool hadMacroDefinition = Bits & 0x01; Bits >>= 1; @@ -503,15 +528,20 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, // the new IdentifierInfo. IdentifierInfo *II = KnownII; if (!II) { - II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); + II = &Reader.getIdentifierTable().getOwn(StringRef(k)); KnownII = II; } Reader.markIdentifierUpToDate(II); - II->setIsFromAST(); + if (!II->isFromAST()) { + bool WasInteresting = isInterestingIdentifier(*II); + II->setIsFromAST(); + if (WasInteresting) + II->setChangedSinceDeserialization(); + } // Set or check the various bits in the IdentifierInfo structure. // Token IDs are read-only. - if (HasRevertedTokenIDToIdentifier) + if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier) II->RevertTokenIDToIdentifier(); II->setObjCOrBuiltinID(ObjCOrBuiltinID); assert(II->isExtensionToken() == ExtensionToken && @@ -526,13 +556,26 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, // If this identifier is a macro, deserialize the macro // definition. if (hadMacroDefinition) { - SmallVector<MacroID, 4> MacroIDs; - while (uint32_t LocalID = ReadUnalignedLE32(d)) { - MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID)); + uint32_t MacroDirectivesOffset = ReadUnalignedLE32(d); + DataLen -= 4; + SmallVector<uint32_t, 8> LocalMacroIDs; + if (hasSubmoduleMacros) { + while (uint32_t LocalMacroID = ReadUnalignedLE32(d)) { + DataLen -= 4; + LocalMacroIDs.push_back(LocalMacroID); + } DataLen -= 4; } - DataLen -= 4; - Reader.setIdentifierIsMacro(II, MacroIDs); + + if (F.Kind == MK_Module) { + for (SmallVectorImpl<uint32_t>::iterator + I = LocalMacroIDs.begin(), E = LocalMacroIDs.end(); I != E; ++I) { + MacroID MacID = Reader.getGlobalMacroID(F, *I); + Reader.addPendingMacroFromModule(II, &F, MacID, F.DirectImportLoc); + } + } else { + Reader.addPendingMacroFromPCH(II, &F, MacroDirectivesOffset); + } } Reader.SetIdentifierInfo(ID, II); @@ -656,12 +699,13 @@ ASTDeclContextNameLookupTrait::ReadData(internal_key_type, unsigned DataLen) { using namespace clang::io; unsigned NumDecls = ReadUnalignedLE16(d); - LE32DeclID *Start = (LE32DeclID *)d; + LE32DeclID *Start = reinterpret_cast<LE32DeclID *>( + const_cast<unsigned char *>(d)); return std::make_pair(Start, Start + NumDecls); } bool ASTReader::ReadDeclContextStorage(ModuleFile &M, - llvm::BitstreamCursor &Cursor, + BitstreamCursor &Cursor, const std::pair<uint64_t, uint64_t> &Offsets, DeclContextInfo &Info) { SavedStreamPosition SavedPosition(Cursor); @@ -670,17 +714,16 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M, Cursor.JumpToBit(Offsets.first); RecordData Record; - const char *Blob; - unsigned BlobLen; + StringRef Blob; unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen); + unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); if (RecCode != DECL_CONTEXT_LEXICAL) { Error("Expected lexical block"); return true; } - Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob); - Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair); + Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob.data()); + Info.NumLexicalDecls = Blob.size() / sizeof(KindDeclIDPair); } // Now the lookup table. @@ -688,18 +731,17 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M, Cursor.JumpToBit(Offsets.second); RecordData Record; - const char *Blob; - unsigned BlobLen; + StringRef Blob; unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen); + unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); if (RecCode != DECL_CONTEXT_VISIBLE) { Error("Expected visible lookup table block"); return true; } Info.NameLookupTableData = ASTDeclContextNameLookupTable::Create( - (const unsigned char *)Blob + Record[0], - (const unsigned char *)Blob, + (const unsigned char *)Blob.data() + Record[0], + (const unsigned char *)Blob.data(), ASTDeclContextNameLookupTrait(*this, M)); } @@ -773,7 +815,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F, bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { using namespace SrcMgr; - llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor; + BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor; // Set the source-location entry cursor to the current position in // the stream. This cursor will be used to read the contents of the @@ -795,35 +837,24 @@ bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { RecordData Record; while (true) { - unsigned Code = SLocEntryCursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (SLocEntryCursor.ReadBlockEnd()) { - Error("error at end of Source Manager block in AST file"); - return true; - } + llvm::BitstreamEntry E = SLocEntryCursor.advanceSkippingSubblocks(); + + switch (E.Kind) { + case llvm::BitstreamEntry::SubBlock: // Handled for us already. + case llvm::BitstreamEntry::Error: + Error("malformed block record in AST file"); + return true; + case llvm::BitstreamEntry::EndBlock: return false; + case llvm::BitstreamEntry::Record: + // The interesting case. + break; } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - SLocEntryCursor.ReadSubBlockID(); - if (SLocEntryCursor.SkipBlock()) { - Error("malformed block record in AST file"); - return true; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - SLocEntryCursor.ReadAbbrevRecord(); - continue; - } - + // Read a record. - const char *BlobStart; - unsigned BlobLen; Record.clear(); - switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + StringRef Blob; + switch (SLocEntryCursor.readRecord(E.ID, Record, &Blob)) { default: // Default behavior: ignore. break; @@ -880,22 +911,19 @@ bool ASTReader::ReadSLocEntry(int ID) { ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second; F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]); - llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; + BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; unsigned BaseOffset = F->SLocEntryBaseOffset; ++NumSLocEntriesRead; - unsigned Code = SLocEntryCursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK || - Code == llvm::bitc::ENTER_SUBBLOCK || - Code == llvm::bitc::DEFINE_ABBREV) { + llvm::BitstreamEntry Entry = SLocEntryCursor.advance(); + if (Entry.Kind != llvm::BitstreamEntry::Record) { Error("incorrectly-formatted source location entry in AST file"); return true; } - + RecordData Record; - const char *BlobStart; - unsigned BlobLen; - switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + StringRef Blob; + switch (SLocEntryCursor.readRecord(Entry.ID, Record, &Blob)) { default: Error("incorrectly-formatted source location entry in AST file"); return true; @@ -905,10 +933,13 @@ bool ASTReader::ReadSLocEntry(int ID) { // we will also try to fail gracefully by setting up the SLocEntry. unsigned InputID = Record[4]; InputFile IF = getInputFile(*F, InputID); - const FileEntry *File = IF.getPointer(); - bool OverriddenBuffer = IF.getInt(); + const FileEntry *File = IF.getFile(); + bool OverriddenBuffer = IF.isOverridden(); - if (!IF.getPointer()) + // Note that we only check if a File was returned. If it was out-of-date + // we have complained but we will continue creating a FileID to recover + // gracefully. + if (!File) return true; SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); @@ -941,8 +972,7 @@ bool ASTReader::ReadSLocEntry(int ID) { ContentCache->ContentsEntry == ContentCache->OrigEntry) { unsigned Code = SLocEntryCursor.ReadCode(); Record.clear(); - unsigned RecCode - = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); + unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob); if (RecCode != SM_SLOC_BUFFER_BLOB) { Error("AST record has invalid code"); @@ -950,8 +980,7 @@ bool ASTReader::ReadSLocEntry(int ID) { } llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), - File->getName()); + = llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), File->getName()); SourceMgr.overrideFileContents(File, Buffer); } @@ -959,15 +988,18 @@ bool ASTReader::ReadSLocEntry(int ID) { } case SM_SLOC_BUFFER_ENTRY: { - const char *Name = BlobStart; + const char *Name = Blob.data(); unsigned Offset = Record[0]; SrcMgr::CharacteristicKind FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); + if (IncludeLoc.isInvalid() && F->Kind == MK_Module) { + IncludeLoc = getImportLocation(F); + } unsigned Code = SLocEntryCursor.ReadCode(); Record.clear(); unsigned RecCode - = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); + = SLocEntryCursor.readRecord(Code, Record, &Blob); if (RecCode != SM_SLOC_BUFFER_BLOB) { Error("AST record has invalid code"); @@ -975,8 +1007,7 @@ bool ASTReader::ReadSLocEntry(int ID) { } llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), - Name); + = llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name); SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID, BaseOffset + Offset, IncludeLoc); break; @@ -997,6 +1028,25 @@ bool ASTReader::ReadSLocEntry(int ID) { return false; } +std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) { + if (ID == 0) + return std::make_pair(SourceLocation(), ""); + + if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { + Error("source location entry ID out-of-range for AST file"); + return std::make_pair(SourceLocation(), ""); + } + + // Find which module file this entry lands in. + ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second; + if (M->Kind != MK_Module) + return std::make_pair(SourceLocation(), ""); + + // FIXME: Can we map this down to a particular submodule? That would be + // ideal. + return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName)); +} + /// \brief Find the location where the module F is imported. SourceLocation ASTReader::getImportLocation(ModuleFile *F) { if (F->ImportLoc.isValid()) @@ -1019,8 +1069,7 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) { /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the /// specified cursor. Read the abbreviations that are at the top of the block /// and then leave the cursor pointing into the block. -bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, - unsigned BlockID) { +bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) { if (Cursor.EnterSubBlock(BlockID)) { Error("malformed block record in AST file"); return Failure; @@ -1039,9 +1088,8 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, } } -void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, - MacroInfo *Hint) { - llvm::BitstreamCursor &Stream = F.MacroCursor; +MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { + BitstreamCursor &Stream = F.MacroCursor; // Keep track of where we are in the stream, then jump back there // after reading this macro. @@ -1052,95 +1100,53 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, SmallVector<IdentifierInfo*, 16> MacroArgs; MacroInfo *Macro = 0; - // RAII object to add the loaded macro information once we're done - // adding tokens. - struct AddLoadedMacroInfoRAII { - Preprocessor &PP; - MacroInfo *Hint; - MacroInfo *MI; - IdentifierInfo *II; - - AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint) - : PP(PP), Hint(Hint), MI(), II() { } - ~AddLoadedMacroInfoRAII( ) { - if (MI) { - // Finally, install the macro. - PP.addLoadedMacroInfo(II, MI, Hint); - } - } - } AddLoadedMacroInfo(PP, Hint); - while (true) { - unsigned Code = Stream.ReadCode(); - switch (Code) { - case llvm::bitc::END_BLOCK: - return; - - case llvm::bitc::ENTER_SUBBLOCK: - // No known subblocks, always skip them. - Stream.ReadSubBlockID(); - if (Stream.SkipBlock()) { - Error("malformed block record in AST file"); - return; - } - continue; - - case llvm::bitc::DEFINE_ABBREV: - Stream.ReadAbbrevRecord(); - continue; - default: break; + // Advance to the next record, but if we get to the end of the block, don't + // pop it (removing all the abbreviations from the cursor) since we want to + // be able to reseek within the block and read entries. + unsigned Flags = BitstreamCursor::AF_DontPopBlockAtEnd; + llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(Flags); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: // Handled for us already. + case llvm::BitstreamEntry::Error: + Error("malformed block record in AST file"); + return Macro; + case llvm::BitstreamEntry::EndBlock: + return Macro; + case llvm::BitstreamEntry::Record: + // The interesting case. + break; } // Read a record. - const char *BlobStart = 0; - unsigned BlobLen = 0; Record.clear(); PreprocessorRecordTypes RecType = - (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart, - BlobLen); + (PreprocessorRecordTypes)Stream.readRecord(Entry.ID, Record); switch (RecType) { + case PP_MACRO_DIRECTIVE_HISTORY: + return Macro; + case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: { // If we already have a macro, that means that we've hit the end // of the definition of the macro we were looking for. We're // done. if (Macro) - return; + return Macro; - IdentifierInfo *II = getLocalIdentifier(F, Record[0]); - if (II == 0) { - Error("macro must have a name in AST file"); - return; - } - - unsigned GlobalID = getGlobalMacroID(F, Record[1]); - - // If this macro has already been loaded, don't do so again. - if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS]) - return; - - SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]); - unsigned NextIndex = 3; + unsigned NextIndex = 1; // Skip identifier ID. + SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]); SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); - MacroInfo *MI = PP.AllocateMacroInfo(Loc); - - // Record this macro. - MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI; - - SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex); - if (UndefLoc.isValid()) - MI->setUndefLoc(UndefLoc); - + MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID); + MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex)); MI->setIsUsed(Record[NextIndex++]); - MI->setIsFromAST(); - - bool IsPublic = Record[NextIndex++]; - MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex)); if (RecType == PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. bool isC99VarArgs = Record[NextIndex++]; bool isGNUVarArgs = Record[NextIndex++]; + bool hasCommaPasting = Record[NextIndex++]; MacroArgs.clear(); unsigned NumArgs = Record[NextIndex++]; for (unsigned i = 0; i != NumArgs; ++i) @@ -1150,65 +1156,11 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, MI->setIsFunctionLike(); if (isC99VarArgs) MI->setIsC99Varargs(); if (isGNUVarArgs) MI->setIsGNUVarargs(); + if (hasCommaPasting) MI->setHasCommaPasting(); MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), PP.getPreprocessorAllocator()); } - if (DeserializationListener) - DeserializationListener->MacroRead(GlobalID, MI); - - // If an update record marked this as undefined, do so now. - // FIXME: Only if the submodule this update came from is visible? - MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID); - if (Update != MacroUpdates.end()) { - if (MI->getUndefLoc().isInvalid()) { - for (unsigned I = 0, N = Update->second.size(); I != N; ++I) { - bool Hidden = false; - if (unsigned SubmoduleID = Update->second[I].first) { - if (Module *Owner = getSubmodule(SubmoduleID)) { - if (Owner->NameVisibility == Module::Hidden) { - // Note that this #undef is hidden. - Hidden = true; - - // Record this hiding for later. - HiddenNamesMap[Owner].push_back( - HiddenName(II, MI, Update->second[I].second.UndefLoc)); - } - } - } - - if (!Hidden) { - MI->setUndefLoc(Update->second[I].second.UndefLoc); - if (PPMutationListener *Listener = PP.getPPMutationListener()) - Listener->UndefinedMacro(MI); - break; - } - } - } - MacroUpdates.erase(Update); - } - - // Determine whether this macro definition is visible. - bool Hidden = !MI->isPublic(); - if (!Hidden && GlobalSubmoduleID) { - if (Module *Owner = getSubmodule(GlobalSubmoduleID)) { - if (Owner->NameVisibility == Module::Hidden) { - // The owning module is not visible, and this macro definition - // should not be, either. - Hidden = true; - - // Note that this macro definition was hidden because its owning - // module is not yet visible. - HiddenNamesMap[Owner].push_back(HiddenName(II, MI)); - } - } - } - MI->setHidden(Hidden); - - // Make sure we install the macro once we're done. - AddLoadedMacroInfo.MI = MI; - AddLoadedMacroInfo.II = II; - // Remember that we saw this macro last so that we add the tokens that // form its body to it. Macro = MI; @@ -1219,8 +1171,12 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, PreprocessedEntityID GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]); PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); - PPRec.RegisterMacroDefinition(Macro, - PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true)); + PreprocessingRecord::PPEntityID + PPID = PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true); + MacroDefinition *PPDef = + cast_or_null<MacroDefinition>(PPRec.getPreprocessedEntity(PPID)); + if (PPDef) + PPRec.RegisterMacroDefinition(Macro, PPDef); } ++NumMacrosRead; @@ -1257,37 +1213,49 @@ ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const return LocalID + I->second; } -unsigned HeaderFileInfoTrait::ComputeHash(const char *path) { - return llvm::HashString(llvm::sys::path::filename(path)); +unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) { + return llvm::hash_combine(ikey.Size, ikey.ModTime); } HeaderFileInfoTrait::internal_key_type -HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; } +HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) { + internal_key_type ikey = { FE->getSize(), FE->getModificationTime(), + FE->getName() }; + return ikey; +} -bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) { - if (strcmp(a, b) == 0) - return true; - - if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b)) +bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) { + if (a.Size != b.Size || a.ModTime != b.ModTime) return false; - // Determine whether the actual files are equivalent. - bool Result = false; - if (llvm::sys::fs::equivalent(a, b, Result)) - return false; + if (strcmp(a.Filename, b.Filename) == 0) + return true; - return Result; + // Determine whether the actual files are equivalent. + FileManager &FileMgr = Reader.getFileManager(); + const FileEntry *FEA = FileMgr.getFile(a.Filename); + const FileEntry *FEB = FileMgr.getFile(b.Filename); + return (FEA && FEA == FEB); } std::pair<unsigned, unsigned> HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); unsigned DataLen = (unsigned) *d++; - return std::make_pair(KeyLen + 1, DataLen); + return std::make_pair(KeyLen, DataLen); } - + +HeaderFileInfoTrait::internal_key_type +HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) { + internal_key_type ikey; + ikey.Size = off_t(clang::io::ReadUnalignedLE64(d)); + ikey.ModTime = time_t(clang::io::ReadUnalignedLE64(d)); + ikey.Filename = (const char *)d; + return ikey; +} + HeaderFileInfoTrait::data_type -HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, +HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, unsigned DataLen) { const unsigned char *End = d + DataLen; using namespace clang::io; @@ -1308,6 +1276,21 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); } + if (d != End) { + uint32_t LocalSMID = ReadUnalignedLE32(d); + if (LocalSMID) { + // This header is part of a module. Associate it with the module to enable + // implicit module import. + SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID); + Module *Mod = Reader.getSubmodule(GlobalSMID); + HFI.isModuleHeader = true; + FileManager &FileMgr = Reader.getFileManager(); + ModuleMap &ModMap = + Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), /*Excluded=*/false); + } + } + assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); (void)End; @@ -1316,10 +1299,19 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, return HFI; } -void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){ - II->setHadMacroDefinition(true); +void ASTReader::addPendingMacroFromModule(IdentifierInfo *II, + ModuleFile *M, + GlobalMacroID GMacID, + SourceLocation ImportLoc) { assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); - PendingMacroIDs[II].append(IDs.begin(), IDs.end()); + PendingMacroIDs[II].push_back(PendingMacroInfo(M, GMacID, ImportLoc)); +} + +void ASTReader::addPendingMacroFromPCH(IdentifierInfo *II, + ModuleFile *M, + uint64_t MacroDirectivesOffset) { + assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); + PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset)); } void ASTReader::ReadDefinedMacros() { @@ -1328,54 +1320,46 @@ void ASTReader::ReadDefinedMacros() { for (ModuleReverseIterator I = ModuleMgr.rbegin(), E = ModuleMgr.rend(); I != E; ++I) { - llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor; + BitstreamCursor &MacroCursor = (*I)->MacroCursor; // If there was no preprocessor block, skip this file. if (!MacroCursor.getBitStreamReader()) continue; - llvm::BitstreamCursor Cursor = MacroCursor; + BitstreamCursor Cursor = MacroCursor; Cursor.JumpToBit((*I)->MacroStartOffset); RecordData Record; while (true) { - unsigned Code = Cursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) - break; - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - Cursor.ReadSubBlockID(); - if (Cursor.SkipBlock()) { - Error("malformed block record in AST file"); - return; + llvm::BitstreamEntry E = Cursor.advanceSkippingSubblocks(); + + switch (E.Kind) { + case llvm::BitstreamEntry::SubBlock: // Handled for us already. + case llvm::BitstreamEntry::Error: + Error("malformed block record in AST file"); + return; + case llvm::BitstreamEntry::EndBlock: + goto NextCursor; + + case llvm::BitstreamEntry::Record: + Record.clear(); + switch (Cursor.readRecord(E.ID, Record)) { + default: // Default behavior: ignore. + break; + + case PP_MACRO_OBJECT_LIKE: + case PP_MACRO_FUNCTION_LIKE: + getLocalIdentifier(**I, Record[0]); + break; + + case PP_TOKEN: + // Ignore tokens. + break; } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Cursor.ReadAbbrevRecord(); - continue; - } - - // Read a record. - const char *BlobStart; - unsigned BlobLen; - Record.clear(); - switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: // Default behavior: ignore. - break; - - case PP_MACRO_OBJECT_LIKE: - case PP_MACRO_FUNCTION_LIKE: - getLocalIdentifier(**I, Record[0]); - break; - - case PP_TOKEN: - // Ignore tokens. break; } } + NextCursor: ; } } @@ -1384,10 +1368,20 @@ namespace { class IdentifierLookupVisitor { StringRef Name; unsigned PriorGeneration; + unsigned &NumIdentifierLookups; + unsigned &NumIdentifierLookupHits; IdentifierInfo *Found; + public: - IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration) - : Name(Name), PriorGeneration(PriorGeneration), Found() { } + IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration, + unsigned &NumIdentifierLookups, + unsigned &NumIdentifierLookupHits) + : Name(Name), PriorGeneration(PriorGeneration), + NumIdentifierLookups(NumIdentifierLookups), + NumIdentifierLookupHits(NumIdentifierLookupHits), + Found() + { + } static bool visit(ModuleFile &M, void *UserData) { IdentifierLookupVisitor *This @@ -1396,7 +1390,7 @@ namespace { // If we've already searched this module file, skip it now. if (M.Generation <= This->PriorGeneration) return true; - + ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; if (!IdTable) @@ -1404,16 +1398,15 @@ namespace { ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M, This->Found); - - std::pair<const char*, unsigned> Key(This->Name.begin(), - This->Name.size()); - ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Trait); + ++This->NumIdentifierLookups; + ASTIdentifierLookupTable::iterator Pos = IdTable->find(This->Name,&Trait); if (Pos == IdTable->end()) return false; // Dereferencing the iterator has the effect of building the // IdentifierInfo node and populating it with the various // declarations it needs. + ++This->NumIdentifierLookupHits; This->Found = *Pos; return true; } @@ -1431,9 +1424,21 @@ void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { unsigned PriorGeneration = 0; if (getContext().getLangOpts().Modules) PriorGeneration = IdentifierGeneration[&II]; - - IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration); - ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); + + // If there is a global index, look there first to determine which modules + // provably do not have any results for this identifier. + GlobalModuleIndex::HitSet Hits; + GlobalModuleIndex::HitSet *HitsPtr = 0; + if (!loadGlobalIndex()) { + if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) { + HitsPtr = &Hits; + } + } + + IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration, + NumIdentifierLookups, + NumIdentifierLookupHits); + ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr); markIdentifierUpToDate(&II); } @@ -1448,27 +1453,196 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) { IdentifierGeneration[II] = CurrentGeneration; } -llvm::PointerIntPair<const FileEntry *, 1, bool> -ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { +void ASTReader::resolvePendingMacro(IdentifierInfo *II, + const PendingMacroInfo &PMInfo) { + assert(II); + + if (PMInfo.M->Kind != MK_Module) { + installPCHMacroDirectives(II, *PMInfo.M, + PMInfo.PCHMacroData.MacroDirectivesOffset); + return; + } + + // Module Macro. + + GlobalMacroID GMacID = PMInfo.ModuleMacroData.GMacID; + SourceLocation ImportLoc = + SourceLocation::getFromRawEncoding(PMInfo.ModuleMacroData.ImportLoc); + + assert(GMacID); + // If this macro has already been loaded, don't do so again. + if (MacrosLoaded[GMacID - NUM_PREDEF_MACRO_IDS]) + return; + + MacroInfo *MI = getMacro(GMacID); + SubmoduleID SubModID = MI->getOwningModuleID(); + MacroDirective *MD = PP.AllocateDefMacroDirective(MI, ImportLoc, + /*isImported=*/true); + + // Determine whether this macro definition is visible. + bool Hidden = false; + Module *Owner = 0; + if (SubModID) { + if ((Owner = getSubmodule(SubModID))) { + if (Owner->NameVisibility == Module::Hidden) { + // The owning module is not visible, and this macro definition + // should not be, either. + Hidden = true; + + // Note that this macro definition was hidden because its owning + // module is not yet visible. + HiddenNamesMap[Owner].push_back(HiddenName(II, MD)); + } + } + } + + if (!Hidden) + installImportedMacro(II, MD, Owner); +} + +void ASTReader::installPCHMacroDirectives(IdentifierInfo *II, + ModuleFile &M, uint64_t Offset) { + assert(M.Kind != MK_Module); + + BitstreamCursor &Cursor = M.MacroCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); + + llvm::BitstreamEntry Entry = + Cursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd); + if (Entry.Kind != llvm::BitstreamEntry::Record) { + Error("malformed block record in AST file"); + return; + } + + RecordData Record; + PreprocessorRecordTypes RecType = + (PreprocessorRecordTypes)Cursor.readRecord(Entry.ID, Record); + if (RecType != PP_MACRO_DIRECTIVE_HISTORY) { + Error("malformed block record in AST file"); + return; + } + + // Deserialize the macro directives history in reverse source-order. + MacroDirective *Latest = 0, *Earliest = 0; + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + MacroDirective *MD = 0; + SourceLocation Loc = ReadSourceLocation(M, Record, Idx); + MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++]; + switch (K) { + case MacroDirective::MD_Define: { + GlobalMacroID GMacID = getGlobalMacroID(M, Record[Idx++]); + MacroInfo *MI = getMacro(GMacID); + bool isImported = Record[Idx++]; + bool isAmbiguous = Record[Idx++]; + DefMacroDirective *DefMD = + PP.AllocateDefMacroDirective(MI, Loc, isImported); + DefMD->setAmbiguous(isAmbiguous); + MD = DefMD; + break; + } + case MacroDirective::MD_Undefine: + MD = PP.AllocateUndefMacroDirective(Loc); + break; + case MacroDirective::MD_Visibility: { + bool isPublic = Record[Idx++]; + MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic); + break; + } + } + + if (!Latest) + Latest = MD; + if (Earliest) + Earliest->setPrevious(MD); + Earliest = MD; + } + + PP.setLoadedMacroDirective(II, Latest); +} + +/// \brief For the given macro definitions, check if they are both in system +/// modules and if one of the two is in the clang builtin headers. +static bool isSystemAndClangMacro(MacroInfo *PrevMI, MacroInfo *NewMI, + Module *NewOwner, ASTReader &Reader) { + assert(PrevMI && NewMI); + if (!NewOwner) + return false; + Module *PrevOwner = 0; + if (SubmoduleID PrevModID = PrevMI->getOwningModuleID()) + PrevOwner = Reader.getSubmodule(PrevModID); + if (!PrevOwner) + return false; + if (PrevOwner == NewOwner) + return false; + if (!PrevOwner->IsSystem || !NewOwner->IsSystem) + return false; + + SourceManager &SM = Reader.getSourceManager(); + FileID PrevFID = SM.getFileID(PrevMI->getDefinitionLoc()); + FileID NewFID = SM.getFileID(NewMI->getDefinitionLoc()); + const FileEntry *PrevFE = SM.getFileEntryForID(PrevFID); + const FileEntry *NewFE = SM.getFileEntryForID(NewFID); + if (PrevFE == 0 || NewFE == 0) + return false; + + Preprocessor &PP = Reader.getPreprocessor(); + ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); + const DirectoryEntry *BuiltinDir = ModMap.getBuiltinIncludeDir(); + + return (PrevFE->getDir() == BuiltinDir) != (NewFE->getDir() == BuiltinDir); +} + +void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD, + Module *Owner) { + assert(II && MD); + + DefMacroDirective *DefMD = cast<DefMacroDirective>(MD); + MacroDirective *Prev = PP.getMacroDirective(II); + if (Prev) { + MacroDirective::DefInfo PrevDef = Prev->getDefinition(); + MacroInfo *PrevMI = PrevDef.getMacroInfo(); + MacroInfo *NewMI = DefMD->getInfo(); + if (NewMI != PrevMI && !PrevMI->isIdenticalTo(*NewMI, PP, + /*Syntactically=*/true)) { + // Before marking the macros as ambiguous, check if this is a case where + // the system macro uses a not identical definition compared to a macro + // from the clang headers. For example: + // #define LONG_MAX __LONG_MAX__ (clang's limits.h) + // #define LONG_MAX 0x7fffffffffffffffL (system's limits.h) + // in which case don't mark them to avoid the "ambiguous macro expansion" + // warning. + // FIXME: This should go away if the system headers get "fixed" to use + // identical definitions. + if (!isSystemAndClangMacro(PrevMI, NewMI, Owner, *this)) { + PrevDef.getDirective()->setAmbiguous(true); + DefMD->setAmbiguous(true); + } + } + } + + PP.appendMacroDirective(II, MD); +} + +InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // If this ID is bogus, just return an empty input file. if (ID == 0 || ID > F.InputFilesLoaded.size()) return InputFile(); // If we've already loaded this input file, return it. - if (F.InputFilesLoaded[ID-1].getPointer()) + if (F.InputFilesLoaded[ID-1].getFile()) return F.InputFilesLoaded[ID-1]; // Go find this input file. - llvm::BitstreamCursor &Cursor = F.InputFilesCursor; + BitstreamCursor &Cursor = F.InputFilesCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(F.InputFileOffsets[ID-1]); unsigned Code = Cursor.ReadCode(); RecordData Record; - const char *BlobStart = 0; - unsigned BlobLen = 0; - switch ((InputFileRecordTypes)Cursor.ReadRecord(Code, Record, - &BlobStart, &BlobLen)) { + StringRef Blob; + switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) { case INPUT_FILE: { unsigned StoredID = Record[0]; assert(ID == StoredID && "Bogus stored ID or offset"); @@ -1478,7 +1652,7 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { bool Overridden = (bool)Record[3]; // Get the file entry for this input file. - StringRef OrigFilename(BlobStart, BlobLen); + StringRef OrigFilename = Blob; std::string Filename = OrigFilename; MaybeAddSystemRootToFilename(F, Filename); const FileEntry *File @@ -1511,17 +1685,15 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { } return InputFile(); } - - // Note that we've loaded this input file. - F.InputFilesLoaded[ID-1] = InputFile(File, Overridden); - + // Check if there was a request to override the contents of the file // that was part of the precompiled header. Overridding such a file // can lead to problems when lexing using the source locations from the // PCH. SourceManager &SM = getSourceManager(); if (!Overridden && SM.isFileOverridden(File)) { - Error(diag::err_fe_pch_file_overridden, Filename); + if (Complain) + Error(diag::err_fe_pch_file_overridden, Filename); // After emitting the diagnostic, recover by disabling the override so // that the original file will be used. SM.disableFileContentsOverride(File); @@ -1532,33 +1704,29 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { StoredSize, StoredTime); } - // For an overridden file, there is nothing to validate. - if (Overridden) - return InputFile(File, Overridden); - - // The stat info from the FileEntry came from the cached stat - // info of the PCH, so we cannot trust it. - struct stat StatBuf; - if (::stat(File->getName(), &StatBuf) != 0) { - StatBuf.st_size = File->getSize(); - StatBuf.st_mtime = File->getModificationTime(); - } + bool IsOutOfDate = false; - if ((StoredSize != StatBuf.st_size + // For an overridden file, there is nothing to validate. + if (!Overridden && (StoredSize != File->getSize() #if !defined(LLVM_ON_WIN32) // In our regression testing, the Windows file system seems to // have inconsistent modification times that sometimes // erroneously trigger this error-handling path. - || StoredTime != StatBuf.st_mtime + || StoredTime != File->getModificationTime() #endif )) { - if (Complain) - Error(diag::err_fe_pch_file_modified, Filename); - - return InputFile(); + if (Complain) { + Error(diag::err_fe_pch_file_modified, Filename, F.FileName); + } + + IsOutOfDate = true; } - return InputFile(File, Overridden); + InputFile IF = InputFile(File, Overridden, IsOutOfDate); + + // Note that we've loaded this input file. + F.InputFilesLoaded[ID-1] = IF; + return IF; } } @@ -1609,9 +1777,9 @@ void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M, ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F, - llvm::SmallVectorImpl<ModuleFile *> &Loaded, + SmallVectorImpl<ImportedModule> &Loaded, unsigned ClientLoadCapabilities) { - llvm::BitstreamCursor &Stream = F.Stream; + BitstreamCursor &Stream = F.Stream; if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { Error("malformed block record in AST file"); @@ -1620,27 +1788,29 @@ ASTReader::ReadControlBlock(ModuleFile &F, // Read all of the records and blocks in the control block. RecordData Record; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - Error("error at end of control block in AST file"); - return Failure; - } - - // Validate all of the input files. + while (1) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + Error("malformed block record in AST file"); + return Failure; + case llvm::BitstreamEntry::EndBlock: + // Validate all of the non-system input files. if (!DisableValidation) { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; - for (unsigned I = 0, N = Record[0]; I < N; ++I) - if (!getInputFile(F, I+1, Complain).getPointer()) + // All user input files reside at the index range [0, Record[1]). + // Record is the one from INPUT_FILE_OFFSETS. + for (unsigned I = 0, N = Record[1]; I < N; ++I) { + InputFile IF = getInputFile(F, I+1, Complain); + if (!IF.getFile() || IF.isOutOfDate()) return OutOfDate; + } } - return Success; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - switch (Stream.ReadSubBlockID()) { + + case llvm::BitstreamEntry::SubBlock: + switch (Entry.ID) { case INPUT_FILES_BLOCK_ID: F.InputFilesCursor = Stream; if (Stream.SkipBlock() || // Skip with the main cursor @@ -1650,28 +1820,24 @@ ASTReader::ReadControlBlock(ModuleFile &F, return Failure; } continue; - + default: - if (!Stream.SkipBlock()) - continue; - break; + if (Stream.SkipBlock()) { + Error("malformed block record in AST file"); + return Failure; + } + continue; } - - Error("malformed block record in AST file"); - return Failure; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; + + case llvm::BitstreamEntry::Record: + // The interesting case. + break; } // Read and process a record. Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record, - &BlobStart, &BlobLen)) { + StringRef Blob; + switch ((ControlRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) { case METADATA: { if (Record[0] != VERSION_MAJOR && !DisableValidation) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) @@ -1689,7 +1855,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, F.RelocatablePCH = Record[4]; const std::string &CurBranch = getClangFullRepositoryVersion(); - StringRef ASTBranch(BlobStart, BlobLen); + StringRef ASTBranch = Blob; if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; @@ -1704,16 +1870,25 @@ ASTReader::ReadControlBlock(ModuleFile &F, while (Idx < N) { // Read information about the AST file. ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; + // The import location will be the local one for now; we will adjust + // all import locations of module imports after the global source + // location info are setup. + SourceLocation ImportLoc = + SourceLocation::getFromRawEncoding(Record[Idx++]); + off_t StoredSize = (off_t)Record[Idx++]; + time_t StoredModTime = (time_t)Record[Idx++]; unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, Record.begin() + Idx + Length); Idx += Length; // Load the AST file. - switch(ReadASTCore(ImportedFile, ImportedKind, &F, Loaded, + switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded, + StoredSize, StoredModTime, ClientLoadCapabilities)) { case Failure: return Failure; // If we have to ignore the dependency, we'll have to ignore this too. + case Missing: case OutOfDate: return OutOfDate; case VersionMismatch: return VersionMismatch; case ConfigurationMismatch: return ConfigurationMismatch; @@ -1781,28 +1956,29 @@ ASTReader::ReadControlBlock(ModuleFile &F, case ORIGINAL_FILE: F.OriginalSourceFileID = FileID::get(Record[0]); - F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen); + F.ActualOriginalSourceFileName = Blob; F.OriginalSourceFileName = F.ActualOriginalSourceFileName; MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName); break; + case ORIGINAL_FILE_ID: + F.OriginalSourceFileID = FileID::get(Record[0]); + break; + case ORIGINAL_PCH_DIR: - F.OriginalDir.assign(BlobStart, BlobLen); + F.OriginalDir = Blob; break; case INPUT_FILE_OFFSETS: - F.InputFileOffsets = (const uint32_t *)BlobStart; + F.InputFileOffsets = (const uint32_t *)Blob.data(); F.InputFilesLoaded.resize(Record[0]); break; } } - - Error("premature end of bitstream in AST file"); - return Failure; } bool ASTReader::ReadASTBlock(ModuleFile &F) { - llvm::BitstreamCursor &Stream = F.Stream; + BitstreamCursor &Stream = F.Stream; if (Stream.EnterSubBlock(AST_BLOCK_ID)) { Error("malformed block record in AST file"); @@ -1811,23 +1987,28 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { // Read all of the records and blocks for the AST file. RecordData Record; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - Error("error at end of module block in AST file"); - return true; - } - + while (1) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + Error("error at end of module block in AST file"); + return true; + case llvm::BitstreamEntry::EndBlock: { + // Outside of C++, we do not store a lookup map for the translation unit. + // Instead, mark it as needing a lookup map to be built if this module + // contains any declarations lexically within it (which it always does!). + // This usually has no cost, since we very rarely need the lookup map for + // the translation unit outside C++. DeclContext *DC = Context.getTranslationUnitDecl(); - if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage()) + if (DC->hasExternalLexicalStorage() && + !getContext().getLangOpts().CPlusPlus) DC->setMustBuildLookupTable(); - + return false; } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - switch (Stream.ReadSubBlockID()) { + case llvm::BitstreamEntry::SubBlock: + switch (Entry.ID) { case DECLTYPES_BLOCK_ID: // We lazily load the decls block, but we want to set up the // DeclsCursor cursor to point into it. Clone our current bitcode @@ -1841,19 +2022,19 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { return true; } break; - + case DECL_UPDATES_BLOCK_ID: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); return true; } break; - + case PREPROCESSOR_BLOCK_ID: F.MacroCursor = Stream; if (!PP.getExternalSource()) PP.setExternalSource(this); - + if (Stream.SkipBlock() || ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) { Error("malformed block record in AST file"); @@ -1861,20 +2042,20 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { } F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo(); break; - + case PREPROCESSOR_DETAIL_BLOCK_ID: F.PreprocessorDetailCursor = Stream; if (Stream.SkipBlock() || - ReadBlockAbbrevs(F.PreprocessorDetailCursor, + ReadBlockAbbrevs(F.PreprocessorDetailCursor, PREPROCESSOR_DETAIL_BLOCK_ID)) { - Error("malformed preprocessor detail record in AST file"); - return true; - } + Error("malformed preprocessor detail record in AST file"); + return true; + } F.PreprocessorDetailStartOffset - = F.PreprocessorDetailCursor.GetCurrentBitNo(); - + = F.PreprocessorDetailCursor.GetCurrentBitNo(); + if (!PP.getPreprocessingRecord()) - PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false); + PP.createPreprocessingRecord(); if (!PP.getPreprocessingRecord()->getExternalSource()) PP.getPreprocessingRecord()->SetExternalSource(*this); break; @@ -1883,14 +2064,14 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { if (ReadSourceManagerBlock(F)) return true; break; - + case SUBMODULE_BLOCK_ID: if (ReadSubmoduleBlock(F)) return true; break; - + case COMMENTS_BLOCK_ID: { - llvm::BitstreamCursor C = Stream; + BitstreamCursor C = Stream; if (Stream.SkipBlock() || ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) { Error("malformed comments block in AST file"); @@ -1899,27 +2080,25 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { CommentsCursors.push_back(std::make_pair(C, &F)); break; } - + default: - if (!Stream.SkipBlock()) - break; - Error("malformed block record in AST file"); - return true; + if (Stream.SkipBlock()) { + Error("malformed block record in AST file"); + return true; + } + break; } continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; + + case llvm::BitstreamEntry::Record: + // The interesting case. + break; } // Read and process a record. Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - switch ((ASTRecordTypes)Stream.ReadRecord(Code, Record, - &BlobStart, &BlobLen)) { + StringRef Blob; + switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) { default: // Default behavior: ignore. break; @@ -1928,7 +2107,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { Error("duplicate TYPE_OFFSET record in AST file"); return true; } - F.TypeOffsets = (const uint32_t *)BlobStart; + F.TypeOffsets = (const uint32_t *)Blob.data(); F.LocalNumTypes = Record[0]; unsigned LocalBaseTypeIndex = Record[1]; F.BaseTypeIndex = getTotalNumTypes(); @@ -1952,7 +2131,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { Error("duplicate DECL_OFFSET record in AST file"); return true; } - F.DeclOffsets = (const DeclOffset *)BlobStart; + F.DeclOffsets = (const DeclOffset *)Blob.data(); F.LocalNumDecls = Record[0]; unsigned LocalBaseDeclID = Record[1]; F.BaseDeclID = getTotalNumDecls(); @@ -1980,9 +2159,9 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { case TU_UPDATE_LEXICAL: { DeclContext *TU = Context.getTranslationUnitDecl(); DeclContextInfo &Info = F.DeclContextInfos[TU]; - Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart); + Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(Blob.data()); Info.NumLexicalDecls - = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair)); + = static_cast<unsigned int>(Blob.size() / sizeof(KindDeclIDPair)); TU->setHasExternalLexicalStorage(true); break; } @@ -1992,8 +2171,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { serialization::DeclID ID = ReadDeclID(F, Record, Idx); ASTDeclContextNameLookupTable *Table = ASTDeclContextNameLookupTable::Create( - (const unsigned char *)BlobStart + Record[Idx++], - (const unsigned char *)BlobStart, + (const unsigned char *)Blob.data() + Record[Idx++], + (const unsigned char *)Blob.data(), ASTDeclContextNameLookupTrait(*this, F)); if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU? DeclContext *TU = Context.getTranslationUnitDecl(); @@ -2005,7 +2184,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { } case IDENTIFIER_TABLE: - F.IdentifierTableData = BlobStart; + F.IdentifierTableData = Blob.data(); if (Record[0]) { F.IdentifierLookupTable = ASTIdentifierLookupTable::Create( @@ -2022,7 +2201,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { Error("duplicate IDENTIFIER_OFFSET record in AST file"); return true; } - F.IdentifierOffsets = (const uint32_t *)BlobStart; + F.IdentifierOffsets = (const uint32_t *)Blob.data(); F.LocalNumIdentifiers = Record[0]; unsigned LocalBaseIdentifierID = Record[1]; F.BaseIdentifierID = getTotalNumIdentifiers(); @@ -2051,8 +2230,24 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { break; case SPECIAL_TYPES: - for (unsigned I = 0, N = Record.size(); I != N; ++I) - SpecialTypes.push_back(getGlobalTypeID(F, Record[I])); + if (SpecialTypes.empty()) { + for (unsigned I = 0, N = Record.size(); I != N; ++I) + SpecialTypes.push_back(getGlobalTypeID(F, Record[I])); + break; + } + + if (SpecialTypes.size() != Record.size()) { + Error("invalid special-types record"); + return true; + } + + for (unsigned I = 0, N = Record.size(); I != N; ++I) { + serialization::TypeID ID = getGlobalTypeID(F, Record[I]); + if (!SpecialTypes[I]) + SpecialTypes[I] = ID; + // FIXME: If ID && SpecialTypes[I] != ID, do we need a separate + // merge step? + } break; case STATISTICS: @@ -2094,13 +2289,13 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { } break; - case LOCALLY_SCOPED_EXTERNAL_DECLS: + case LOCALLY_SCOPED_EXTERN_C_DECLS: for (unsigned I = 0, N = Record.size(); I != N; ++I) - LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I])); + LocallyScopedExternCDecls.push_back(getGlobalDeclID(F, Record[I])); break; case SELECTOR_OFFSETS: { - F.SelectorOffsets = (const uint32_t *)BlobStart; + F.SelectorOffsets = (const uint32_t *)Blob.data(); F.LocalNumSelectors = Record[0]; unsigned LocalBaseSelectorID = Record[1]; F.BaseSelectorID = getTotalNumSelectors(); @@ -2122,7 +2317,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { } case METHOD_POOL: - F.SelectorLookupTableData = (const unsigned char *)BlobStart; + F.SelectorLookupTableData = (const unsigned char *)Blob.data(); if (Record[0]) F.SelectorLookupTable = ASTSelectorLookupTable::Create( @@ -2149,12 +2344,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { break; case FILE_SORTED_DECLS: - F.FileSortedDecls = (const DeclID *)BlobStart; + F.FileSortedDecls = (const DeclID *)Blob.data(); F.NumFileSortedDecls = Record[0]; break; case SOURCE_LOCATION_OFFSETS: { - F.SLocEntryOffsets = (const uint32_t *)BlobStart; + F.SLocEntryOffsets = (const uint32_t *)Blob.data(); F.LocalNumSLocEntries = Record[0]; unsigned SLocSpaceSize = Record[1]; llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = @@ -2187,8 +2382,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { case MODULE_OFFSET_MAP: { // Additional remapping information. - const unsigned char *Data = (const unsigned char*)BlobStart; - const unsigned char *DataEnd = Data + BlobLen; + const unsigned char *Data = (const unsigned char*)Blob.data(); + const unsigned char *DataEnd = Data + Blob.size(); // Continuous range maps we may be updating in our module. ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap); @@ -2324,15 +2519,15 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { break; case PPD_ENTITIES_OFFSETS: { - F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart; - assert(BlobLen % sizeof(PPEntityOffset) == 0); - F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset); + F.PreprocessedEntityOffsets = (const PPEntityOffset *)Blob.data(); + assert(Blob.size() % sizeof(PPEntityOffset) == 0); + F.NumPreprocessedEntities = Blob.size() / sizeof(PPEntityOffset); unsigned LocalBasePreprocessedEntityID = Record[0]; unsigned StartingID; if (!PP.getPreprocessingRecord()) - PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false); + PP.createPreprocessingRecord(); if (!PP.getPreprocessingRecord()->getExternalSource()) PP.getPreprocessingRecord()->SetExternalSource(*this); StartingID @@ -2384,7 +2579,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { } F.LocalNumObjCCategoriesInMap = Record[0]; - F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)BlobStart; + F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data(); break; } @@ -2399,7 +2594,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { } F.LocalNumCXXBaseSpecifiers = Record[0]; - F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart; + F.CXXBaseSpecifiersOffsets = (const uint32_t *)Blob.data(); NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers; break; } @@ -2421,9 +2616,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { break; case HEADER_SEARCH_TABLE: { - F.HeaderFileInfoTableData = BlobStart; + F.HeaderFileInfoTableData = Blob.data(); F.LocalNumHeaderFileInfos = Record[1]; - F.HeaderFileFrameworkStrings = BlobStart + Record[2]; if (Record[0]) { F.HeaderFileInfoTable = HeaderFileInfoLookupTable::Create( @@ -2431,7 +2625,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { (const unsigned char *)F.HeaderFileInfoTableData, HeaderFileInfoTrait(*this, F, &PP.getHeaderSearchInfo(), - BlobStart + Record[2])); + Blob.data() + Record[2])); PP.getHeaderSearchInfo().SetExternalSource(this); if (!PP.getHeaderSearchInfo().getExternalLookup()) @@ -2459,7 +2653,24 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { for (unsigned I = 0, N = Record.size(); I != N; ++I) KnownNamespaces.push_back(getGlobalDeclID(F, Record[I])); break; - + + case UNDEFINED_BUT_USED: + if (UndefinedButUsed.size() % 2 != 0) { + Error("Invalid existing UndefinedButUsed"); + return true; + } + + if (Record.size() % 2 != 0) { + Error("invalid undefined-but-used record"); + return true; + } + for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { + UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++])); + UndefinedButUsed.push_back( + ReadSourceLocation(F, Record, I).getRawEncoding()); + } + break; + case IMPORTED_MODULES: { if (F.Kind != MK_Module) { // If we aren't loading a module (which has its own exports), make @@ -2485,7 +2696,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { } F.LocalNumRedeclarationsInMap = Record[0]; - F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart; + F.RedeclarationsMap = (const LocalRedeclarationsInfo *)Blob.data(); break; } @@ -2504,7 +2715,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { Error("duplicate MACRO_OFFSET record in AST file"); return true; } - F.MacroOffsets = (const uint32_t *)BlobStart; + F.MacroOffsets = (const uint32_t *)Blob.data(); F.LocalNumMacros = Record[0]; unsigned LocalBaseMacroID = Record[1]; F.BaseMacroID = getTotalNumMacros(); @@ -2523,60 +2734,73 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) { break; } - case MACRO_UPDATES: { - for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { - MacroID ID = getGlobalMacroID(F, Record[I++]); - if (I == N) - break; - - SourceLocation UndefLoc = ReadSourceLocation(F, Record, I); - SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);; - MacroUpdate Update; - Update.UndefLoc = UndefLoc; - MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update)); - } + case MACRO_TABLE: { + // FIXME: Not used yet. break; } } } - Error("premature end of bitstream in AST file"); - return true; } -void ASTReader::makeNamesVisible(const HiddenNames &Names) { - for (unsigned I = 0, N = Names.size(); I != N; ++I) { - switch (Names[I].getKind()) { - case HiddenName::Declaration: - Names[I].getDecl()->Hidden = false; - break; +/// \brief Move the given method to the back of the global list of methods. +static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { + // Find the entry for this selector in the method pool. + Sema::GlobalMethodPool::iterator Known + = S.MethodPool.find(Method->getSelector()); + if (Known == S.MethodPool.end()) + return; - case HiddenName::MacroVisibility: { - std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro(); - Macro.second->setHidden(!Macro.second->isPublic()); - if (Macro.second->isDefined()) { - PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); + // Retrieve the appropriate method list. + ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first + : Known->second.second; + bool Found = false; + for (ObjCMethodList *List = &Start; List; List = List->Next) { + if (!Found) { + if (List->Method == Method) { + Found = true; + } else { + // Keep searching. + continue; } - break; } - case HiddenName::MacroUndef: { - std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro(); - if (Macro.second->isDefined()) { - Macro.second->setUndefLoc(Names[I].getMacroUndefLoc()); - if (PPMutationListener *Listener = PP.getPPMutationListener()) - Listener->UndefinedMacro(Macro.second); - PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); + if (List->Next) + List->Method = List->Next->Method; + else + List->Method = Method; + } +} + +void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) { + for (unsigned I = 0, N = Names.size(); I != N; ++I) { + switch (Names[I].getKind()) { + case HiddenName::Declaration: { + Decl *D = Names[I].getDecl(); + bool wasHidden = D->Hidden; + D->Hidden = false; + + if (wasHidden && SemaObj) { + if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) { + moveMethodToBackOfGlobalList(*SemaObj, Method); + } } break; } + case HiddenName::MacroVisibility: { + std::pair<IdentifierInfo *, MacroDirective *> Macro = Names[I].getMacro(); + installImportedMacro(Macro.first, Macro.second, Owner); + break; + } } } } void ASTReader::makeModuleVisible(Module *Mod, - Module::NameVisibilityKind NameVisibility) { + Module::NameVisibilityKind NameVisibility, + SourceLocation ImportLoc, + bool Complain) { llvm::SmallPtrSet<Module *, 4> Visited; - llvm::SmallVector<Module *, 4> Stack; + SmallVector<Module *, 4> Stack; Stack.push_back(Mod); while (!Stack.empty()) { Mod = Stack.back(); @@ -2600,7 +2824,7 @@ void ASTReader::makeModuleVisible(Module *Mod, // mark them as visible. HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod); if (Hidden != HiddenNamesMap.end()) { - makeNamesVisible(Hidden->second); + makeNamesVisible(Hidden->second, Hidden->first); HiddenNamesMap.erase(Hidden); } @@ -2614,80 +2838,86 @@ void ASTReader::makeModuleVisible(Module *Mod, } // Push any exported modules onto the stack to be marked as visible. - bool AnyWildcard = false; - bool UnrestrictedWildcard = false; - llvm::SmallVector<Module *, 4> WildcardRestrictions; - for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) { - Module *Exported = Mod->Exports[I].getPointer(); - if (!Mod->Exports[I].getInt()) { - // Export a named module directly; no wildcards involved. - if (Visited.insert(Exported)) - Stack.push_back(Exported); - - continue; - } - - // Wildcard export: export all of the imported modules that match - // the given pattern. - AnyWildcard = true; - if (UnrestrictedWildcard) - continue; - - if (Module *Restriction = Mod->Exports[I].getPointer()) - WildcardRestrictions.push_back(Restriction); - else { - WildcardRestrictions.clear(); - UnrestrictedWildcard = true; - } - } - - // If there were any wildcards, push any imported modules that were - // re-exported by the wildcard restriction. - if (!AnyWildcard) - continue; - - for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) { - Module *Imported = Mod->Imports[I]; - if (!Visited.insert(Imported)) - continue; - - bool Acceptable = UnrestrictedWildcard; - if (!Acceptable) { - // Check whether this module meets one of the restrictions. - for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) { - Module *Restriction = WildcardRestrictions[R]; - if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) { - Acceptable = true; - break; - } + SmallVector<Module *, 16> Exports; + Mod->getExportedModules(Exports); + for (SmallVectorImpl<Module *>::iterator + I = Exports.begin(), E = Exports.end(); I != E; ++I) { + Module *Exported = *I; + if (Visited.insert(Exported)) + Stack.push_back(Exported); + } + + // Detect any conflicts. + if (Complain) { + assert(ImportLoc.isValid() && "Missing import location"); + for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) { + if (Mod->Conflicts[I].Other->NameVisibility >= NameVisibility) { + Diag(ImportLoc, diag::warn_module_conflict) + << Mod->getFullModuleName() + << Mod->Conflicts[I].Other->getFullModuleName() + << Mod->Conflicts[I].Message; + // FIXME: Need note where the other module was imported. } } - - if (!Acceptable) - continue; - - Stack.push_back(Imported); } } } +bool ASTReader::loadGlobalIndex() { + if (GlobalIndex) + return false; + + if (TriedLoadingGlobalIndex || !UseGlobalIndex || + !Context.getLangOpts().Modules) + return true; + + // Try to load the global index. + TriedLoadingGlobalIndex = true; + StringRef ModuleCachePath + = getPreprocessor().getHeaderSearchInfo().getModuleCachePath(); + std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> Result + = GlobalModuleIndex::readIndex(ModuleCachePath); + if (!Result.first) + return true; + + GlobalIndex.reset(Result.first); + ModuleMgr.setGlobalIndex(GlobalIndex.get()); + return false; +} + +bool ASTReader::isGlobalIndexUnavailable() const { + return Context.getLangOpts().Modules && UseGlobalIndex && + !hasGlobalIndex() && TriedLoadingGlobalIndex; +} + ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, ModuleKind Type, + SourceLocation ImportLoc, unsigned ClientLoadCapabilities) { // Bump the generation number. unsigned PreviousGeneration = CurrentGeneration++; unsigned NumModules = ModuleMgr.size(); - llvm::SmallVector<ModuleFile *, 4> Loaded; - switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, + SmallVector<ImportedModule, 4> Loaded; + switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, /*ImportedBy=*/0, Loaded, + 0, 0, ClientLoadCapabilities)) { case Failure: + case Missing: case OutOfDate: case VersionMismatch: case ConfigurationMismatch: case HadErrors: - ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end()); + ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(), + Context.getLangOpts().Modules + ? &PP.getHeaderSearchInfo().getModuleMap() + : 0); + + // If we find that any modules are unusable, the global index is going + // to be out-of-date. Just remove it. + GlobalIndex.reset(); + ModuleMgr.setGlobalIndex(0); return ReadResult; case Success: @@ -2697,10 +2927,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, // Here comes stuff that we only do once the entire chain is loaded. // Load the AST blocks of all of the modules that we loaded. - for (llvm::SmallVectorImpl<ModuleFile *>::iterator M = Loaded.begin(), - MEnd = Loaded.end(); + for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), + MEnd = Loaded.end(); M != MEnd; ++M) { - ModuleFile &F = **M; + ModuleFile &F = *M->Mod; // Read the AST block. if (ReadASTBlock(F)) @@ -2723,6 +2953,24 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, } } + // Setup the import locations and notify the module manager that we've + // committed to these module files. + for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), + MEnd = Loaded.end(); + M != MEnd; ++M) { + ModuleFile &F = *M->Mod; + + ModuleMgr.moduleFileAccepted(&F); + + // Set the import location. + F.DirectImportLoc = ImportLoc; + if (!M->ImportedBy) + F.ImportLoc = M->ImportLoc; + else + F.ImportLoc = ReadSourceLocation(*M->ImportedBy, + M->ImportLoc.getRawEncoding()); + } + // Mark all of the identifiers in the identifier table as being out of date, // so that various accessors know to check the loaded modules when the // identifier is used. @@ -2732,22 +2980,34 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, Id->second->setOutOfDate(true); // Resolve any unresolved module exports. - for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) { - UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I]; + for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) { + UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I]; SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID); Module *ResolvedMod = getSubmodule(GlobalID); - - if (Unresolved.IsImport) { + + switch (Unresolved.Kind) { + case UnresolvedModuleRef::Conflict: + if (ResolvedMod) { + Module::Conflict Conflict; + Conflict.Other = ResolvedMod; + Conflict.Message = Unresolved.String.str(); + Unresolved.Mod->Conflicts.push_back(Conflict); + } + continue; + + case UnresolvedModuleRef::Import: if (ResolvedMod) Unresolved.Mod->Imports.push_back(ResolvedMod); continue; - } - if (ResolvedMod || Unresolved.IsWildcard) - Unresolved.Mod->Exports.push_back( - Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); + case UnresolvedModuleRef::Export: + if (ResolvedMod || Unresolved.IsWildcard) + Unresolved.Mod->Exports.push_back( + Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); + continue; + } } - UnresolvedModuleImportExports.clear(); + UnresolvedModuleRefs.clear(); InitializeContext(); @@ -2777,35 +3037,64 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, ObjCClassesLoaded[I], PreviousGeneration); } - + return Success; } ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, ModuleKind Type, + SourceLocation ImportLoc, ModuleFile *ImportedBy, - llvm::SmallVectorImpl<ModuleFile *> &Loaded, + SmallVectorImpl<ImportedModule> &Loaded, + off_t ExpectedSize, time_t ExpectedModTime, unsigned ClientLoadCapabilities) { ModuleFile *M; - bool NewModule; std::string ErrorStr; - llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy, - CurrentGeneration, ErrorStr); - - if (!M) { - // We couldn't load the module. - std::string Msg = "Unable to load module \"" + FileName.str() + "\": " - + ErrorStr; - Error(Msg); - return Failure; - } + ModuleManager::AddModuleResult AddResult + = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy, + CurrentGeneration, ExpectedSize, ExpectedModTime, + M, ErrorStr); - if (!NewModule) { - // We've already loaded this module. + switch (AddResult) { + case ModuleManager::AlreadyLoaded: return Success; + + case ModuleManager::NewlyLoaded: + // Load module file below. + break; + + case ModuleManager::Missing: + // The module file was missing; if the client handle handle, that, return + // it. + if (ClientLoadCapabilities & ARR_Missing) + return Missing; + + // Otherwise, return an error. + { + std::string Msg = "Unable to load module \"" + FileName.str() + "\": " + + ErrorStr; + Error(Msg); + } + return Failure; + + case ModuleManager::OutOfDate: + // We couldn't load the module file because it is out-of-date. If the + // client can handle out-of-date, return it. + if (ClientLoadCapabilities & ARR_OutOfDate) + return OutOfDate; + + // Otherwise, return an error. + { + std::string Msg = "Unable to load module \"" + FileName.str() + "\": " + + ErrorStr; + Error(Msg); + } + return Failure; } + assert(M && "Missing module file"); + // FIXME: This seems rather a hack. Should CurrentDir be part of the // module? if (FileName != "-") { @@ -2814,7 +3103,7 @@ ASTReader::ReadASTCore(StringRef FileName, } ModuleFile &F = *M; - llvm::BitstreamCursor &Stream = F.Stream; + BitstreamCursor &Stream = F.Stream; Stream.init(F.StreamFile); F.SizeInBits = F.Buffer->getBufferSize() * 8; @@ -2827,18 +3116,25 @@ ASTReader::ReadASTCore(StringRef FileName, return Failure; } - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); + // This is used for compatibility with older PCH formats. + bool HaveReadControlBlock = false; - if (Code != llvm::bitc::ENTER_SUBBLOCK) { + while (1) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + case llvm::BitstreamEntry::EndBlock: + case llvm::BitstreamEntry::Record: Error("invalid record at top-level of AST file"); return Failure; + + case llvm::BitstreamEntry::SubBlock: + break; } - unsigned BlockID = Stream.ReadSubBlockID(); - // We only know the control subblock ID. - switch (BlockID) { + switch (Entry.ID) { case llvm::bitc::BLOCKINFO_BLOCK_ID: if (Stream.ReadBlockInfoBlock()) { Error("malformed BlockInfoBlock in AST file"); @@ -2846,11 +3142,13 @@ ASTReader::ReadASTCore(StringRef FileName, } break; case CONTROL_BLOCK_ID: + HaveReadControlBlock = true; switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) { case Success: break; case Failure: return Failure; + case Missing: return Missing; case OutOfDate: return OutOfDate; case VersionMismatch: return VersionMismatch; case ConfigurationMismatch: return ConfigurationMismatch; @@ -2858,8 +3156,14 @@ ASTReader::ReadASTCore(StringRef FileName, } break; case AST_BLOCK_ID: + if (!HaveReadControlBlock) { + if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) + Diag(diag::warn_pch_version_too_old); + return VersionMismatch; + } + // Record that we've loaded this module. - Loaded.push_back(M); + Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc)); return Success; default: @@ -3004,7 +3308,9 @@ void ASTReader::InitializeContext() { // Re-export any modules that were imported by a non-module AST file. for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) { if (Module *Imported = getSubmodule(ImportedModules[I])) - makeModuleVisible(Imported, Module::AllVisible); + makeModuleVisible(Imported, Module::AllVisible, + /*ImportLoc=*/SourceLocation(), + /*Complain=*/false); } ImportedModules.clear(); } @@ -3013,11 +3319,41 @@ void ASTReader::finalizeForWriting() { for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(), HiddenEnd = HiddenNamesMap.end(); Hidden != HiddenEnd; ++Hidden) { - makeNamesVisible(Hidden->second); + makeNamesVisible(Hidden->second, Hidden->first); } HiddenNamesMap.clear(); } +/// SkipCursorToControlBlock - Given a cursor at the start of an AST file, scan +/// ahead and drop the cursor into the start of the CONTROL_BLOCK, returning +/// false on success and true on failure. +static bool SkipCursorToControlBlock(BitstreamCursor &Cursor) { + while (1) { + llvm::BitstreamEntry Entry = Cursor.advance(); + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + case llvm::BitstreamEntry::EndBlock: + return true; + + case llvm::BitstreamEntry::Record: + // Ignore top-level records. + Cursor.skipRecord(Entry.ID); + break; + + case llvm::BitstreamEntry::SubBlock: + if (Entry.ID == CONTROL_BLOCK_ID) { + if (Cursor.EnterSubBlock(CONTROL_BLOCK_ID)) + return true; + // Found it! + return false; + } + + if (Cursor.SkipBlock()) + return true; + } + } +} + /// \brief Retrieve the name of the original source file name /// directly from the AST file, without actually loading the AST /// file. @@ -3035,7 +3371,7 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, // Initialize the stream llvm::BitstreamReader StreamFile; - llvm::BitstreamCursor Stream; + BitstreamCursor Stream; StreamFile.init((const unsigned char *)Buffer->getBufferStart(), (const unsigned char *)Buffer->getBufferEnd()); Stream.init(StreamFile); @@ -3048,54 +3384,30 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName; return std::string(); } + + // Scan for the CONTROL_BLOCK_ID block. + if (SkipCursorToControlBlock(Stream)) { + Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; + return std::string(); + } + // Scan for ORIGINAL_FILE inside the control block. RecordData Record; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - unsigned BlockID = Stream.ReadSubBlockID(); - - // We only know the AST subblock ID. - switch (BlockID) { - case CONTROL_BLOCK_ID: - if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { - Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; - return std::string(); - } - break; - - default: - if (Stream.SkipBlock()) { - Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; - return std::string(); - } - break; - } - continue; - } - - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - Diags.Report(diag::err_fe_pch_error_at_end_block) << ASTFileName; - return std::string(); - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; + while (1) { + llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + if (Entry.Kind == llvm::BitstreamEntry::EndBlock) + return std::string(); + + if (Entry.Kind != llvm::BitstreamEntry::Record) { + Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; + return std::string(); } - + Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE) - return std::string(BlobStart, BlobLen); + StringRef Blob; + if (Stream.readRecord(Entry.ID, Record, &Blob) == ORIGINAL_FILE) + return Blob.str(); } - - return std::string(); } namespace { @@ -3147,7 +3459,7 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, // Initialize the stream llvm::BitstreamReader StreamFile; - llvm::BitstreamCursor Stream; + BitstreamCursor Stream; StreamFile.init((const unsigned char *)Buffer->getBufferStart(), (const unsigned char *)Buffer->getBufferEnd()); Stream.init(StreamFile); @@ -3160,105 +3472,71 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, return true; } + // Scan for the CONTROL_BLOCK_ID block. + if (SkipCursorToControlBlock(Stream)) + return true; + + // Scan for ORIGINAL_FILE inside the control block. RecordData Record; - bool InControlBlock = false; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - unsigned BlockID = Stream.ReadSubBlockID(); - - // We only know the control subblock ID. - switch (BlockID) { - case CONTROL_BLOCK_ID: - if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { - return true; - } else { - InControlBlock = true; - } - break; - - default: - if (Stream.SkipBlock()) - return true; - break; - } - continue; - } - - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { + while (1) { + llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + if (Entry.Kind == llvm::BitstreamEntry::EndBlock) + return false; + + if (Entry.Kind != llvm::BitstreamEntry::Record) + return true; + + Record.clear(); + StringRef Blob; + unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); + switch ((ControlRecordTypes)RecCode) { + case METADATA: { + if (Record[0] != VERSION_MAJOR) return true; - } - InControlBlock = false; - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; + if (Listener.ReadFullVersionInformation(Blob)) + return true; + + break; } + case LANGUAGE_OPTIONS: + if (ParseLanguageOptions(Record, false, Listener)) + return true; + break; - Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen); - if (InControlBlock) { - switch ((ControlRecordTypes)RecCode) { - case METADATA: { - if (Record[0] != VERSION_MAJOR) { - return true; - } - - const std::string &CurBranch = getClangFullRepositoryVersion(); - StringRef ASTBranch(BlobStart, BlobLen); - if (StringRef(CurBranch) != ASTBranch) - return true; - - break; - } - case LANGUAGE_OPTIONS: - if (ParseLanguageOptions(Record, false, Listener)) - return true; - break; - - case TARGET_OPTIONS: - if (ParseTargetOptions(Record, false, Listener)) - return true; - break; + case TARGET_OPTIONS: + if (ParseTargetOptions(Record, false, Listener)) + return true; + break; - case DIAGNOSTIC_OPTIONS: - if (ParseDiagnosticOptions(Record, false, Listener)) - return true; - break; + case DIAGNOSTIC_OPTIONS: + if (ParseDiagnosticOptions(Record, false, Listener)) + return true; + break; - case FILE_SYSTEM_OPTIONS: - if (ParseFileSystemOptions(Record, false, Listener)) - return true; - break; + case FILE_SYSTEM_OPTIONS: + if (ParseFileSystemOptions(Record, false, Listener)) + return true; + break; - case HEADER_SEARCH_OPTIONS: - if (ParseHeaderSearchOptions(Record, false, Listener)) - return true; - break; + case HEADER_SEARCH_OPTIONS: + if (ParseHeaderSearchOptions(Record, false, Listener)) + return true; + break; - case PREPROCESSOR_OPTIONS: { - std::string IgnoredSuggestedPredefines; - if (ParsePreprocessorOptions(Record, false, Listener, - IgnoredSuggestedPredefines)) - return true; - break; - } + case PREPROCESSOR_OPTIONS: { + std::string IgnoredSuggestedPredefines; + if (ParsePreprocessorOptions(Record, false, Listener, + IgnoredSuggestedPredefines)) + return true; + break; + } - default: - // No other validation to perform. - break; - } + default: + // No other validation to perform. + break; } } - - return false; } @@ -3283,35 +3561,24 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { Module *CurrentModule = 0; RecordData Record; while (true) { - unsigned Code = F.Stream.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (F.Stream.ReadBlockEnd()) { - Error("error at end of submodule block in AST file"); - return true; - } - return false; - } + llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks(); - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - F.Stream.ReadSubBlockID(); - if (F.Stream.SkipBlock()) { - Error("malformed block record in AST file"); - return true; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - F.Stream.ReadAbbrevRecord(); - continue; + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: // Handled for us already. + case llvm::BitstreamEntry::Error: + Error("malformed block record in AST file"); + return true; + case llvm::BitstreamEntry::EndBlock: + return false; + case llvm::BitstreamEntry::Record: + // The interesting case. + break; } - + // Read a record. - const char *BlobStart; - unsigned BlobLen; + StringRef Blob; Record.clear(); - switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + switch (F.Stream.readRecord(Entry.ID, Record, &Blob)) { default: // Default behavior: ignore. break; @@ -3321,12 +3588,12 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { return true; } - if (Record.size() < 7) { + if (Record.size() < 8) { Error("malformed module definition"); return true; } - StringRef Name(BlobStart, BlobLen); + StringRef Name = Blob; SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]); SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]); bool IsFramework = Record[2]; @@ -3335,7 +3602,8 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { bool InferSubmodules = Record[5]; bool InferExplicitSubmodules = Record[6]; bool InferExportWildcard = Record[7]; - + bool ConfigMacrosExhaustive = Record[8]; + Module *ParentModule = 0; if (Parent) ParentModule = getSubmodule(Parent); @@ -3351,17 +3619,39 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { Error("too many submodules"); return true; } + + if (!ParentModule) { + if (const FileEntry *CurFile = CurrentModule->getASTFile()) { + if (CurFile != F.File) { + if (!Diags.isDiagnosticInFlight()) { + Diag(diag::err_module_file_conflict) + << CurrentModule->getTopLevelModuleName() + << CurFile->getName() + << F.File->getName(); + } + return true; + } + } + + CurrentModule->setASTFile(F.File); + } - CurrentModule->setASTFile(F.File); CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; CurrentModule->InferSubmodules = InferSubmodules; CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; CurrentModule->InferExportWildcard = InferExportWildcard; + CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive; if (DeserializationListener) DeserializationListener->ModuleRead(GlobalID, CurrentModule); SubmodulesLoaded[GlobalIndex] = CurrentModule; + + // Clear out data that will be replaced by what is the module file. + CurrentModule->LinkLibraries.clear(); + CurrentModule->ConfigMacros.clear(); + CurrentModule->UnresolvedConflicts.clear(); + CurrentModule->Conflicts.clear(); break; } @@ -3374,8 +3664,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - StringRef FileName(BlobStart, BlobLen); - if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) { + if (const FileEntry *Umbrella = PP.getFileManager().getFile(Blob)) { if (!CurrentModule->getUmbrellaHeader()) ModMap.setUmbrellaHeader(CurrentModule, Umbrella); else if (CurrentModule->getUmbrellaHeader() != Umbrella) { @@ -3395,14 +3684,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - // FIXME: Be more lazy about this! - StringRef FileName(BlobStart, BlobLen); - if (const FileEntry *File = PP.getFileManager().getFile(FileName)) { - if (std::find(CurrentModule->Headers.begin(), - CurrentModule->Headers.end(), - File) == CurrentModule->Headers.end()) - ModMap.addHeader(CurrentModule, File, false); - } + // We lazily associate headers with their modules via the HeaderInfoTable. + // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead + // of complete filenames or remove it entirely. break; } @@ -3415,14 +3699,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - // FIXME: Be more lazy about this! - StringRef FileName(BlobStart, BlobLen); - if (const FileEntry *File = PP.getFileManager().getFile(FileName)) { - if (std::find(CurrentModule->Headers.begin(), - CurrentModule->Headers.end(), - File) == CurrentModule->Headers.end()) - ModMap.addHeader(CurrentModule, File, true); - } + // We lazily associate headers with their modules via the HeaderInfoTable. + // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead + // of complete filenames or remove it entirely. break; } @@ -3435,10 +3714,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - // FIXME: Be more lazy about this! - StringRef FileName(BlobStart, BlobLen); - if (const FileEntry *File = PP.getFileManager().getFile(FileName)) - CurrentModule->TopHeaders.insert(File); + CurrentModule->addTopHeaderFilename(Blob); break; } @@ -3451,9 +3727,8 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - StringRef DirName(BlobStart, BlobLen); if (const DirectoryEntry *Umbrella - = PP.getFileManager().getDirectory(DirName)) { + = PP.getFileManager().getDirectory(Blob)) { if (!CurrentModule->getUmbrellaDir()) ModMap.setUmbrellaDir(CurrentModule, Umbrella); else if (CurrentModule->getUmbrellaDir() != Umbrella) { @@ -3500,13 +3775,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { break; for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { - UnresolvedModuleImportExport Unresolved; + UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; - Unresolved.IsImport = true; + Unresolved.Kind = UnresolvedModuleRef::Import; Unresolved.IsWildcard = false; - UnresolvedModuleImportExports.push_back(Unresolved); + UnresolvedModuleRefs.push_back(Unresolved); } break; } @@ -3521,13 +3796,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { break; for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { - UnresolvedModuleImportExport Unresolved; + UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; - Unresolved.IsImport = false; + Unresolved.Kind = UnresolvedModuleRef::Export; Unresolved.IsWildcard = Record[Idx + 1]; - UnresolvedModuleImportExports.push_back(Unresolved); + UnresolvedModuleRefs.push_back(Unresolved); } // Once we've loaded the set of exports, there's no reason to keep @@ -3544,11 +3819,55 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (!CurrentModule) break; - CurrentModule->addRequirement(StringRef(BlobStart, BlobLen), - Context.getLangOpts(), + CurrentModule->addRequirement(Blob, Context.getLangOpts(), Context.getTargetInfo()); break; } + + case SUBMODULE_LINK_LIBRARY: + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + CurrentModule->LinkLibraries.push_back( + Module::LinkLibrary(Blob, Record[0])); + break; + + case SUBMODULE_CONFIG_MACRO: + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + CurrentModule->ConfigMacros.push_back(Blob.str()); + break; + + case SUBMODULE_CONFLICT: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + UnresolvedModuleRef Unresolved; + Unresolved.File = &F; + Unresolved.Mod = CurrentModule; + Unresolved.ID = Record[0]; + Unresolved.Kind = UnresolvedModuleRef::Conflict; + Unresolved.IsWildcard = false; + Unresolved.String = Blob; + UnresolvedModuleRefs.push_back(Unresolved); + break; + } } } } @@ -3570,6 +3889,8 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record, #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++])); #include "clang/Basic/LangOptions.def" +#define SANITIZER(NAME, ID) LangOpts.Sanitize.ID = Record[Idx++]; +#include "clang/Basic/Sanitizers.def" ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); @@ -3578,6 +3899,15 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record, unsigned Length = Record[Idx++]; LangOpts.CurrentModule.assign(Record.begin() + Idx, Record.begin() + Idx + Length); + + Idx += Length; + + // Comment options. + for (unsigned N = Record[Idx++]; N; --N) { + LangOpts.CommentOpts.BlockCommandNames.push_back( + ReadString(Record, Idx)); + } + return Listener.ReadLanguageOptions(LangOpts, Complain); } @@ -3637,14 +3967,10 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, std::string Path = ReadString(Record, Idx); frontend::IncludeDirGroup Group = static_cast<frontend::IncludeDirGroup>(Record[Idx++]); - bool IsUserSupplied = Record[Idx++]; bool IsFramework = Record[Idx++]; bool IgnoreSysRoot = Record[Idx++]; - bool IsInternal = Record[Idx++]; - bool ImplicitExternC = Record[Idx++]; HSOpts.UserEntries.push_back( - HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework, - IgnoreSysRoot, IsInternal, ImplicitExternC)); + HeaderSearchOptions::Entry(Path, Group, IsFramework, IgnoreSysRoot)); } // System header prefixes. @@ -3735,41 +4061,28 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { unsigned LocalIndex = PPInfo.second; const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; - SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); - M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset); - - unsigned Code = M.PreprocessorDetailCursor.ReadCode(); - switch (Code) { - case llvm::bitc::END_BLOCK: - return 0; - - case llvm::bitc::ENTER_SUBBLOCK: - Error("unexpected subblock record in preprocessor detail block"); - return 0; - - case llvm::bitc::DEFINE_ABBREV: - Error("unexpected abbrevation record in preprocessor detail block"); - return 0; - - default: - break; - } - if (!PP.getPreprocessingRecord()) { Error("no preprocessing record"); return 0; } + SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); + M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset); + + llvm::BitstreamEntry Entry = + M.PreprocessorDetailCursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd); + if (Entry.Kind != llvm::BitstreamEntry::Record) + return 0; + // Read the record. SourceRange Range(ReadSourceLocation(M, PPOffs.Begin), ReadSourceLocation(M, PPOffs.End)); PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); - const char *BlobStart = 0; - unsigned BlobLen = 0; + StringRef Blob; RecordData Record; PreprocessorDetailRecordTypes RecType = - (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord( - Code, Record, BlobStart, BlobLen); + (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.readRecord( + Entry.ID, Record, &Blob); switch (RecType) { case PPD_MACRO_EXPANSION: { bool isBuiltin = Record[0]; @@ -3806,8 +4119,8 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { } case PPD_INCLUSION_DIRECTIVE: { - const char *FullFileNameStart = BlobStart + Record[0]; - StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]); + const char *FullFileNameStart = Blob.data() + Record[0]; + StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]); const FileEntry *File = 0; if (!FullFileName.empty()) File = PP.getFileManager().getFile(FullFileName); @@ -3817,7 +4130,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { = static_cast<InclusionDirective::InclusionKind>(Record[2]); InclusionDirective *ID = new (PPRec) InclusionDirective(PPRec, Kind, - StringRef(BlobStart, Record[0]), + StringRef(Blob.data(), Record[0]), Record[1], Record[3], File, Range); @@ -3885,7 +4198,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const { GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - - BLoc.getOffset()); + BLoc.getOffset() - 1); assert(SLocMapI != GlobalSLocOffsetMap.end() && "Corrupted global sloc offset map"); @@ -3933,7 +4246,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const { GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - - ELoc.getOffset()); + ELoc.getOffset() - 1); assert(SLocMapI != GlobalSLocOffsetMap.end() && "Corrupted global sloc offset map"); @@ -3969,7 +4282,7 @@ std::pair<unsigned, unsigned> /// \brief Optionally returns true or false if the preallocated preprocessed /// entity with index \arg Index came from file \arg FID. -llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index, +Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index, FileID FID) { if (FID.isInvalid()) return false; @@ -3992,32 +4305,25 @@ llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index, namespace { /// \brief Visitor used to search for information about a header file. class HeaderFileInfoVisitor { - ASTReader &Reader; const FileEntry *FE; - llvm::Optional<HeaderFileInfo> HFI; + Optional<HeaderFileInfo> HFI; public: - HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE) - : Reader(Reader), FE(FE) { } + explicit HeaderFileInfoVisitor(const FileEntry *FE) + : FE(FE) { } static bool visit(ModuleFile &M, void *UserData) { HeaderFileInfoVisitor *This = static_cast<HeaderFileInfoVisitor *>(UserData); - HeaderFileInfoTrait Trait(This->Reader, M, - &This->Reader.getPreprocessor().getHeaderSearchInfo(), - M.HeaderFileFrameworkStrings, - This->FE->getName()); - HeaderFileInfoLookupTable *Table = static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable); if (!Table) return false; // Look in the on-disk hash table for an entry for this file name. - HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(), - &Trait); + HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE); if (Pos == Table->end()) return false; @@ -4025,14 +4331,14 @@ namespace { return true; } - llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; } + Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; } }; } HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { - HeaderFileInfoVisitor Visitor(*this, FE); + HeaderFileInfoVisitor Visitor(FE); ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor); - if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) { + if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) { if (Listener) Listener->ReadHeaderFileInfo(*HFI, FE->getUID()); return *HFI; @@ -4043,7 +4349,7 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { // FIXME: Make it work properly with modules. - llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates; + SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates; for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { ModuleFile &F = *(*I); unsigned Idx = 0; @@ -4103,7 +4409,7 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { /// IDs. QualType ASTReader::readTypeRecord(unsigned Index) { RecordLocation Loc = TypeCursorForIndex(Index); - llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; + BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; // Keep track of where we are in the stream, then jump back there // after reading this type. @@ -4118,7 +4424,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) { DeclsCursor.JumpToBit(Loc.Offset); RecordData Record; unsigned Code = DeclsCursor.ReadCode(); - switch ((TypeCode)DeclsCursor.ReadRecord(Code, Record)) { + switch ((TypeCode)DeclsCursor.readRecord(Code, Record)) { case TYPE_EXT_QUAL: { if (Record.size() != 2) { Error("Incorrect encoding of extended qualifier type"); @@ -4287,8 +4593,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) { } else if (EST == EST_Unevaluated) { EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx); } - return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams, - EPI); + return Context.getFunctionType(ResultType, ParamTypes, EPI); } case TYPE_UNRESOLVED_USING: { @@ -4392,7 +4697,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) { QualType Pattern = readType(*Loc.F, Record, Idx); if (Pattern.isNull()) return QualType(); - llvm::Optional<unsigned> NumExpansions; + Optional<unsigned> NumExpansions; if (Record[1]) NumExpansions = Record[1] - 1; return Context.getPackExpansionType(Pattern, NumExpansions); @@ -4834,6 +5139,14 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break; case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break; case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break; + case PREDEF_TYPE_IMAGE1D_ID: T = Context.OCLImage1dTy; break; + case PREDEF_TYPE_IMAGE1D_ARR_ID: T = Context.OCLImage1dArrayTy; break; + case PREDEF_TYPE_IMAGE1D_BUFF_ID: T = Context.OCLImage1dBufferTy; break; + case PREDEF_TYPE_IMAGE2D_ID: T = Context.OCLImage2dTy; break; + case PREDEF_TYPE_IMAGE2D_ARR_ID: T = Context.OCLImage2dArrayTy; break; + case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break; + case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break; + case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break; case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; case PREDEF_TYPE_AUTO_RREF_DEDUCT: @@ -4957,13 +5270,13 @@ uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Recor CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { RecordLocation Loc = getLocalBitOffset(Offset); - llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor; + BitstreamCursor &Cursor = Loc.F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(Loc.Offset); ReadingKindTracker ReadingKind(Read_Decl, *this); RecordData Record; unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.ReadRecord(Code, Record); + unsigned RecCode = Cursor.readRecord(Code, Record); if (RecCode != DECL_CXX_BASE_SPECIFIERS) { Error("Malformed AST file: missing C++ base specifiers"); return 0; @@ -4997,7 +5310,7 @@ bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, return &M == I->second; } -ModuleFile *ASTReader::getOwningModuleFile(Decl *D) { +ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) { if (!D->isFromASTFile()) return 0; GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID()); @@ -5269,7 +5582,7 @@ namespace { /// declaration context. class DeclContextNameLookupVisitor { ASTReader &Reader; - llvm::SmallVectorImpl<const DeclContext *> &Contexts; + SmallVectorImpl<const DeclContext *> &Contexts; DeclarationName Name; SmallVectorImpl<NamedDecl *> &Decls; @@ -5333,14 +5646,34 @@ namespace { }; } -DeclContext::lookup_result +/// \brief Retrieve the "definitive" module file for the definition of the +/// given declaration context, if there is one. +/// +/// The "definitive" module file is the only place where we need to look to +/// find information about the declarations within the given declaration +/// context. For example, C++ and Objective-C classes, C structs/unions, and +/// Objective-C protocols, categories, and extensions are all defined in a +/// single place in the source code, so they have definitive module files +/// associated with them. C++ namespaces, on the other hand, can have +/// definitions in multiple different module files. +/// +/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's +/// NDEBUG checking. +static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC, + ASTReader &Reader) { + if (const DeclContext *DefDC = getDefinitiveDeclContext(DC)) + return Reader.getOwningModuleFile(cast<Decl>(DefDC)); + + return 0; +} + +bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { assert(DC->hasExternalVisibleStorage() && "DeclContext has no visible decls in storage"); if (!Name) - return DeclContext::lookup_result(DeclContext::lookup_iterator(0), - DeclContext::lookup_iterator(0)); + return false; SmallVector<NamedDecl *, 64> Decls; @@ -5361,10 +5694,19 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, } DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls); - ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); + + // If we can definitively determine which module file to look into, + // only look there. Otherwise, look in all module files. + ModuleFile *Definitive; + if (Contexts.size() == 1 && + (Definitive = getDefinitiveModuleFileFor(DC, *this))) { + DeclContextNameLookupVisitor::visit(*Definitive, &Visitor); + } else { + ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); + } ++NumVisibleDeclContextsRead; SetExternalVisibleDeclsForName(DC, Name, Decls); - return const_cast<DeclContext*>(DC)->lookup(Name); + return !Decls.empty(); } namespace { @@ -5372,15 +5714,17 @@ namespace { /// declaration context. class DeclContextAllNamesVisitor { ASTReader &Reader; - llvm::SmallVectorImpl<const DeclContext *> &Contexts; + SmallVectorImpl<const DeclContext *> &Contexts; llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > &Decls; + bool VisitAll; public: DeclContextAllNamesVisitor(ASTReader &Reader, SmallVectorImpl<const DeclContext *> &Contexts, llvm::DenseMap<DeclarationName, - SmallVector<NamedDecl *, 8> > &Decls) - : Reader(Reader), Contexts(Contexts), Decls(Decls) { } + SmallVector<NamedDecl *, 8> > &Decls, + bool VisitAll) + : Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { } static bool visit(ModuleFile &M, void *UserData) { DeclContextAllNamesVisitor *This @@ -5406,8 +5750,9 @@ namespace { Info->second.NameLookupTableData; bool FoundAnything = false; for (ASTDeclContextNameLookupTable::data_iterator - I = LookupTable->data_begin(), E = LookupTable->data_end(); - I != E; ++I) { + I = LookupTable->data_begin(), E = LookupTable->data_end(); + I != E; + ++I) { ASTDeclContextNameLookupTrait::data_type Data = *I; for (; Data.first != Data.second; ++Data.first) { NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, @@ -5421,7 +5766,7 @@ namespace { } } - return FoundAnything; + return FoundAnything && !This->VisitAll; } }; } @@ -5429,7 +5774,7 @@ namespace { void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { if (!DC->hasExternalVisibleStorage()) return; - llvm::DenseMap<DeclarationName, llvm::SmallVector<NamedDecl*, 8> > Decls; + llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > Decls; // Compute the declaration contexts we need to look into. Multiple such // declaration contexts occur when two declaration contexts from disjoint @@ -5447,12 +5792,13 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { } } - DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls); + DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls, + /*VisitAll=*/DC->isFileContext()); ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor); ++NumVisibleDeclContextsRead; for (llvm::DenseMap<DeclarationName, - llvm::SmallVector<NamedDecl*, 8> >::iterator + SmallVector<NamedDecl *, 8> >::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { SetExternalVisibleDeclsForName(DC, I->first, I->second); } @@ -5576,8 +5922,31 @@ void ASTReader::PrintStats() { NumMethodPoolEntriesRead, TotalNumMethodPoolEntries, ((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries * 100)); - std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses); } + if (NumMethodPoolLookups) { + std::fprintf(stderr, " %u/%u method pool lookups succeeded (%f%%)\n", + NumMethodPoolHits, NumMethodPoolLookups, + ((float)NumMethodPoolHits/NumMethodPoolLookups * 100.0)); + } + if (NumMethodPoolTableLookups) { + std::fprintf(stderr, " %u/%u method pool table lookups succeeded (%f%%)\n", + NumMethodPoolTableHits, NumMethodPoolTableLookups, + ((float)NumMethodPoolTableHits/NumMethodPoolTableLookups + * 100.0)); + } + + if (NumIdentifierLookupHits) { + std::fprintf(stderr, + " %u / %u identifier table lookups succeeded (%f%%)\n", + NumIdentifierLookupHits, NumIdentifierLookups, + (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups); + } + + if (GlobalIndex) { + std::fprintf(stderr, "\n"); + GlobalIndex->printStats(); + } + std::fprintf(stderr, "\n"); dump(); std::fprintf(stderr, "\n"); @@ -5646,8 +6015,8 @@ void ASTReader::InitializeSema(Sema &S) { // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { - SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I], - PreloadedDecls[I]->getDeclName()); + NamedDecl *ND = cast<NamedDecl>(PreloadedDecls[I]->getMostRecentDecl()); + SemaObj->pushExternalDeclIntoScope(ND, PreloadedDecls[I]->getDeclName()); } PreloadedDecls.clear(); @@ -5678,10 +6047,21 @@ void ASTReader::InitializeSema(Sema &S) { IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) { // Note that we are loading an identifier. Deserializing AnIdentifier(this); - - IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart), - /*PriorGeneration=*/0); - ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); + StringRef Name(NameStart, NameEnd - NameStart); + + // If there is a global index, look there first to determine which modules + // provably do not have any results for this identifier. + GlobalModuleIndex::HitSet Hits; + GlobalModuleIndex::HitSet *HitsPtr = 0; + if (!loadGlobalIndex()) { + if (GlobalIndex->lookupIdentifier(Name, Hits)) { + HitsPtr = &Hits; + } + } + IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0, + NumIdentifierLookups, + NumIdentifierLookupHits); + ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr); IdentifierInfo *II = Visitor.getIdentifierInfo(); markIdentifierUpToDate(II); return II; @@ -5737,9 +6117,9 @@ StringRef ASTIdentifierIterator::Next() { // We have any identifiers remaining in the current AST file; return // the next one. - std::pair<const char*, unsigned> Key = *Current; + StringRef Result = *Current; ++Current; - return StringRef(Key.first, Key.second); + return Result; } IdentifierIterator *ASTReader::getIdentifiers() const { @@ -5751,8 +6131,8 @@ namespace clang { namespace serialization { ASTReader &Reader; Selector Sel; unsigned PriorGeneration; - llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods; - llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods; + SmallVector<ObjCMethodDecl *, 4> InstanceMethods; + SmallVector<ObjCMethodDecl *, 4> FactoryMethods; public: ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, @@ -5770,12 +6150,14 @@ namespace clang { namespace serialization { if (M.Generation <= This->PriorGeneration) return true; + ++This->Reader.NumMethodPoolTableLookups; ASTSelectorLookupTable *PoolTable = (ASTSelectorLookupTable*)M.SelectorLookupTable; ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel); if (Pos == PoolTable->end()) return false; - + + ++This->Reader.NumMethodPoolTableHits; ++This->Reader.NumSelectorsRead; // FIXME: Not quite happy with the statistics here. We probably should // disable this tracking when called via LoadSelector. @@ -5818,15 +6200,16 @@ void ASTReader::ReadMethodPool(Selector Sel) { Generation = CurrentGeneration; // Search for methods defined with this selector. + ++NumMethodPoolLookups; ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration); ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor); if (Visitor.getInstanceMethods().empty() && - Visitor.getFactoryMethods().empty()) { - ++NumMethodPoolMisses; + Visitor.getFactoryMethods().empty()) return; - } - + + ++NumMethodPoolHits; + if (!getSema()) return; @@ -5849,6 +6232,16 @@ void ASTReader::ReadKnownNamespaces( } } +void ASTReader::ReadUndefinedButUsed( + llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined) { + for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) { + NamedDecl *D = cast<NamedDecl>(GetDecl(UndefinedButUsed[Idx++])); + SourceLocation Loc = + SourceLocation::getFromRawEncoding(UndefinedButUsed[Idx++]); + Undefined.insert(std::make_pair(D, Loc)); + } +} + void ASTReader::ReadTentativeDefinitions( SmallVectorImpl<VarDecl *> &TentativeDefs) { for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { @@ -5902,14 +6295,14 @@ void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) { } void -ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl *> &Decls) { - for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) { - NamedDecl *D - = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I])); +ASTReader::ReadLocallyScopedExternCDecls(SmallVectorImpl<NamedDecl *> &Decls) { + for (unsigned I = 0, N = LocallyScopedExternCDecls.size(); I != N; ++I) { + NamedDecl *D + = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternCDecls[I])); if (D) Decls.push_back(D); } - LocallyScopedExternalDecls.clear(); + LocallyScopedExternCDecls.clear(); } void ASTReader::ReadReferencedSelectors( @@ -6000,28 +6393,32 @@ void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) { /// \param DeclIDs the set of declaration IDs with the name @p II that are /// visible at global scope. /// -/// \param Nonrecursive should be true to indicate that the caller knows that -/// this call is non-recursive, and therefore the globally-visible declarations -/// will not be placed onto the pending queue. +/// \param Decls if non-null, this vector will be populated with the set of +/// deserialized declarations. These declarations will not be pushed into +/// scope. void ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, const SmallVectorImpl<uint32_t> &DeclIDs, - bool Nonrecursive) { - if (NumCurrentElementsDeserializing && !Nonrecursive) { - PendingIdentifierInfos.push_back(PendingIdentifierInfo()); - PendingIdentifierInfo &PII = PendingIdentifierInfos.back(); - PII.II = II; - PII.DeclIDs.append(DeclIDs.begin(), DeclIDs.end()); + SmallVectorImpl<Decl *> *Decls) { + if (NumCurrentElementsDeserializing && !Decls) { + PendingIdentifierInfos[II].append(DeclIDs.begin(), DeclIDs.end()); return; } for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) { NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I])); if (SemaObj) { + // If we're simply supposed to record the declarations, do so now. + if (Decls) { + Decls->push_back(D); + continue; + } + // Introduce this declaration into the translation-unit scope // and add it to the declaration chain for this identifier, so // that (unqualified) name lookup will find it. - SemaObj->pushExternalDeclIntoScope(D, II); + NamedDecl *ND = cast<NamedDecl>(D->getMostRecentDecl()); + SemaObj->pushExternalDeclIntoScope(ND, II); } else { // Queue this declaration so that it will be added to the // translation unit scope and identifier's declaration chain @@ -6081,7 +6478,7 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) { return LocalID + I->second; } -MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) { +MacroInfo *ASTReader::getMacro(MacroID ID) { if (ID == 0) return 0; @@ -6097,7 +6494,11 @@ MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) { assert(I != GlobalMacroMap.end() && "Corrupted global macro map"); ModuleFile *M = I->second; unsigned Index = ID - M->BaseMacroID; - ReadMacroRecord(*M, M->MacroOffsets[Index], Hint); + MacrosLoaded[ID] = ReadMacroRecord(*M, M->MacroOffsets[Index]); + + if (DeserializationListener) + DeserializationListener->MacroRead(ID + NUM_PREDEF_MACRO_IDS, + MacrosLoaded[ID]); } return MacrosLoaded[ID]; @@ -6140,7 +6541,11 @@ Module *ASTReader::getSubmodule(SubmoduleID GlobalID) { return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS]; } - + +Module *ASTReader::getModule(unsigned ID) { + return getSubmodule(ID); +} + Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { return DecodeSelector(getGlobalSelectorID(M, LocalID)); } @@ -6370,7 +6775,7 @@ ASTReader::ReadTemplateArgument(ModuleFile &F, return TemplateArgument(ReadTemplateName(F, Record, Idx)); case TemplateArgument::TemplateExpansion: { TemplateName Name = ReadTemplateName(F, Record, Idx); - llvm::Optional<unsigned> NumTemplateExpansions; + Optional<unsigned> NumTemplateExpansions; if (unsigned NumExpansions = Record[Idx++]) NumTemplateExpansions = NumExpansions - 1; return TemplateArgument(Name, NumTemplateExpansions); @@ -6420,13 +6825,14 @@ ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs, } /// \brief Read a UnresolvedSet structure. -void ASTReader::ReadUnresolvedSet(ModuleFile &F, UnresolvedSetImpl &Set, +void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set, const RecordData &Record, unsigned &Idx) { unsigned NumDecls = Record[Idx++]; + Set.reserve(Context, NumDecls); while (NumDecls--) { NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx); AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; - Set.addDecl(D, AS); + Set.addDecl(Context, D, AS); } } @@ -6656,8 +7062,10 @@ llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) { } /// \brief Read a floating-point value -llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) { - return llvm::APFloat(ReadAPInt(Record, Idx)); +llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, + const llvm::fltSemantics &Sem, + unsigned &Idx) { + return llvm::APFloat(Sem, ReadAPInt(Record, Idx)); } // \brief Read a string @@ -6721,39 +7129,35 @@ void ASTReader::ClearSwitchCaseIDs() { void ASTReader::ReadComments() { std::vector<RawComment *> Comments; - for (SmallVectorImpl<std::pair<llvm::BitstreamCursor, + for (SmallVectorImpl<std::pair<BitstreamCursor, serialization::ModuleFile *> >::iterator I = CommentsCursors.begin(), E = CommentsCursors.end(); I != E; ++I) { - llvm::BitstreamCursor &Cursor = I->first; + BitstreamCursor &Cursor = I->first; serialization::ModuleFile &F = *I->second; SavedStreamPosition SavedPosition(Cursor); RecordData Record; while (true) { - unsigned Code = Cursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) + llvm::BitstreamEntry Entry = + Cursor.advanceSkippingSubblocks(BitstreamCursor::AF_DontPopBlockAtEnd); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: // Handled for us already. + case llvm::BitstreamEntry::Error: + Error("malformed block record in AST file"); + return; + case llvm::BitstreamEntry::EndBlock: + goto NextCursor; + case llvm::BitstreamEntry::Record: + // The interesting case. break; - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - Cursor.ReadSubBlockID(); - if (Cursor.SkipBlock()) { - Error("malformed block record in AST file"); - return; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Cursor.ReadAbbrevRecord(); - continue; } // Read a record. Record.clear(); - switch ((CommentRecordTypes) Cursor.ReadRecord(Code, Record)) { + switch ((CommentRecordTypes)Cursor.readRecord(Entry.ID, Record)) { case COMMENTS_RAW_COMMENT: { unsigned Idx = 0; SourceRange SR = ReadSourceRange(F, Record, Idx); @@ -6768,19 +7172,24 @@ void ASTReader::ReadComments() { } } } + NextCursor:; } Context.Comments.addCommentsToFront(Comments); } void ASTReader::finishPendingActions() { while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() || - !PendingMacroIDs.empty()) { + !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty()) { // If any identifiers with corresponding top-level declarations have // been loaded, load those declarations now. + llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> > TopLevelDecls; while (!PendingIdentifierInfos.empty()) { - SetGloballyVisibleDecls(PendingIdentifierInfos.front().II, - PendingIdentifierInfos.front().DeclIDs, true); - PendingIdentifierInfos.pop_front(); + // FIXME: std::move + IdentifierInfo *II = PendingIdentifierInfos.back().first; + SmallVector<uint32_t, 4> DeclIDs = PendingIdentifierInfos.back().second; + PendingIdentifierInfos.pop_back(); + + SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]); } // Load pending declaration chains. @@ -6790,17 +7199,48 @@ void ASTReader::finishPendingActions() { } PendingDeclChains.clear(); + // Make the most recent of the top-level declarations visible. + for (llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >::iterator + TLD = TopLevelDecls.begin(), TLDEnd = TopLevelDecls.end(); + TLD != TLDEnd; ++TLD) { + IdentifierInfo *II = TLD->first; + for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) { + NamedDecl *ND = cast<NamedDecl>(TLD->second[I]->getMostRecentDecl()); + SemaObj->pushExternalDeclIntoScope(ND, II); + } + } + // Load any pending macro definitions. for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) { - // FIXME: std::move here - SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second; - MacroInfo *Hint = 0; + IdentifierInfo *II = PendingMacroIDs.begin()[I].first; + SmallVector<PendingMacroInfo, 2> GlobalIDs; + GlobalIDs.swap(PendingMacroIDs.begin()[I].second); + // Initialize the macro history from chained-PCHs ahead of module imports. for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; ++IDIdx) { - Hint = getMacro(GlobalIDs[IDIdx], Hint); + const PendingMacroInfo &Info = GlobalIDs[IDIdx]; + if (Info.M->Kind != MK_Module) + resolvePendingMacro(II, Info); + } + // Handle module imports. + for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; + ++IDIdx) { + const PendingMacroInfo &Info = GlobalIDs[IDIdx]; + if (Info.M->Kind == MK_Module) + resolvePendingMacro(II, Info); } } PendingMacroIDs.clear(); + + // Wire up the DeclContexts for Decls that we delayed setting until + // recursive loading is completed. + while (!PendingDeclContextInfos.empty()) { + PendingDeclContextInfo Info = PendingDeclContextInfos.front(); + PendingDeclContextInfos.pop_front(); + DeclContext *SemaDC = cast<DeclContext>(GetDecl(Info.SemaDC)); + DeclContext *LexicalDC = cast<DeclContext>(GetDecl(Info.LexicalDC)); + Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext()); + } } // If we deserialized any C++ or Objective-C class definitions, any @@ -6908,18 +7348,22 @@ void ASTReader::FinishedDeserializing() { ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot, bool DisableValidation, - bool AllowASTWithCompilerErrors) + bool AllowASTWithCompilerErrors, bool UseGlobalIndex) : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context), Consumer(0), ModuleMgr(PP.getFileManager()), isysroot(isysroot), DisableValidation(DisableValidation), - AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), + AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), + UseGlobalIndex(UseGlobalIndex), TriedLoadingGlobalIndex(false), CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts), NumSLocEntriesRead(0), TotalNumSLocEntries(0), - NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), - TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), - NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0), + NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), + TotalNumMacros(0), NumIdentifierLookups(0), NumIdentifierLookupHits(0), + NumSelectorsRead(0), NumMethodPoolEntriesRead(0), + NumMethodPoolLookups(0), NumMethodPoolHits(0), + NumMethodPoolTableLookups(0), NumMethodPoolTableHits(0), + TotalNumMethodPoolEntries(0), NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0), NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0), TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0), diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index c42944d..0fbdd7e 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -12,19 +12,19 @@ // //===----------------------------------------------------------------------===// +#include "clang/Serialization/ASTReader.h" #include "ASTCommon.h" #include "ASTReaderInternals.h" -#include "clang/Serialization/ASTReader.h" -#include "clang/Sema/IdentifierResolver.h" -#include "clang/Sema/Sema.h" -#include "clang/Sema/SemaDiagnostic.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/DeclGroup.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; using namespace clang::serialization; @@ -44,9 +44,6 @@ namespace clang { unsigned &Idx; TypeID TypeIDForTypeDecl; - DeclID DeclContextIDForTemplateParmDecl; - DeclID LexicalDeclContextIDForTemplateParmDecl; - bool HasPendingBody; uint64_t GetCurrentCursorOffset(); @@ -116,29 +113,25 @@ namespace clang { ASTReader &Reader; GlobalDeclID FirstID; mutable bool Owning; + Decl::Kind DeclKind; void operator=(RedeclarableResult &) LLVM_DELETED_FUNCTION; public: - RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID) - : Reader(Reader), FirstID(FirstID), Owning(true) { } + RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID, + Decl::Kind DeclKind) + : Reader(Reader), FirstID(FirstID), Owning(true), DeclKind(DeclKind) { } RedeclarableResult(const RedeclarableResult &Other) - : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning) + : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning) , + DeclKind(Other.DeclKind) { Other.Owning = false; } ~RedeclarableResult() { - // FIXME: We want to suppress this when the declaration is local to - // a function, since there's no reason to search other AST files - // for redeclarations (they can't exist). However, this is hard to - // do locally because the declaration hasn't necessarily loaded its - // declaration context yet. Also, local externs still have the function - // as their (semantic) declaration context, which is wrong and would - // break this optimize. - - if (FirstID && Owning && Reader.PendingDeclChainsKnown.insert(FirstID)) + if (FirstID && Owning && isRedeclarableDeclKind(DeclKind) && + Reader.PendingDeclChainsKnown.insert(FirstID)) Reader.PendingDeclChains.push_back(FirstID); } @@ -151,7 +144,7 @@ namespace clang { Owning = false; } }; - + /// \brief Class used to capture the result of searching for an existing /// declaration of a specific kind and name, along with the ability /// to update the place where this result was found (the declaration @@ -272,6 +265,7 @@ namespace clang { void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *BD); + void VisitEmptyDecl(EmptyDecl *D); std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); @@ -295,6 +289,7 @@ namespace clang { void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); }; } @@ -333,14 +328,6 @@ void ASTDeclReader::Visit(Decl *D) { Reader.PendingBodies[FD] = GetCurrentCursorOffset(); HasPendingBody = true; } - } else if (D->isTemplateParameter()) { - // If we have a fully initialized template parameter, we can now - // set its DeclContext. - DeclContext *SemaDC = cast<DeclContext>( - Reader.GetDecl(DeclContextIDForTemplateParmDecl)); - DeclContext *LexicalDC = cast<DeclContext>( - Reader.GetDecl(LexicalDeclContextIDForTemplateParmDecl)); - D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext()); } } @@ -350,8 +337,11 @@ void ASTDeclReader::VisitDecl(Decl *D) { // parameter immediately, because the template parameter might be // used in the formulation of its DeclContext. Use the translation // unit DeclContext as a placeholder. - DeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx); - LexicalDeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx); + GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(Record, Idx); + GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(Record, Idx); + Reader.addPendingDeclContextInfo(D, + SemaDCIDForTemplateParmDecl, + LexicalDCIDForTemplateParmDecl); D->setDeclContext(Reader.getContext().getTranslationUnitDecl()); } else { DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx); @@ -479,6 +469,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) { RD->setHasFlexibleArrayMember(Record[Idx++]); RD->setAnonymousStructOrUnion(Record[Idx++]); RD->setHasObjectMember(Record[Idx++]); + RD->setHasVolatileMember(Record[Idx++]); } void ASTDeclReader::VisitValueDecl(ValueDecl *VD) { @@ -513,9 +504,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { // FunctionDecl's body is handled last at ASTDeclReader::Visit, // after everything else is read. - + FD->SClass = (StorageClass)Record[Idx++]; - FD->SClassAsWritten = (StorageClass)Record[Idx++]; FD->IsInline = Record[Idx++]; FD->IsInlineSpecified = Record[Idx++]; FD->IsVirtualAsWritten = Record[Idx++]; @@ -528,6 +518,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->IsExplicitlyDefaulted = Record[Idx++]; FD->HasImplicitReturnZero = Record[Idx++]; FD->IsConstexpr = Record[Idx++]; + FD->HasSkippedBody = Record[Idx++]; + FD->HasCachedLinkage = true; + FD->CachedLinkage = Record[Idx++]; FD->EndRangeLoc = ReadSourceLocation(Record, Idx); switch ((FunctionDecl::TemplatedKind)Record[Idx++]) { @@ -652,6 +645,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { MD->setPropertyAccessor(Record[Idx++]); MD->setDefined(Record[Idx++]); MD->IsOverriding = Record[Idx++]; + MD->HasSkippedBody = Record[Idx++]; MD->IsRedeclaration = Record[Idx++]; MD->HasRedeclaration = Record[Idx++]; @@ -899,9 +893,8 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { void ASTDeclReader::VisitVarDecl(VarDecl *VD) { RedeclarableResult Redecl = VisitRedeclarable(VD); VisitDeclaratorDecl(VD); - + VD->VarDeclBits.SClass = (StorageClass)Record[Idx++]; - VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++]; VD->VarDeclBits.ThreadSpecified = Record[Idx++]; VD->VarDeclBits.InitStyle = Record[Idx++]; VD->VarDeclBits.ExceptionVar = Record[Idx++]; @@ -909,6 +902,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) { VD->VarDeclBits.CXXForRangeDecl = Record[Idx++]; VD->VarDeclBits.ARCPseudoStrong = Record[Idx++]; VD->VarDeclBits.IsConstexpr = Record[Idx++]; + VD->HasCachedLinkage = true; + VD->CachedLinkage = Record[Idx++]; // Only true variables (not parameters or implicit parameters) can be merged. if (VD->getKind() == Decl::Var) @@ -1083,11 +1078,7 @@ void ASTDeclReader::ReadCXXDefinitionData( const RecordData &Record, unsigned &Idx) { // Note: the caller has deserialized the IsLambda bit already. Data.UserDeclaredConstructor = Record[Idx++]; - Data.UserDeclaredCopyConstructor = Record[Idx++]; - Data.UserDeclaredMoveConstructor = Record[Idx++]; - Data.UserDeclaredCopyAssignment = Record[Idx++]; - Data.UserDeclaredMoveAssignment = Record[Idx++]; - Data.UserDeclaredDestructor = Record[Idx++]; + Data.UserDeclaredSpecialMembers = Record[Idx++]; Data.Aggregate = Record[Idx++]; Data.PlainOldData = Record[Idx++]; Data.Empty = Record[Idx++]; @@ -1101,25 +1092,26 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasMutableFields = Record[Idx++]; Data.HasOnlyCMembers = Record[Idx++]; Data.HasInClassInitializer = Record[Idx++]; - Data.HasTrivialDefaultConstructor = Record[Idx++]; + Data.HasUninitializedReferenceMember = Record[Idx++]; + Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++]; + Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++]; + Data.NeedOverloadResolutionForDestructor = Record[Idx++]; + Data.DefaultedMoveConstructorIsDeleted = Record[Idx++]; + Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++]; + Data.DefaultedDestructorIsDeleted = Record[Idx++]; + Data.HasTrivialSpecialMembers = Record[Idx++]; + Data.HasIrrelevantDestructor = Record[Idx++]; Data.HasConstexprNonCopyMoveConstructor = Record[Idx++]; Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++]; Data.HasConstexprDefaultConstructor = Record[Idx++]; - Data.HasTrivialCopyConstructor = Record[Idx++]; - Data.HasTrivialMoveConstructor = Record[Idx++]; - Data.HasTrivialCopyAssignment = Record[Idx++]; - Data.HasTrivialMoveAssignment = Record[Idx++]; - Data.HasTrivialDestructor = Record[Idx++]; - Data.HasIrrelevantDestructor = Record[Idx++]; Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++]; Data.ComputedVisibleConversions = Record[Idx++]; Data.UserProvidedDefaultConstructor = Record[Idx++]; - Data.DeclaredDefaultConstructor = Record[Idx++]; - Data.DeclaredCopyConstructor = Record[Idx++]; - Data.DeclaredMoveConstructor = Record[Idx++]; - Data.DeclaredCopyAssignment = Record[Idx++]; - Data.DeclaredMoveAssignment = Record[Idx++]; - Data.DeclaredDestructor = Record[Idx++]; + Data.DeclaredSpecialMembers = Record[Idx++]; + Data.ImplicitCopyConstructorHasConstParam = Record[Idx++]; + Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++]; + Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++]; + Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++]; Data.FailedImplicitMoveConstructor = Record[Idx++]; Data.FailedImplicitMoveAssignment = Record[Idx++]; @@ -1266,10 +1258,12 @@ void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { void ASTDeclReader::VisitFriendDecl(FriendDecl *D) { VisitDecl(D); - if (Record[Idx++]) - D->Friend = GetTypeSourceInfo(Record, Idx); - else + if (Record[Idx++]) // hasFriendDecl D->Friend = ReadDeclAs<NamedDecl>(Record, Idx); + else + D->Friend = GetTypeSourceInfo(Record, Idx); + for (unsigned i = 0; i != D->NumTPLists; ++i) + D->getTPLists()[i] = Reader.ReadTemplateParameterList(F, Record, Idx); D->NextFriend = Record[Idx++]; D->UnsupportedFriend = (Record[Idx++] != 0); D->FriendLoc = ReadSourceLocation(Record, Idx); @@ -1532,6 +1526,10 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { D->RParenLoc = ReadSourceLocation(Record, Idx); } +void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) { + VisitDecl(D); +} + std::pair<uint64_t, uint64_t> ASTDeclReader::VisitDeclContext(DeclContext *DC) { uint64_t LexicalOffset = Record[Idx++]; @@ -1563,7 +1561,8 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { // The result structure takes care to note that we need to load the // other declaration chains for this ID. - return RedeclarableResult(Reader, FirstDeclID); + return RedeclarableResult(Reader, FirstDeclID, + static_cast<T *>(D)->getKind()); } /// \brief Attempts to merge the given declaration (D) with another declaration @@ -1626,6 +1625,17 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, } } +void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { + VisitDecl(D); + unsigned NumVars = D->varlist_size(); + SmallVector<DeclRefExpr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F))); + } + D->setVars(Vars); +} + //===----------------------------------------------------------------------===// // Attribute Reading //===----------------------------------------------------------------------===// @@ -1811,6 +1821,30 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { if (DC->isTranslationUnit() && Reader.SemaObj) { IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver; + + // Temporarily consider the identifier to be up-to-date. We don't want to + // cause additional lookups here. + class UpToDateIdentifierRAII { + IdentifierInfo *II; + bool WasOutToDate; + + public: + explicit UpToDateIdentifierRAII(IdentifierInfo *II) + : II(II), WasOutToDate(false) + { + if (II) { + WasOutToDate = II->isOutOfDate(); + if (WasOutToDate) + II->setOutOfDate(false); + } + } + + ~UpToDateIdentifierRAII() { + if (WasOutToDate) + II->setOutOfDate(true); + } + } UpToDate(Name.getAsIdentifierInfo()); + for (IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); I != IEnd; ++I) { @@ -1820,10 +1854,11 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { } if (DC->isNamespace()) { - for (DeclContext::lookup_result R = DC->lookup(Name); - R.first != R.second; ++R.first) { - if (isSameEntity(*R.first, D)) - return FindExistingResult(Reader, D, *R.first); + DeclContext::lookup_result R = DC->lookup(Name); + for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; + ++I) { + if (isSameEntity(*I, D)) + return FindExistingResult(Reader, D, *I); } } @@ -1937,7 +1972,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { ASTDeclReader Reader(*this, *Loc.F, ID, RawLocation, Record,Idx); Decl *D = 0; - switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) { + switch ((DeclCode)DeclsCursor.readRecord(Code, Record)) { case DECL_CONTEXT_LEXICAL: case DECL_CONTEXT_VISIBLE: llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord"); @@ -2005,7 +2040,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { D = AccessSpecDecl::CreateDeserialized(Context, ID); break; case DECL_FRIEND: - D = FriendDecl::CreateDeserialized(Context, ID); + D = FriendDecl::CreateDeserialized(Context, ID, Record[Idx++]); break; case DECL_FRIEND_TEMPLATE: D = FriendTemplateDecl::CreateDeserialized(Context, ID); @@ -2109,6 +2144,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { // locations. D = ImportDecl::CreateDeserialized(Context, ID, Record.back()); break; + case DECL_OMP_THREADPRIVATE: + D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]); + break; + case DECL_EMPTY: + D = EmptyDecl::CreateDeserialized(Context, ID); + break; } assert(D && "Unknown declaration reading AST file"); @@ -2122,12 +2163,18 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { // If this declaration is also a declaration context, get the // offsets for its tables of lexical and visible declarations. if (DeclContext *DC = dyn_cast<DeclContext>(D)) { + // FIXME: This should really be + // DeclContext *LookupDC = DC->getPrimaryContext(); + // but that can walk the redeclaration chain, which might not work yet. + DeclContext *LookupDC = DC; + if (isa<NamespaceDecl>(DC)) + LookupDC = DC->getPrimaryContext(); std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC); if (Offsets.first || Offsets.second) { if (Offsets.first != 0) DC->setHasExternalLexicalStorage(true); if (Offsets.second != 0) - DC->setHasExternalVisibleStorage(true); + LookupDC->setHasExternalVisibleStorage(true); if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets, Loc.F->DeclContextInfos[DC])) return 0; @@ -2139,7 +2186,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { if (I != PendingVisibleUpdates.end()) { // There are updates. This means the context has external visible // storage, even if the original stored version didn't. - DC->setHasExternalVisibleStorage(true); + LookupDC->setHasExternalVisibleStorage(true); DeclContextVisibleUpdates &U = I->second; for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end(); UI != UE; ++UI) { @@ -2149,9 +2196,6 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { } PendingVisibleUpdates.erase(I); } - - if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage()) - DC->setMustBuildLookupTable(); } assert(Idx == Record.size()); @@ -2189,7 +2233,7 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { Cursor.JumpToBit(Offset); RecordData Record; unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.ReadRecord(Code, Record); + unsigned RecCode = Cursor.readRecord(Code, Record); (void)RecCode; assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!"); @@ -2226,7 +2270,7 @@ namespace { SmallVectorImpl<DeclID> &SearchDecls; llvm::SmallPtrSet<Decl *, 16> &Deserialized; GlobalDeclID CanonID; - llvm::SmallVector<Decl *, 4> Chain; + SmallVector<Decl *, 4> Chain; public: RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls, @@ -2307,7 +2351,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) { Decl *CanonDecl = D->getCanonicalDecl(); // Determine the set of declaration IDs we'll be searching for. - llvm::SmallVector<DeclID, 1> SearchDecls; + SmallVector<DeclID, 1> SearchDecls; GlobalDeclID CanonID = 0; if (D == CanonDecl) { SearchDecls.push_back(ID); // Always first. @@ -2404,7 +2448,7 @@ namespace { if (Tail) ASTDeclReader::setNextObjCCategory(Tail, Cat); else - Interface->setCategoryList(Cat); + Interface->setCategoryListRaw(Cat); Tail = Cat; } @@ -2419,13 +2463,15 @@ namespace { Tail(0) { // Populate the name -> category map with the set of known categories. - for (ObjCCategoryDecl *Cat = Interface->getCategoryList(); Cat; - Cat = Cat->getNextClassCategory()) { + for (ObjCInterfaceDecl::known_categories_iterator + Cat = Interface->known_categories_begin(), + CatEnd = Interface->known_categories_end(); + Cat != CatEnd; ++Cat) { if (Cat->getDeclName()) - NameCategoryMap[Cat->getDeclName()] = Cat; + NameCategoryMap[Cat->getDeclName()] = *Cat; // Keep track of the tail of the category list. - Tail = Cat; + Tail = *Cat; } } diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h index e5159e9..327da44 100644 --- a/lib/Serialization/ASTReaderInternals.h +++ b/lib/Serialization/ASTReaderInternals.h @@ -13,17 +13,19 @@ #ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H #define LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H -#include "clang/Basic/OnDiskHashTable.h" #include "clang/AST/DeclarationName.h" +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/Serialization/ASTBitCodes.h" #include "llvm/Support/Endian.h" -#include <utility> #include <sys/stat.h> +#include <utility> namespace clang { class ASTReader; class HeaderSearch; struct HeaderFileInfo; +class FileEntry; namespace serialization { @@ -77,8 +79,43 @@ public: unsigned DataLen); }; +/// \brief Base class for the trait describing the on-disk hash table for the +/// identifiers in an AST file. +/// +/// This class is not useful by itself; rather, it provides common +/// functionality for accessing the on-disk hash table of identifiers +/// in an AST file. Different subclasses customize that functionality +/// based on what information they are interested in. Those subclasses +/// must provide the \c data_type typedef and the ReadData operation, +/// only. +class ASTIdentifierLookupTraitBase { +public: + typedef StringRef external_key_type; + typedef StringRef internal_key_type; + + + static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { + return a == b; + } + + static unsigned ComputeHash(const internal_key_type& a); + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d); + + // This hopefully will just get inlined and removed by the optimizer. + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; } + + // This hopefully will just get inlined and removed by the optimizer. + static const external_key_type& + GetExternalKey(const internal_key_type& x) { return x; } + + static internal_key_type ReadKey(const unsigned char* d, unsigned n); +}; + /// \brief Class that performs lookup for an identifier stored in an AST file. -class ASTIdentifierLookupTrait { +class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase { ASTReader &Reader; ModuleFile &F; @@ -90,42 +127,15 @@ class ASTIdentifierLookupTrait { public: typedef IdentifierInfo * data_type; - typedef const std::pair<const char*, unsigned> external_key_type; - - typedef external_key_type internal_key_type; - ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F, IdentifierInfo *II = 0) : Reader(Reader), F(F), KnownII(II) { } - - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0 - : false; - } - - static unsigned ComputeHash(const internal_key_type& a); - - // This hopefully will just get inlined and removed by the optimizer. - static const internal_key_type& - GetInternalKey(const external_key_type& x) { return x; } - - // This hopefully will just get inlined and removed by the optimizer. - static const external_key_type& - GetExternalKey(const internal_key_type& x) { return x; } - - static std::pair<unsigned, unsigned> - ReadKeyDataLength(const unsigned char*& d); - - static std::pair<const char*, unsigned> - ReadKey(const unsigned char* d, unsigned n); - - IdentifierInfo *ReadData(const internal_key_type& k, - const unsigned char* d, - unsigned DataLen); + + data_type ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen); ASTReader &getReader() const { return Reader; } - }; /// \brief The on-disk hash table used to contain information about @@ -142,8 +152,8 @@ class ASTSelectorLookupTrait { public: struct data_type { SelectorID ID; - llvm::SmallVector<ObjCMethodDecl *, 2> Instance; - llvm::SmallVector<ObjCMethodDecl *, 2> Factory; + SmallVector<ObjCMethodDecl *, 2> Instance; + SmallVector<ObjCMethodDecl *, 2> Factory; }; typedef Selector external_key_type; @@ -187,47 +197,33 @@ class HeaderFileInfoTrait { ModuleFile &M; HeaderSearch *HS; const char *FrameworkStrings; - const char *SearchPath; - struct stat SearchPathStatBuf; - llvm::Optional<int> SearchPathStatResult; - - int StatSimpleCache(const char *Path, struct stat *StatBuf) { - if (Path == SearchPath) { - if (!SearchPathStatResult) - SearchPathStatResult = stat(Path, &SearchPathStatBuf); - - *StatBuf = SearchPathStatBuf; - return *SearchPathStatResult; - } - - return stat(Path, StatBuf); - } - + public: - typedef const char *external_key_type; - typedef const char *internal_key_type; + typedef const FileEntry *external_key_type; + + struct internal_key_type { + off_t Size; + time_t ModTime; + const char *Filename; + }; + typedef const internal_key_type &internal_key_ref; typedef HeaderFileInfo data_type; HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS, - const char *FrameworkStrings, - const char *SearchPath = 0) - : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings), - SearchPath(SearchPath) { } + const char *FrameworkStrings) + : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { } - static unsigned ComputeHash(const char *path); - static internal_key_type GetInternalKey(const char *path); - bool EqualKey(internal_key_type a, internal_key_type b); + static unsigned ComputeHash(internal_key_ref ikey); + static internal_key_type GetInternalKey(const FileEntry *FE); + bool EqualKey(internal_key_ref a, internal_key_ref b); static std::pair<unsigned, unsigned> ReadKeyDataLength(const unsigned char*& d); - static internal_key_type ReadKey(const unsigned char *d, unsigned) { - return (const char *)d; - } + static internal_key_type ReadKey(const unsigned char *d, unsigned); - data_type ReadData(const internal_key_type, const unsigned char *d, - unsigned DataLen); + data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen); }; /// \brief The on-disk hash table used for known header files. diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 367f75f..078ecb7 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -132,6 +132,8 @@ void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) { void ASTStmtReader::VisitSwitchCase(SwitchCase *S) { VisitStmt(S); Reader.RecordSwitchCaseID(S, Record[Idx++]); + S->setKeywordLoc(ReadSourceLocation(Record, Idx)); + S->setColonLoc(ReadSourceLocation(Record, Idx)); } void ASTStmtReader::VisitCaseStmt(CaseStmt *S) { @@ -139,16 +141,12 @@ void ASTStmtReader::VisitCaseStmt(CaseStmt *S) { S->setLHS(Reader.ReadSubExpr()); S->setRHS(Reader.ReadSubExpr()); S->setSubStmt(Reader.ReadSubStmt()); - S->setCaseLoc(ReadSourceLocation(Record, Idx)); S->setEllipsisLoc(ReadSourceLocation(Record, Idx)); - S->setColonLoc(ReadSourceLocation(Record, Idx)); } void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) { VisitSwitchCase(S); S->setSubStmt(Reader.ReadSubStmt()); - S->setDefaultLoc(ReadSourceLocation(Record, Idx)); - S->setColonLoc(ReadSourceLocation(Record, Idx)); } void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { @@ -380,8 +378,10 @@ void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) { void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) { VisitExpr(E); - E->setValue(Reader.getContext(), Reader.ReadAPFloat(Record, Idx)); + E->setRawSemantics(static_cast<Stmt::APFloatSemantics>(Record[Idx++])); E->setExact(Record[Idx++]); + E->setValue(Reader.getContext(), + Reader.ReadAPFloat(Record, E->getSemantics(), Idx)); E->setLocation(ReadSourceLocation(Record, Idx)); } @@ -528,6 +528,7 @@ void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) { VisitExpr(E); E->setBase(Reader.ReadSubExpr()); E->setIsaMemberLoc(ReadSourceLocation(Record, Idx)); + E->setOpLoc(ReadSourceLocation(Record, Idx)); E->setArrow(Record[Idx++]); } @@ -892,6 +893,7 @@ void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { VisitExpr(E); E->setDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx)); E->setLocation(ReadSourceLocation(Record, Idx)); + E->setOpLoc(ReadSourceLocation(Record, Idx)); E->setBase(Reader.ReadSubExpr()); E->setIsArrow(Record[Idx++]); E->setIsFreeIvar(Record[Idx++]); @@ -1102,6 +1104,7 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { E->setLocation(ReadSourceLocation(Record, Idx)); E->setElidable(Record[Idx++]); E->setHadMultipleCandidates(Record[Idx++]); + E->setListInitialization(Record[Idx++]); E->setRequiresZeroInitialization(Record[Idx++]); E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]); E->ParenRange = ReadSourceRange(Record, Idx); @@ -1146,6 +1149,8 @@ void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { SourceRange R = ReadSourceRange(Record, Idx); E->Loc = R.getBegin(); E->RParenLoc = R.getEnd(); + R = ReadSourceRange(Record, Idx); + E->AngleBrackets = R; } void ASTStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { @@ -1596,36 +1601,27 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { Stmt::EmptyShell Empty; while (true) { - unsigned Code = Cursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (Cursor.ReadBlockEnd()) { - Error("error at end of block in AST file"); - return 0; - } + llvm::BitstreamEntry Entry = Cursor.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: // Handled for us already. + case llvm::BitstreamEntry::Error: + Error("malformed block record in AST file"); + return 0; + case llvm::BitstreamEntry::EndBlock: + goto Done; + case llvm::BitstreamEntry::Record: + // The interesting case. break; } - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - Cursor.ReadSubBlockID(); - if (Cursor.SkipBlock()) { - Error("malformed block record in AST file"); - return 0; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Cursor.ReadAbbrevRecord(); - continue; - } Stmt *S = 0; Idx = 0; Record.clear(); bool Finished = false; bool IsStmtReference = false; - switch ((StmtCode)Cursor.ReadRecord(Code, Record)) { + switch ((StmtCode)Cursor.readRecord(Entry.ID, Record)) { case STMT_STOP: Finished = true; break; @@ -1868,7 +1864,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case EXPR_INIT_LIST: - S = new (Context) InitListExpr(getContext(), Empty); + S = new (Context) InitListExpr(Empty); break; case EXPR_DESIGNATED_INIT: @@ -2250,11 +2246,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { assert(Idx == Record.size() && "Invalid deserialization of statement"); StmtStack.push_back(S); } - -#ifndef NDEBUG +Done: assert(StmtStack.size() > PrevNumStmts && "Read too many sub stmts!"); assert(StmtStack.size() == PrevNumStmts + 1 && "Extra expressions on stack!"); -#endif - return StmtStack.pop_back_val(); } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index a2e8b71..cf93d1c 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -13,24 +13,15 @@ #include "clang/Serialization/ASTWriter.h" #include "ASTCommon.h" -#include "clang/Sema/Sema.h" -#include "clang/Sema/IdentifierResolver.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclContextInternals.h" -#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" -#include "clang/Serialization/ASTReader.h" -#include "clang/Lex/HeaderSearchOptions.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/PreprocessorOptions.h" -#include "clang/Lex/HeaderSearch.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/OnDiskHashTable.h" @@ -40,8 +31,18 @@ #include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" #include "clang/Basic/VersionTuple.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/Sema.h" +#include "clang/Serialization/ASTReader.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/FileSystem.h" @@ -353,7 +354,7 @@ ASTTypeWriter::VisitDependentTemplateSpecializationType( void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) { Writer.AddTypeRef(T->getPattern(), Record); - if (llvm::Optional<unsigned> NumExpansions = T->getNumExpansions()) + if (Optional<unsigned> NumExpansions = T->getNumExpansions()) Record.push_back(*NumExpansions + 1); else Record.push_back(0); @@ -777,6 +778,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(TARGET_OPTIONS); RECORD(ORIGINAL_FILE); RECORD(ORIGINAL_PCH_DIR); + RECORD(ORIGINAL_FILE_ID); RECORD(INPUT_FILE_OFFSETS); RECORD(DIAGNOSTIC_OPTIONS); RECORD(FILE_SYSTEM_OPTIONS); @@ -797,7 +799,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); RECORD(UNUSED_FILESCOPED_DECLS); - RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS); + RECORD(LOCALLY_SCOPED_EXTERN_C_DECLS); RECORD(SELECTOR_OFFSETS); RECORD(METHOD_POOL); RECORD(PP_COUNTER_VALUE); @@ -823,6 +825,7 @@ 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); @@ -832,7 +835,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(LOCAL_REDECLARATIONS); RECORD(OBJC_CATEGORIES); RECORD(MACRO_OFFSET); - RECORD(MACRO_UPDATES); + RECORD(MACRO_TABLE); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -1020,7 +1023,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, // Imports if (Chain) { serialization::ModuleManager &Mgr = Chain->getModuleManager(); - llvm::SmallVector<char, 128> ModulePaths; + SmallVector<char, 128> ModulePaths; Record.clear(); for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end(); @@ -1030,7 +1033,9 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, continue; Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding - // FIXME: Write import location, once it matters. + AddSourceLocation((*M)->ImportLoc, Record); + Record.push_back((*M)->File->getSize()); + Record.push_back((*M)->File->getModificationTime()); // FIXME: This writes the absolute path for AST files we depend on. const std::string &FileName = (*M)->FileName; Record.push_back(FileName.size()); @@ -1047,12 +1052,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ Record.push_back(static_cast<unsigned>(LangOpts.get##Name())); #include "clang/Basic/LangOptions.def" +#define SANITIZER(NAME, ID) Record.push_back(LangOpts.Sanitize.ID); +#include "clang/Basic/Sanitizers.def" Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind()); AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record); Record.push_back(LangOpts.CurrentModule.size()); Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end()); + + // 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); + } + Stream.EmitRecord(LANGUAGE_OPTIONS, Record); // Target options. @@ -1108,11 +1125,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I]; AddString(Entry.Path, Record); Record.push_back(static_cast<unsigned>(Entry.Group)); - Record.push_back(Entry.IsUserSupplied); Record.push_back(Entry.IsFramework); Record.push_back(Entry.IgnoreSysRoot); - Record.push_back(Entry.IsInternal); - Record.push_back(Entry.ImplicitExternC); } // System header prefixes. @@ -1180,6 +1194,10 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); } + Record.clear(); + Record.push_back(SM.getMainFileID().getOpaqueValue()); + Stream.EmitRecord(ORIGINAL_FILE_ID, Record); + // Original PCH directory if (!OutputFile.empty() && OutputFile != "-") { BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); @@ -1197,11 +1215,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir); } - WriteInputFiles(Context.SourceMgr, isysroot); + WriteInputFiles(Context.SourceMgr, + PP.getHeaderSearchInfo().getHeaderSearchOpts(), + isysroot); Stream.ExitBlock(); } -void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { +namespace { + /// \brief An input file. + struct InputFileEntry { + const FileEntry *File; + bool IsSystemFile; + bool BufferOverridden; + }; +} + +void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, + HeaderSearchOptions &HSOpts, + StringRef isysroot) { using namespace llvm; Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); RecordData Record; @@ -1216,8 +1247,9 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev); - // Write out all of the input files. - std::vector<uint32_t> InputFileOffsets; + // Get all ContentCache objects for files, sorted by whether the file is a + // system one or not. System files go at the back, users files at the front. + std::deque<InputFileEntry> SortedFiles; for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { // Get this source location entry. const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); @@ -1230,28 +1262,67 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { if (!Cache->OrigEntry) continue; + InputFileEntry Entry; + Entry.File = Cache->OrigEntry; + Entry.IsSystemFile = Cache->IsSystemFile; + Entry.BufferOverridden = Cache->BufferOverridden; + if (Cache->IsSystemFile) + SortedFiles.push_back(Entry); + else + SortedFiles.push_front(Entry); + } + + // If we have an isysroot for a Darwin SDK, include its SDKSettings.plist in + // the set of (non-system) input files. This is simple heuristic for + // detecting whether the system headers may have changed, because it is too + // expensive to stat() all of the system headers. + FileManager &FileMgr = SourceMgr.getFileManager(); + if (!HSOpts.Sysroot.empty() && !Chain) { + llvm::SmallString<128> SDKSettingsFileName(HSOpts.Sysroot); + llvm::sys::path::append(SDKSettingsFileName, "SDKSettings.plist"); + if (const FileEntry *SDKSettingsFile = FileMgr.getFile(SDKSettingsFileName)) { + InputFileEntry Entry = { SDKSettingsFile, false, false }; + SortedFiles.push_front(Entry); + } + } + + unsigned UserFilesNum = 0; + // Write out all of the input files. + std::vector<uint32_t> InputFileOffsets; + for (std::deque<InputFileEntry>::iterator + I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) { + const InputFileEntry &Entry = *I; + + uint32_t &InputFileID = InputFileIDs[Entry.File]; + if (InputFileID != 0) + continue; // already recorded this file. + // Record this entry's offset. InputFileOffsets.push_back(Stream.GetCurrentBitNo()); - InputFileIDs[Cache->OrigEntry] = InputFileOffsets.size(); + + InputFileID = InputFileOffsets.size(); + + 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(Cache->OrigEntry->getSize()); - Record.push_back(Cache->OrigEntry->getModificationTime()); + Record.push_back(Entry.File->getSize()); + Record.push_back(Entry.File->getModificationTime()); // Whether this file was overridden. - Record.push_back(Cache->BufferOverridden); + Record.push_back(Entry.BufferOverridden); // Turn the file name into an absolute path, if it isn't already. - const char *Filename = Cache->OrigEntry->getName(); + const char *Filename = Entry.File->getName(); SmallString<128> FilePath(Filename); // Ask the file manager to fixup the relative path for us. This will // honor the working directory. - SourceMgr.getFileManager().FixupRelativePath(FilePath); + FileMgr.FixupRelativePath(FilePath); // FIXME: This call to make_absolute shouldn't be necessary, the // call to FixupRelativePath should always return an absolute path. @@ -1262,13 +1333,15 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename); } - + Stream.ExitBlock(); // Create input file offsets abbreviation. BitCodeAbbrev *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 + // input files OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev); @@ -1276,58 +1349,11 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { Record.clear(); Record.push_back(INPUT_FILE_OFFSETS); Record.push_back(InputFileOffsets.size()); + Record.push_back(UserFilesNum); Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets)); } //===----------------------------------------------------------------------===// -// stat cache Serialization -//===----------------------------------------------------------------------===// - -namespace { -// Trait used for the on-disk hash table of stat cache results. -class ASTStatCacheTrait { -public: - typedef const char * key_type; - typedef key_type key_type_ref; - - typedef struct stat data_type; - typedef const data_type &data_type_ref; - - static unsigned ComputeHash(const char *path) { - return llvm::HashString(path); - } - - std::pair<unsigned,unsigned> - EmitKeyDataLength(raw_ostream& Out, const char *path, - data_type_ref Data) { - unsigned StrLen = strlen(path); - clang::io::Emit16(Out, StrLen); - unsigned DataLen = 4 + 4 + 2 + 8 + 8; - clang::io::Emit8(Out, DataLen); - return std::make_pair(StrLen + 1, DataLen); - } - - void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) { - Out.write(path, KeyLen); - } - - void EmitData(raw_ostream &Out, key_type_ref, - data_type_ref Data, unsigned DataLen) { - using namespace clang::io; - uint64_t Start = Out.tell(); (void)Start; - - Emit32(Out, (uint32_t) Data.st_ino); - Emit32(Out, (uint32_t) Data.st_dev); - Emit16(Out, (uint16_t) Data.st_mode); - Emit64(Out, (uint64_t) Data.st_mtime); - Emit64(Out, (uint64_t) Data.st_size); - - assert(Out.tell() - Start == DataLen && "Wrong data length"); - } -}; -} // end anonymous namespace - -//===----------------------------------------------------------------------===// // Source Manager Serialization //===----------------------------------------------------------------------===// @@ -1391,44 +1417,53 @@ namespace { // Trait used for the on-disk hash table of header search information. class HeaderFileInfoTrait { ASTWriter &Writer; + const HeaderSearch &HS; // Keep track of the framework names we've used during serialization. SmallVector<char, 128> FrameworkStringData; llvm::StringMap<unsigned> FrameworkNameOffset; public: - HeaderFileInfoTrait(ASTWriter &Writer) - : Writer(Writer) { } + HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS) + : Writer(Writer), HS(HS) { } - typedef const char *key_type; - typedef key_type key_type_ref; + struct key_type { + const FileEntry *FE; + const char *Filename; + }; + typedef const key_type &key_type_ref; typedef HeaderFileInfo data_type; typedef const data_type &data_type_ref; - static unsigned ComputeHash(const char *path) { - // The hash is based only on the filename portion of the key, so that the - // reader can match based on filenames when symlinking or excess path - // elements ("foo/../", "../") change the form of the name. However, - // complete path is still the key. - return llvm::HashString(llvm::sys::path::filename(path)); + static unsigned 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. + return llvm::hash_combine(key.FE->getSize(), + key.FE->getModificationTime()); } std::pair<unsigned,unsigned> - EmitKeyDataLength(raw_ostream& Out, const char *path, - data_type_ref Data) { - unsigned StrLen = strlen(path); - clang::io::Emit16(Out, StrLen); + EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) { + unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8; + clang::io::Emit16(Out, KeyLen); unsigned DataLen = 1 + 2 + 4 + 4; + if (Data.isModuleHeader) + DataLen += 4; clang::io::Emit8(Out, DataLen); - return std::make_pair(StrLen + 1, DataLen); + return std::make_pair(KeyLen, DataLen); } - void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) { - Out.write(path, KeyLen); + void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) { + clang::io::Emit64(Out, key.FE->getSize()); + KeyLen -= 8; + clang::io::Emit64(Out, key.FE->getModificationTime()); + KeyLen -= 8; + Out.write(key.Filename, KeyLen); } - void EmitData(raw_ostream &Out, key_type_ref, + void EmitData(raw_ostream &Out, key_type_ref key, data_type_ref Data, unsigned DataLen) { using namespace clang::io; uint64_t Start = Out.tell(); (void)Start; @@ -1462,7 +1497,12 @@ namespace { Offset = Pos->second; } Emit32(Out, Offset); - + + if (Data.isModuleHeader) { + Module *Mod = HS.findModuleForHeader(key.FE); + Emit32(Out, Writer.getExistingSubmoduleID(Mod)); + } + assert(Out.tell() - Start == DataLen && "Wrong data length"); } @@ -1481,7 +1521,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { if (FilesByUID.size() > HS.header_file_size()) FilesByUID.resize(HS.header_file_size()); - HeaderFileInfoTrait GeneratorTrait(*this); + HeaderFileInfoTrait GeneratorTrait(*this, HS); OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator; SmallVector<const char *, 4> SavedStrings; unsigned NumHeaderSearchEntries = 0; @@ -1507,7 +1547,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { SavedStrings.push_back(Filename); } - Generator.insert(Filename, HFI, GeneratorTrait); + HeaderFileInfoTrait::key_type key = { File, Filename }; + Generator.insert(key, HFI, GeneratorTrait); ++NumHeaderSearchEntries; } @@ -1542,7 +1583,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { // Free all of the strings we had to duplicate. for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I) - free((void*)SavedStrings[I]); + free(const_cast<char *>(SavedStrings[I])); } /// \brief Writes the block containing the serialized form of the @@ -1746,14 +1787,67 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Preprocessor Serialization //===----------------------------------------------------------------------===// -static int compareMacroDefinitions(const void *XPtr, const void *YPtr) { - const std::pair<const IdentifierInfo *, MacroInfo *> &X = - *(const std::pair<const IdentifierInfo *, MacroInfo *>*)XPtr; - const std::pair<const IdentifierInfo *, MacroInfo *> &Y = - *(const std::pair<const IdentifierInfo *, MacroInfo *>*)YPtr; +namespace { +class ASTMacroTableTrait { +public: + typedef IdentID key_type; + typedef key_type key_type_ref; + + struct Data { + uint32_t MacroDirectivesOffset; + }; + + typedef Data data_type; + typedef const data_type &data_type_ref; + + static unsigned ComputeHash(IdentID IdID) { + return llvm::hash_value(IdID); + } + + std::pair<unsigned,unsigned> + static EmitKeyDataLength(raw_ostream& Out, + key_type_ref Key, data_type_ref Data) { + unsigned KeyLen = 4; // IdentID. + unsigned DataLen = 4; // MacroDirectivesOffset. + return std::make_pair(KeyLen, DataLen); + } + + static void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) { + clang::io::Emit32(Out, Key); + } + + static void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data, + unsigned) { + clang::io::Emit32(Out, Data.MacroDirectivesOffset); + } +}; +} // end anonymous namespace + +static int compareMacroDirectives(const void *XPtr, const void *YPtr) { + const std::pair<const IdentifierInfo *, MacroDirective *> &X = + *(const std::pair<const IdentifierInfo *, MacroDirective *>*)XPtr; + const std::pair<const IdentifierInfo *, MacroDirective *> &Y = + *(const std::pair<const IdentifierInfo *, MacroDirective *>*)YPtr; return X.first->getName().compare(Y.first->getName()); } +static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule, + const Preprocessor &PP) { + if (MacroInfo *MI = MD->getMacroInfo()) + if (MI->isBuiltinMacro()) + return true; + + if (IsModule) { + SourceLocation Loc = MD->getLocation(); + if (Loc.isInvalid()) + return true; + if (PP.getSourceManager().getFileID(Loc) == PP.getPredefinesFileID()) + return true; + } + + return false; +} + /// \brief Writes the block containing the serialized form of the /// preprocessor. /// @@ -1780,26 +1874,73 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n"); - // Loop over all the macro definitions that are live at the end of the file, + // Loop over all the macro directives that are live at the end of the file, // emitting each to the PP section. - // Construct the list of macro definitions that need to be serialized. - SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2> - MacrosToEmit; - llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen; - for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0), - E = PP.macro_end(Chain == 0); + // Construct the list of macro directives that need to be serialized. + SmallVector<std::pair<const IdentifierInfo *, MacroDirective *>, 2> + MacroDirectives; + for (Preprocessor::macro_iterator + I = PP.macro_begin(/*IncludeExternalMacros=*/false), + E = PP.macro_end(/*IncludeExternalMacros=*/false); I != E; ++I) { - if (!IsModule || I->second->isPublic()) { - MacroDefinitionsSeen.insert(I->first); - MacrosToEmit.push_back(std::make_pair(I->first, I->second)); - } + MacroDirectives.push_back(std::make_pair(I->first, I->second)); } // Sort the set of macro definitions that need to be serialized by the // name of the macro, to provide a stable ordering. - llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(), - &compareMacroDefinitions); + llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(), + &compareMacroDirectives); + + OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator; + + // Emit the macro directives as a list and associate the offset with the + // identifier they belong to. + for (unsigned I = 0, N = MacroDirectives.size(); I != N; ++I) { + const IdentifierInfo *Name = MacroDirectives[I].first; + uint64_t MacroDirectiveOffset = Stream.GetCurrentBitNo(); + MacroDirective *MD = MacroDirectives[I].second; + + // If the macro or identifier need no updates, don't write the macro history + // for this one. + // FIXME: Chain the macro history instead of re-writing it. + if (MD->isFromPCH() && + Name->isFromAST() && !Name->hasChangedSinceDeserialization()) + continue; + + // Emit the macro directives in reverse source order. + for (; MD; MD = MD->getPrevious()) { + if (MD->isHidden()) + continue; + if (shouldIgnoreMacro(MD, IsModule, PP)) + continue; + + AddSourceLocation(MD->getLocation(), Record); + Record.push_back(MD->getKind()); + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) { + MacroID InfoID = getMacroRef(DefMD->getInfo(), Name); + Record.push_back(InfoID); + Record.push_back(DefMD->isImported()); + Record.push_back(DefMD->isAmbiguous()); + + } else if (VisibilityMacroDirective * + VisMD = dyn_cast<VisibilityMacroDirective>(MD)) { + Record.push_back(VisMD->isPublic()); + } + } + if (Record.empty()) + continue; + + Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record); + Record.clear(); + + IdentMacroDirectivesOffsetMap[Name] = MacroDirectiveOffset; + + IdentID NameID = getIdentifierRef(Name); + ASTMacroTableTrait::Data data; + data.MacroDirectivesOffset = MacroDirectiveOffset; + Generator.insert(NameID, data); + } /// \brief Offsets of each of the macros into the bitstream, indexed by /// the local macro ID @@ -1809,95 +1950,107 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { /// defined. std::vector<uint32_t> MacroOffsets; - for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) { - const IdentifierInfo *Name = MacrosToEmit[I].first; + for (unsigned I = 0, N = MacroInfosToEmit.size(); I != N; ++I) { + const IdentifierInfo *Name = MacroInfosToEmit[I].Name; + MacroInfo *MI = MacroInfosToEmit[I].MI; + MacroID ID = MacroInfosToEmit[I].ID; - for (MacroInfo *MI = MacrosToEmit[I].second; MI; - MI = MI->getPreviousDefinition()) { - MacroID ID = getMacroRef(MI); - if (!ID) - continue; + if (ID < FirstMacroID) { + assert(0 && "Loaded MacroInfo entered MacroInfosToEmit ?"); + continue; + } - // Skip macros from a AST file if we're chaining. - if (Chain && MI->isFromAST() && !MI->hasChangedAfterLoad()) - continue; + // Record the local offset of this macro. + unsigned Index = ID - FirstMacroID; + if (Index == MacroOffsets.size()) + MacroOffsets.push_back(Stream.GetCurrentBitNo()); + else { + if (Index > MacroOffsets.size()) + MacroOffsets.resize(Index + 1); - if (ID < FirstMacroID) { - // This will have been dealt with via an update record. - assert(MacroUpdates.count(MI) > 0 && "Missing macro update"); - continue; - } + MacroOffsets[Index] = Stream.GetCurrentBitNo(); + } - // Record the local offset of this macro. - unsigned Index = ID - FirstMacroID; - if (Index == MacroOffsets.size()) - MacroOffsets.push_back(Stream.GetCurrentBitNo()); - else { - if (Index > MacroOffsets.size()) - MacroOffsets.resize(Index + 1); + AddIdentifierRef(Name, Record); + Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc())); + AddSourceLocation(MI->getDefinitionLoc(), Record); + AddSourceLocation(MI->getDefinitionEndLoc(), Record); + Record.push_back(MI->isUsed()); + unsigned Code; + if (MI->isObjectLike()) { + Code = PP_MACRO_OBJECT_LIKE; + } else { + Code = PP_MACRO_FUNCTION_LIKE; - MacroOffsets[Index] = Stream.GetCurrentBitNo(); - } + Record.push_back(MI->isC99Varargs()); + Record.push_back(MI->isGNUVarargs()); + Record.push_back(MI->hasCommaPasting()); + Record.push_back(MI->getNumArgs()); + for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); + I != E; ++I) + AddIdentifierRef(*I, Record); + } - AddIdentifierRef(Name, Record); - addMacroRef(MI, Record); - Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc())); - AddSourceLocation(MI->getDefinitionLoc(), Record); - AddSourceLocation(MI->getUndefLoc(), Record); - Record.push_back(MI->isUsed()); - Record.push_back(MI->isPublic()); - AddSourceLocation(MI->getVisibilityLocation(), Record); - unsigned Code; - if (MI->isObjectLike()) { - Code = PP_MACRO_OBJECT_LIKE; - } else { - Code = PP_MACRO_FUNCTION_LIKE; - - Record.push_back(MI->isC99Varargs()); - Record.push_back(MI->isGNUVarargs()); - Record.push_back(MI->getNumArgs()); - for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); - I != E; ++I) - AddIdentifierRef(*I, Record); - } + // If we have a detailed preprocessing record, record the macro definition + // ID that corresponds to this macro. + if (PPRec) + Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); - // If we have a detailed preprocessing record, record the macro definition - // ID that corresponds to this macro. - if (PPRec) - Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); + Stream.EmitRecord(Code, Record); + Record.clear(); - Stream.EmitRecord(Code, Record); + // Emit the tokens array. + for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { + // Note that we know that the preprocessor does not have any annotation + // tokens in it because they are created by the parser, and thus can't + // be in a macro definition. + const Token &Tok = MI->getReplacementToken(TokNo); + + Record.push_back(Tok.getLocation().getRawEncoding()); + Record.push_back(Tok.getLength()); + + // FIXME: When reading literal tokens, reconstruct the literal pointer + // if it is needed. + AddIdentifierRef(Tok.getIdentifierInfo(), Record); + // FIXME: Should translate token kind to a stable encoding. + Record.push_back(Tok.getKind()); + // FIXME: Should translate token flags to a stable encoding. + Record.push_back(Tok.getFlags()); + + Stream.EmitRecord(PP_TOKEN, Record); Record.clear(); - - // Emit the tokens array. - for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { - // Note that we know that the preprocessor does not have any annotation - // tokens in it because they are created by the parser, and thus can't - // be in a macro definition. - const Token &Tok = MI->getReplacementToken(TokNo); - - Record.push_back(Tok.getLocation().getRawEncoding()); - Record.push_back(Tok.getLength()); - - // FIXME: When reading literal tokens, reconstruct the literal pointer - // if it is needed. - AddIdentifierRef(Tok.getIdentifierInfo(), Record); - // FIXME: Should translate token kind to a stable encoding. - Record.push_back(Tok.getKind()); - // FIXME: Should translate token flags to a stable encoding. - Record.push_back(Tok.getFlags()); - - Stream.EmitRecord(PP_TOKEN, Record); - Record.clear(); - } - ++NumMacros; } + ++NumMacros; } + Stream.ExitBlock(); - // Write the offsets table for macro IDs. + // Create the on-disk hash table in a buffer. + SmallString<4096> MacroTable; + uint32_t BucketOffset; + { + llvm::raw_svector_ostream Out(MacroTable); + // Make sure that no bucket is at offset 0 + clang::io::Emit32(Out, 0); + BucketOffset = Generator.Emit(Out); + } + + // Write the macro table using namespace llvm; BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MACRO_TABLE)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MacroTableAbbrev = Stream.EmitAbbrev(Abbrev); + + Record.push_back(MACRO_TABLE); + Record.push_back(BucketOffset); + Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable.str()); + Record.clear(); + + // Write the offsets table for macro IDs. + using namespace llvm; + Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID @@ -2019,6 +2172,18 @@ unsigned ASTWriter::getSubmoduleID(Module *Mod) { return SubmoduleIDs[Mod] = NextSubmoduleID++; } +unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const { + if (!Mod) + return 0; + + llvm::DenseMap<Module *, unsigned>::const_iterator + Known = SubmoduleIDs.find(Mod); + if (Known != SubmoduleIDs.end()) + return Known->second; + + return 0; +} + /// \brief Compute the number of modules within the given tree (including the /// given module). static unsigned getNumberOfModules(Module *Mod) { @@ -2062,6 +2227,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild... + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev); @@ -2095,6 +2261,23 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev); + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev); + + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name + unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev); + + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message + unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev); + // Write the submodule metadata block. RecordData Record; Record.push_back(getNumberOfModules(WritingModule)); @@ -2125,6 +2308,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { 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 requirements. @@ -2163,11 +2347,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record, Mod->ExcludedHeaders[I]->getName()); } - for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) { + ArrayRef<const FileEntry *> + TopHeaders = Mod->getTopHeaders(PP->getFileManager()); + for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) { Record.clear(); Record.push_back(SUBMODULE_TOPHEADER); Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, - Mod->TopHeaders[I]->getName()); + TopHeaders[I]->getName()); } // Emit the imports. @@ -2197,7 +2383,35 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { } Stream.EmitRecord(SUBMODULE_EXPORTS, Record); } - + + // 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); + } + + // 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); + } + + // 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]); + } + // Queue up the submodules of this module. for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); @@ -2230,8 +2444,14 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) { return getSubmoduleID(OwningMod); } -void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) { - // FIXME: Make it work properly with modules. +void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, + bool isModule) { + // Make sure set diagnostic pragmas don't affect the translation unit that + // imports the module. + // FIXME: Make diagnostic pragma sections work properly with modules. + if (isModule) + return; + llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64> DiagStateIDMap; unsigned CurrID = 0; @@ -2664,7 +2884,7 @@ class ASTIdentifierTableTrait { /// \brief Determines whether this is an "interesting" identifier /// that needs a full IdentifierInfo structure written into the hash /// table. - bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) { + bool isInterestingIdentifier(IdentifierInfo *II, MacroDirective *&Macro) { if (II->isPoisoned() || II->isExtensionToken() || II->getObjCOrBuiltinID() || @@ -2675,16 +2895,101 @@ class ASTIdentifierTableTrait { return hadMacroDefinition(II, Macro); } - bool hadMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) { + bool hadMacroDefinition(IdentifierInfo *II, MacroDirective *&Macro) { if (!II->hadMacroDefinition()) return false; - if (Macro || (Macro = PP.getMacroInfoHistory(II))) - return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic()); + if (Macro || (Macro = PP.getMacroDirectiveHistory(II))) { + if (!IsModule) + return !shouldIgnoreMacro(Macro, IsModule, PP); + SubmoduleID ModID; + if (getFirstPublicSubmoduleMacro(Macro, ModID)) + return true; + } return false; } + DefMacroDirective *getFirstPublicSubmoduleMacro(MacroDirective *MD, + SubmoduleID &ModID) { + ModID = 0; + if (DefMacroDirective *DefMD = getPublicSubmoduleMacro(MD, ModID)) + if (!shouldIgnoreMacro(DefMD, IsModule, PP)) + return DefMD; + return 0; + } + + DefMacroDirective *getNextPublicSubmoduleMacro(DefMacroDirective *MD, + SubmoduleID &ModID) { + if (DefMacroDirective * + DefMD = getPublicSubmoduleMacro(MD->getPrevious(), ModID)) + if (!shouldIgnoreMacro(DefMD, IsModule, PP)) + return DefMD; + return 0; + } + + /// \brief Traverses the macro directives history and returns the latest + /// macro that is public and not undefined in the same submodule. + /// A macro that is defined in submodule A and undefined in submodule B, + /// will still be considered as defined/exported from submodule A. + DefMacroDirective *getPublicSubmoduleMacro(MacroDirective *MD, + SubmoduleID &ModID) { + if (!MD) + return 0; + + SubmoduleID OrigModID = ModID; + bool isUndefined = false; + Optional<bool> isPublic; + for (; MD; MD = MD->getPrevious()) { + if (MD->isHidden()) + continue; + + SubmoduleID ThisModID = getSubmoduleID(MD); + if (ThisModID == 0) { + isUndefined = false; + isPublic = Optional<bool>(); + continue; + } + if (ThisModID != ModID){ + ModID = ThisModID; + isUndefined = false; + isPublic = Optional<bool>(); + } + // We are looking for a definition in a different submodule than the one + // that we started with. If a submodule has re-definitions of the same + // macro, only the last definition will be used as the "exported" one. + if (ModID == OrigModID) + continue; + + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) { + if (!isUndefined && (!isPublic.hasValue() || isPublic.getValue())) + return DefMD; + continue; + } + + if (isa<UndefMacroDirective>(MD)) { + isUndefined = true; + continue; + } + + VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD); + if (!isPublic.hasValue()) + isPublic = VisMD->isPublic(); + } + + return 0; + } + + SubmoduleID getSubmoduleID(MacroDirective *MD) { + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) { + MacroInfo *MI = DefMD->getInfo(); + if (unsigned ID = MI->getOwningModuleID()) + return ID; + return Writer.inferSubmoduleIDFromLocation(MI->getDefinitionLoc()); + } + return Writer.inferSubmoduleIDFromLocation(MD->getLocation()); + } + public: typedef IdentifierInfo* key_type; typedef key_type key_type_ref; @@ -2704,17 +3009,21 @@ public: EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) { unsigned KeyLen = II->getLength() + 1; unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 - MacroInfo *Macro = 0; + MacroDirective *Macro = 0; if (isInterestingIdentifier(II, Macro)) { DataLen += 2; // 2 bytes for builtin ID DataLen += 2; // 2 bytes for flags if (hadMacroDefinition(II, Macro)) { - for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) { - if (Writer.getMacroRef(M) != 0) - DataLen += 4; + DataLen += 4; // MacroDirectives offset. + if (IsModule) { + SubmoduleID ModID; + for (DefMacroDirective * + DefMD = getFirstPublicSubmoduleMacro(Macro, ModID); + DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) { + DataLen += 4; // MacroInfo ID. + } + DataLen += 4; } - - DataLen += 4; } for (IdentifierResolver::iterator D = IdResolver.begin(II), @@ -2740,7 +3049,7 @@ public: void EmitData(raw_ostream& Out, IdentifierInfo* II, IdentID ID, unsigned) { - MacroInfo *Macro = 0; + MacroDirective *Macro = 0; if (!isInterestingIdentifier(II, Macro)) { clang::io::Emit32(Out, ID << 1); return; @@ -2753,6 +3062,7 @@ public: Bits = 0; bool HadMacroDefinition = hadMacroDefinition(II, Macro); Bits = (Bits << 1) | unsigned(HadMacroDefinition); + Bits = (Bits << 1) | unsigned(IsModule); Bits = (Bits << 1) | unsigned(II->isExtensionToken()); Bits = (Bits << 1) | unsigned(II->isPoisoned()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); @@ -2760,13 +3070,19 @@ public: clang::io::Emit16(Out, Bits); if (HadMacroDefinition) { - // Write all of the macro IDs associated with this identifier. - for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) { - if (MacroID ID = Writer.getMacroRef(M)) - clang::io::Emit32(Out, ID); + clang::io::Emit32(Out, Writer.getMacroDirectivesOffset(II)); + if (IsModule) { + // Write the IDs of macros coming from different submodules. + SubmoduleID ModID; + for (DefMacroDirective * + DefMD = getFirstPublicSubmoduleMacro(Macro, ModID); + DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) { + MacroID InfoID = Writer.getMacroID(DefMD->getInfo()); + assert(InfoID); + clang::io::Emit32(Out, InfoID); + } + clang::io::Emit32(Out, 0); } - - clang::io::Emit32(Out, 0); } // Emit the declaration IDs in reverse order, because the @@ -2820,7 +3136,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, assert(ID->first && "NULL identifier in identifier table"); if (!Chain || !ID->first->isFromAST() || ID->first->hasChangedSinceDeserialization()) - Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second, + Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second, Trait); } @@ -2857,6 +3173,11 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); +#ifndef NDEBUG + 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()); @@ -2936,7 +3257,7 @@ public: clang::io::Emit16(Out, KeyLen); // 2 bytes for num of decls and 4 for each DeclID. - unsigned DataLen = 2 + 4 * (Lookup.second - Lookup.first); + unsigned DataLen = 2 + 4 * Lookup.size(); clang::io::Emit16(Out, DataLen); return std::make_pair(KeyLen, DataLen); @@ -2976,9 +3297,10 @@ public: void EmitData(raw_ostream& Out, key_type_ref, data_type Lookup, unsigned DataLen) { uint64_t Start = Out.tell(); (void)Start; - clang::io::Emit16(Out, Lookup.second - Lookup.first); - for (; Lookup.first != Lookup.second; ++Lookup.first) - clang::io::Emit32(Out, Writer.GetDeclRef(*Lookup.first)); + clang::io::Emit16(Out, Lookup.size()); + for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end(); + I != E; ++I) + clang::io::Emit32(Out, Writer.GetDeclRef(*I)); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } @@ -3002,8 +3324,6 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, // If not in C++, we perform name lookup for the translation unit via the // IdentifierInfo chains, don't bother to build a visible-declarations table. - // FIXME: In C++ we need the visible declarations in order to "see" the - // friend declarations, is there a way to do this without writing the table ? if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus) return 0; @@ -3022,12 +3342,12 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, // Create the on-disk hash table representation. DeclarationName ConversionName; - llvm::SmallVector<NamedDecl *, 4> ConversionDecls; + SmallVector<NamedDecl *, 4> ConversionDecls; for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); D != DEnd; ++D) { DeclarationName Name = D->first; DeclContext::lookup_result Result = D->second.getLookupResult(); - if (Result.first != Result.second) { + if (!Result.empty()) { if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { // Hash all conversion function names to the same name. The actual // type information in conversion function name is not used in the @@ -3036,7 +3356,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, // functions under a single key. if (!ConversionName) ConversionName = Name; - ConversionDecls.append(Result.first, Result.second); + ConversionDecls.append(Result.begin(), Result.end()); continue; } @@ -3095,7 +3415,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { DeclContext::lookup_result Result = D->second.getLookupResult(); // For any name that appears in this table, the results are complete, i.e. // they overwrite results from previous PCHs. Merging is always a mess. - if (Result.first != Result.second) + if (!Result.empty()) Generator.insert(Name, Result, Trait); } @@ -3156,20 +3476,32 @@ void ASTWriter::WriteRedeclarations() { LocalRedeclChains.push_back(0); // Placeholder for the size. // Collect the set of local redeclarations of this declaration. - for (Decl *Prev = MostRecent; Prev != First; + for (Decl *Prev = MostRecent; Prev != First; Prev = Prev->getPreviousDecl()) { if (!Prev->isFromASTFile()) { AddDeclRef(Prev, LocalRedeclChains); ++Size; } } + + if (!First->isFromASTFile() && Chain) { + Decl *FirstFromAST = MostRecent; + for (Decl *Prev = MostRecent; Prev; Prev = Prev->getPreviousDecl()) { + if (Prev->isFromASTFile()) + FirstFromAST = Prev; + } + + Chain->MergedDecls[FirstFromAST].push_back(getDeclID(First)); + } + 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 to the set of local declarations. + // Add the mapping from the first ID from the AST to the set of local + // declarations. LocalRedeclarationsInfo Info = { getDeclID(First), Offset }; LocalRedeclsMap.push_back(Info); @@ -3204,7 +3536,7 @@ void ASTWriter::WriteRedeclarations() { } void ASTWriter::WriteObjCCategories() { - llvm::SmallVector<ObjCCategoriesInfo, 2> CategoriesMap; + SmallVector<ObjCCategoriesInfo, 2> CategoriesMap; RecordData Categories; for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) { @@ -3217,10 +3549,12 @@ void ASTWriter::WriteObjCCategories() { Categories.push_back(0); // Add the categories. - for (ObjCCategoryDecl *Cat = Class->getCategoryList(); - Cat; Cat = Cat->getNextClassCategory(), ++Size) { - assert(getDeclID(Cat) != 0 && "Bogus category"); - AddDeclRef(Cat, Categories); + for (ObjCInterfaceDecl::known_categories_iterator + Cat = Class->known_categories_begin(), + CatEnd = Class->known_categories_end(); + Cat != CatEnd; ++Cat, ++Size) { + assert(getDeclID(*Cat) != 0 && "Bogus category"); + AddDeclRef(*Cat, Categories); } // Update the size. @@ -3300,11 +3634,11 @@ void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) { void ASTWriter::AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record) { Record.push_back(Version.getMajor()); - if (llvm::Optional<unsigned> Minor = Version.getMinor()) + if (Optional<unsigned> Minor = Version.getMinor()) Record.push_back(*Minor + 1); else Record.push_back(0); - if (llvm::Optional<unsigned> Subminor = Version.getSubminor()) + if (Optional<unsigned> Subminor = Version.getSubminor()) Record.push_back(*Subminor + 1); else Record.push_back(0); @@ -3405,6 +3739,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Module *WritingModule) { using namespace llvm; + bool isModule = WritingModule != 0; + // Make sure that the AST reader knows to finalize itself. if (Chain) Chain->finalizeForWriting(); @@ -3447,11 +3783,19 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // If there are any out-of-date identifiers, bring them up to date. if (ExternalPreprocessorSource *ExtSource = PP.getExternalSource()) { + // Find out-of-date identifiers. + SmallVector<IdentifierInfo *, 4> OutOfDate; for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), IDEnd = PP.getIdentifierTable().end(); - ID != IDEnd; ++ID) + ID != IDEnd; ++ID) { if (ID->second->isOutOfDate()) - ExtSource->updateOutOfDateIdentifier(*ID->second); + OutOfDate.push_back(ID->second); + } + + // Update the out-of-date identifiers. + for (unsigned I = 0, N = OutOfDate.size(); I != N; ++I) { + ExtSource->updateOutOfDateIdentifier(*OutOfDate[I]); + } } // Build a record containing all of the tentative definitions in this file, in @@ -3462,13 +3806,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // Build a record containing all of the file scoped decls in this file. RecordData UnusedFileScopedDecls; - AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls, - UnusedFileScopedDecls); + if (!isModule) + AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls, + UnusedFileScopedDecls); // Build a record containing all of the delegating constructors we still need // to resolve. RecordData DelegatingCtorDecls; - AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls); + if (!isModule) + AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls); // Write the set of weak, undeclared identifiers. We always write the // entire table, since later PCH files in a PCH chain are only interested in @@ -3485,18 +3831,18 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, } } - // Build a record containing all of the locally-scoped external + // Build a record containing all of the locally-scoped extern "C" // declarations in this header file. Generally, this record will be // empty. - RecordData LocallyScopedExternalDecls; + RecordData LocallyScopedExternCDecls; // FIXME: This is filling in the AST file in densemap order which is // nondeterminstic! for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator - TD = SemaRef.LocallyScopedExternalDecls.begin(), - TDEnd = SemaRef.LocallyScopedExternalDecls.end(); + TD = SemaRef.LocallyScopedExternCDecls.begin(), + TDEnd = SemaRef.LocallyScopedExternCDecls.end(); TD != TDEnd; ++TD) { if (!TD->second->isFromASTFile()) - AddDeclRef(TD->second, LocallyScopedExternalDecls); + AddDeclRef(TD->second, LocallyScopedExternCDecls); } // Build a record containing all of the ext_vector declarations. @@ -3542,7 +3888,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // Build a record containing all of the known namespaces. RecordData KnownNamespaces; - for (llvm::DenseMap<NamespaceDecl*, bool>::iterator + for (llvm::MapVector<NamespaceDecl*, bool>::iterator I = SemaRef.KnownNamespaces.begin(), IEnd = SemaRef.KnownNamespaces.end(); I != IEnd; ++I) { @@ -3550,6 +3896,17 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, AddDeclRef(I->first, KnownNamespaces); } + // Build a record of all used, undefined objects that require definitions. + RecordData UndefinedButUsed; + + 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); + } + // Write the control block WriteControlBlock(PP, Context, isysroot, OutputFile); @@ -3557,6 +3914,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, 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); + // 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(); @@ -3686,16 +4049,16 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, Buffer.data(), Buffer.size()); } - WritePreprocessor(PP, WritingModule != 0); + WritePreprocessor(PP, isModule); WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot); WriteSelectors(SemaRef); WriteReferencedSelectorsPool(SemaRef); - WriteIdentifierTable(PP, SemaRef.IdResolver, WritingModule != 0); + WriteIdentifierTable(PP, SemaRef.IdResolver, isModule); WriteFPPragmaOptions(SemaRef.getFPOptions()); WriteOpenCLExtensions(SemaRef); WriteTypeDeclOffsets(); - WritePragmaDiagnosticMappings(Context.getDiagnostics()); + WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule); WriteCXXBaseSpecifiersOffsets(); @@ -3722,10 +4085,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS, WeakUndeclaredIdentifiers); - // Write the record containing locally-scoped external definitions. - if (!LocallyScopedExternalDecls.empty()) - Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS, - LocallyScopedExternalDecls); + // Write the record containing locally-scoped extern "C" definitions. + if (!LocallyScopedExternCDecls.empty()) + Stream.EmitRecord(LOCALLY_SCOPED_EXTERN_C_DECLS, + LocallyScopedExternCDecls); // Write the record containing ext_vector type names. if (!ExtVectorDecls.empty()) @@ -3758,6 +4121,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // Write the known namespaces. if (!KnownNamespaces.empty()) Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces); + + // Write the undefined internal functions and variables, and inline functions. + if (!UndefinedButUsed.empty()) + Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed); // Write the visible updates to DeclContexts. for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator @@ -3788,11 +4155,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, } } - WriteMacroUpdates(); WriteDeclUpdatesBlocks(); WriteDeclReplacementsBlock(); - WriteMergedDecls(); WriteRedeclarations(); + WriteMergedDecls(); WriteObjCCategories(); // Some simple statistics @@ -3805,21 +4171,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.ExitBlock(); } -void ASTWriter::WriteMacroUpdates() { - if (MacroUpdates.empty()) - return; - - RecordData Record; - for (MacroUpdatesMap::iterator I = MacroUpdates.begin(), - E = MacroUpdates.end(); - I != E; ++I) { - addMacroRef(I->first, Record); - AddSourceLocation(I->second.UndefLoc, Record); - Record.push_back(inferSubmoduleIDFromLocation(I->second.UndefLoc)); - } - Stream.EmitRecord(MACRO_UPDATES, Record); -} - /// \brief Go through the declaration update blocks and resolve declaration /// pointers into declaration IDs. void ASTWriter::ResolveDeclUpdatesBlocks() { @@ -3915,10 +4266,6 @@ void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Recor Record.push_back(getIdentifierRef(II)); } -void ASTWriter::addMacroRef(MacroInfo *MI, RecordDataImpl &Record) { - Record.push_back(getMacroRef(MI)); -} - IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { if (II == 0) return 0; @@ -3929,7 +4276,7 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { return ID; } -MacroID ASTWriter::getMacroRef(MacroInfo *MI) { +MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) { // Don't emit builtin macros like __LINE__ to the AST file unless they // have been redefined by the header (in which case they are not // isBuiltinMacro). @@ -3937,11 +4284,27 @@ MacroID ASTWriter::getMacroRef(MacroInfo *MI) { return 0; MacroID &ID = MacroIDs[MI]; - if (ID == 0) + if (ID == 0) { ID = NextMacroID++; + MacroInfoToEmitData Info = { Name, MI, ID }; + MacroInfosToEmit.push_back(Info); + } return ID; } +MacroID ASTWriter::getMacroID(MacroInfo *MI) { + if (MI == 0 || MI->isBuiltinMacro()) + return 0; + + assert(MacroIDs.find(MI) != MacroIDs.end() && "Macro not emitted!"); + return MacroIDs[MI]; +} + +uint64_t ASTWriter::getMacroDirectivesOffset(const IdentifierInfo *Name) { + assert(IdentMacroDirectivesOffsetMap[Name] && "not set!"); + return IdentMacroDirectivesOffsetMap[Name]; +} + void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) { Record.push_back(getSelectorRef(SelRef)); } @@ -3951,14 +4314,16 @@ SelectorID ASTWriter::getSelectorRef(Selector Sel) { return 0; } - SelectorID &SID = SelectorIDs[Sel]; + SelectorID SID = SelectorIDs[Sel]; if (SID == 0 && Chain) { // This might trigger a ReadSelector callback, which will set the ID for // this selector. Chain->LoadSelector(Sel); + SID = SelectorIDs[Sel]; } if (SID == 0) { SID = NextSelectorID++; + SelectorIDs[Sel] = SID; } return SID; } @@ -4431,7 +4796,7 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg, break; case TemplateArgument::TemplateExpansion: AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record); - if (llvm::Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions()) + if (Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions()) Record.push_back(*NumExpansions + 1); else Record.push_back(0); @@ -4474,9 +4839,9 @@ ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs, void -ASTWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record) { +ASTWriter::AddUnresolvedSet(const ASTUnresolvedSet &Set, RecordDataImpl &Record) { Record.push_back(Set.size()); - for (UnresolvedSetImpl::const_iterator + for (ASTUnresolvedSet::const_iterator I = Set.begin(), E = Set.end(); I != E; ++I) { AddDeclRef(I.getDecl(), Record); Record.push_back(I.getAccess()); @@ -4568,11 +4933,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData; Record.push_back(Data.IsLambda); Record.push_back(Data.UserDeclaredConstructor); - Record.push_back(Data.UserDeclaredCopyConstructor); - Record.push_back(Data.UserDeclaredMoveConstructor); - Record.push_back(Data.UserDeclaredCopyAssignment); - Record.push_back(Data.UserDeclaredMoveAssignment); - Record.push_back(Data.UserDeclaredDestructor); + Record.push_back(Data.UserDeclaredSpecialMembers); Record.push_back(Data.Aggregate); Record.push_back(Data.PlainOldData); Record.push_back(Data.Empty); @@ -4586,25 +4947,26 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.HasMutableFields); Record.push_back(Data.HasOnlyCMembers); Record.push_back(Data.HasInClassInitializer); - Record.push_back(Data.HasTrivialDefaultConstructor); + Record.push_back(Data.HasUninitializedReferenceMember); + Record.push_back(Data.NeedOverloadResolutionForMoveConstructor); + Record.push_back(Data.NeedOverloadResolutionForMoveAssignment); + Record.push_back(Data.NeedOverloadResolutionForDestructor); + Record.push_back(Data.DefaultedMoveConstructorIsDeleted); + Record.push_back(Data.DefaultedMoveAssignmentIsDeleted); + Record.push_back(Data.DefaultedDestructorIsDeleted); + Record.push_back(Data.HasTrivialSpecialMembers); + Record.push_back(Data.HasIrrelevantDestructor); Record.push_back(Data.HasConstexprNonCopyMoveConstructor); Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr); Record.push_back(Data.HasConstexprDefaultConstructor); - Record.push_back(Data.HasTrivialCopyConstructor); - Record.push_back(Data.HasTrivialMoveConstructor); - Record.push_back(Data.HasTrivialCopyAssignment); - Record.push_back(Data.HasTrivialMoveAssignment); - Record.push_back(Data.HasTrivialDestructor); - Record.push_back(Data.HasIrrelevantDestructor); Record.push_back(Data.HasNonLiteralTypeFieldsOrBases); Record.push_back(Data.ComputedVisibleConversions); Record.push_back(Data.UserProvidedDefaultConstructor); - Record.push_back(Data.DeclaredDefaultConstructor); - Record.push_back(Data.DeclaredCopyConstructor); - Record.push_back(Data.DeclaredMoveConstructor); - Record.push_back(Data.DeclaredCopyAssignment); - Record.push_back(Data.DeclaredMoveAssignment); - Record.push_back(Data.DeclaredDestructor); + Record.push_back(Data.DeclaredSpecialMembers); + Record.push_back(Data.ImplicitCopyConstructorHasConstParam); + Record.push_back(Data.ImplicitCopyAssignmentHasConstParam); + Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam); + Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam); Record.push_back(Data.FailedImplicitMoveConstructor); Record.push_back(Data.FailedImplicitMoveAssignment); // IsLambda bit is already saved. @@ -4676,11 +5038,17 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) { } void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) { - IdentifierIDs[II] = ID; + // Always keep the highest ID. See \p TypeRead() for more information. + IdentID &StoredID = IdentifierIDs[II]; + if (ID > StoredID) + StoredID = ID; } void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) { - MacroIDs[MI] = ID; + // Always keep the highest ID. See \p TypeRead() for more information. + MacroID &StoredID = MacroIDs[MI]; + if (ID > StoredID) + StoredID = ID; } void ASTWriter::TypeRead(TypeIdx Idx, QualType T) { @@ -4695,7 +5063,10 @@ void ASTWriter::TypeRead(TypeIdx Idx, QualType T) { } void ASTWriter::SelectorRead(SelectorID ID, Selector S) { - SelectorIDs[S] = ID; + // Always keep the highest ID. See \p TypeRead() for more information. + SelectorID &StoredID = SelectorIDs[S]; + if (ID > StoredID) + StoredID = ID; } void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID, @@ -4709,10 +5080,6 @@ void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) { SubmoduleIDs[Mod] = ID; } -void ASTWriter::UndefinedMacro(MacroInfo *MI) { - MacroUpdates[MI].UndefLoc = MI->getUndefLoc(); -} - void ASTWriter::CompletedTagDefinition(const TagDecl *D) { assert(D->isCompleteDefinition()); assert(!WritingAST && "Already writing the AST!"); @@ -4737,6 +5104,7 @@ void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile())) return; // Not a source decl added to a DeclContext from PCH. + assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!"); AddUpdatedDeclContext(DC); UpdatingVisibleDecls.push_back(D); } diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 7486565..023599d 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -12,14 +12,14 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" -#include "clang/Serialization/ASTReader.h" #include "ASTCommon.h" -#include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" -#include "clang/AST/DeclContextInternals.h" #include "clang/Basic/SourceManager.h" +#include "clang/Serialization/ASTReader.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/ErrorHandling.h" @@ -102,6 +102,7 @@ namespace clang { void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *D); + void VisitEmptyDecl(EmptyDecl *D); void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, uint64_t VisibleOffset); @@ -122,6 +123,7 @@ namespace clang { void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); }; } @@ -252,6 +254,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { !D->isModulePrivate() && !CXXRecordDecl::classofKind(D->getKind()) && !D->getIntegerTypeSourceInfo() && + !D->getMemberSpecializationInfo() && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclEnumAbbrev(); @@ -263,6 +266,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) { Record.push_back(D->hasFlexibleArrayMember()); Record.push_back(D->isAnonymousStructOrUnion()); Record.push_back(D->hasObjectMember()); + Record.push_back(D->hasVolatileMember()); if (!D->hasAttrs() && !D->isImplicit() && @@ -315,7 +319,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { // after everything else is written. Record.push_back(D->getStorageClass()); // FIXME: stable encoding - Record.push_back(D->getStorageClassAsWritten()); Record.push_back(D->IsInline); Record.push_back(D->isInlineSpecified()); Record.push_back(D->isVirtualAsWritten()); @@ -328,6 +331,8 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->isExplicitlyDefaulted()); Record.push_back(D->hasImplicitReturnZero()); Record.push_back(D->isConstexpr()); + Record.push_back(D->HasSkippedBody); + Record.push_back(D->getLinkage()); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->getTemplatedKind()); @@ -419,6 +424,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { Record.push_back(D->isPropertyAccessor()); Record.push_back(D->isDefined()); Record.push_back(D->IsOverriding); + Record.push_back(D->HasSkippedBody); Record.push_back(D->IsRedeclaration); Record.push_back(D->HasRedeclaration); @@ -489,13 +495,14 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { PEnd = Data.AllReferencedProtocols.end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); + - if (ObjCCategoryDecl *Cat = D->getCategoryList()) { + if (ObjCCategoryDecl *Cat = D->getCategoryListRaw()) { // Ensure that we write out the set of categories for this class. Writer.ObjCClassesWithCategories.insert(D); // Make sure that the categories get serialized. - for (; Cat; Cat = Cat->getNextClassCategory()) + for (; Cat; Cat = Cat->getNextClassCategoryRaw()) (void)Writer.GetDeclRef(Cat); } } @@ -669,8 +676,7 @@ void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { void ASTDeclWriter::VisitVarDecl(VarDecl *D) { VisitRedeclarable(D); VisitDeclaratorDecl(D); - Record.push_back(D->getStorageClass()); // FIXME: stable encoding - Record.push_back(D->getStorageClassAsWritten()); + Record.push_back(D->getStorageClass()); Record.push_back(D->isThreadSpecified()); Record.push_back(D->getInitStyle()); Record.push_back(D->isExceptionVariable()); @@ -678,6 +684,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->isCXXForRangeDecl()); Record.push_back(D->isARCPseudoStrong()); Record.push_back(D->isConstexpr()); + Record.push_back(D->getLinkage()); if (D->getInit()) { Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2)); @@ -774,6 +781,11 @@ void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { Code = serialization::DECL_FILE_SCOPE_ASM; } +void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) { + VisitDecl(D); + Code = serialization::DECL_EMPTY; +} + void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { VisitDecl(D); Writer.AddStmt(D->getBody()); @@ -839,11 +851,10 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { if (StoredDeclsMap *Map = NS->buildLookup()) { for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); D != DEnd; ++D) { - DeclContext::lookup_result Result = D->second.getLookupResult(); - while (Result.first != Result.second) { - Writer.GetDeclRef(*Result.first); - ++Result.first; - } + DeclContext::lookup_result R = D->second.getLookupResult(); + for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; + ++I) + Writer.GetDeclRef(*I); } } } @@ -940,10 +951,10 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { Record.push_back(CXXRecNotTemplate); } - // Store the key function to avoid deserializing every method so we can - // compute it. + // Store (what we currently believe to be) the key function to avoid + // deserializing every method so we can compute it. if (D->IsCompleteDefinition) - Writer.AddDeclRef(Context.getKeyFunction(D), Record); + Writer.AddDeclRef(Context.getCurrentKeyFunction(D), Record); Code = serialization::DECL_CXX_RECORD; } @@ -1014,12 +1025,19 @@ void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) { } void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) { + // Record the number of friend type template parameter lists here + // so as to simplify memory allocation during deserialization. + Record.push_back(D->NumTPLists); VisitDecl(D); - Record.push_back(D->Friend.is<TypeSourceInfo*>()); - if (D->Friend.is<TypeSourceInfo*>()) - Writer.AddTypeSourceInfo(D->Friend.get<TypeSourceInfo*>(), Record); + bool hasFriendDecl = D->Friend.is<NamedDecl*>(); + Record.push_back(hasFriendDecl); + if (hasFriendDecl) + Writer.AddDeclRef(D->getFriendDecl(), Record); else - Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record); + Writer.AddTypeSourceInfo(D->getFriendType(), Record); + for (unsigned i = 0; i < D->NumTPLists; ++i) + Writer.AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i), + Record); Writer.AddDeclRef(D->getNextFriend(), Record); Record.push_back(D->UnsupportedFriend); Writer.AddSourceLocation(D->FriendLoc, Record); @@ -1275,7 +1293,10 @@ template <typename T> void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { T *First = D->getFirstDeclaration(); if (First->getMostRecentDecl() != First) { - // There is more than one declaration of this entity, so we will need to + assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) && + "Not considered redeclarable?"); + + // There is more than one declaration of this entity, so we will need to // write a redeclaration chain. Writer.AddDeclRef(First, Record); Writer.Redeclarations.insert(First); @@ -1292,6 +1313,16 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { } +void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { + Record.push_back(D->varlist_size()); + VisitDecl(D); + for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(), + E = D->varlist_end(); + I != E; ++I) + Writer.AddStmt(*I); + Code = serialization::DECL_OMP_THREADPRIVATE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// @@ -1451,6 +1482,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasVolatileMember // DC Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset @@ -1483,7 +1515,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // VarDecl Abv->Add(BitCodeAbbrevOp(0)); // StorageClass - Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable @@ -1491,6 +1522,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr + Abv->Add(BitCodeAbbrevOp(0)); // Linkage Abv->Add(BitCodeAbbrevOp(0)); // HasInit Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo // ParmVarDecl @@ -1562,7 +1594,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // VarDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClassAsWritten Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable @@ -1570,6 +1601,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Linkage Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo // Type Source Info diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 7e8ce42..b6f1d54 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -78,6 +78,8 @@ void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) { void ASTStmtWriter::VisitSwitchCase(SwitchCase *S) { VisitStmt(S); Record.push_back(Writer.getSwitchCaseID(S)); + Writer.AddSourceLocation(S->getKeywordLoc(), Record); + Writer.AddSourceLocation(S->getColonLoc(), Record); } void ASTStmtWriter::VisitCaseStmt(CaseStmt *S) { @@ -85,17 +87,13 @@ void ASTStmtWriter::VisitCaseStmt(CaseStmt *S) { Writer.AddStmt(S->getLHS()); Writer.AddStmt(S->getRHS()); Writer.AddStmt(S->getSubStmt()); - Writer.AddSourceLocation(S->getCaseLoc(), Record); Writer.AddSourceLocation(S->getEllipsisLoc(), Record); - Writer.AddSourceLocation(S->getColonLoc(), Record); Code = serialization::STMT_CASE; } void ASTStmtWriter::VisitDefaultStmt(DefaultStmt *S) { VisitSwitchCase(S); Writer.AddStmt(S->getSubStmt()); - Writer.AddSourceLocation(S->getDefaultLoc(), Record); - Writer.AddSourceLocation(S->getColonLoc(), Record); Code = serialization::STMT_DEFAULT; } @@ -326,8 +324,9 @@ void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) { void ASTStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) { VisitExpr(E); - Writer.AddAPFloat(E->getValue(), Record); + Record.push_back(E->getRawSemantics()); Record.push_back(E->isExact()); + Writer.AddAPFloat(E->getValue(), Record); Writer.AddSourceLocation(E->getLocation(), Record); Code = serialization::EXPR_FLOATING_LITERAL; } @@ -499,6 +498,7 @@ void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) { VisitExpr(E); Writer.AddStmt(E->getBase()); Writer.AddSourceLocation(E->getIsaMemberLoc(), Record); + Writer.AddSourceLocation(E->getOpLoc(), Record); Record.push_back(E->isArrow()); Code = serialization::EXPR_OBJC_ISA; } @@ -857,6 +857,7 @@ void ASTStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { VisitExpr(E); Writer.AddDeclRef(E->getDecl(), Record); Writer.AddSourceLocation(E->getLocation(), Record); + Writer.AddSourceLocation(E->getOpLoc(), Record); Writer.AddStmt(E->getBase()); Record.push_back(E->isArrow()); Record.push_back(E->isFreeIvar()); @@ -1076,6 +1077,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { Writer.AddSourceLocation(E->getLocation(), Record); Record.push_back(E->isElidable()); Record.push_back(E->hadMultipleCandidates()); + Record.push_back(E->isListInitialization()); Record.push_back(E->requiresZeroInitialization()); Record.push_back(E->getConstructionKind()); // FIXME: stable encoding Writer.AddSourceRange(E->getParenRange(), Record); @@ -1124,6 +1126,7 @@ void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { VisitExplicitCastExpr(E); Writer.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()), Record); + Writer.AddSourceRange(E->getAngleBrackets(), Record); } void ASTStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt index 20999e1..3c68b64 100644 --- a/lib/Serialization/CMakeLists.txt +++ b/lib/Serialization/CMakeLists.txt @@ -1,3 +1,5 @@ +set(LLVM_LINK_COMPONENTS bitreader) + add_clang_library(clangSerialization ASTCommon.h ASTReaderInternals.h @@ -9,6 +11,7 @@ add_clang_library(clangSerialization ASTWriterDecl.cpp ASTWriterStmt.cpp GeneratePCH.cpp + GlobalModuleIndex.cpp Module.cpp ModuleManager.cpp ) diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp index 870d654..32c2df3 100644 --- a/lib/Serialization/GeneratePCH.cpp +++ b/lib/Serialization/GeneratePCH.cpp @@ -13,11 +13,11 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" -#include "clang/Sema/SemaConsumer.h" -#include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" -#include "clang/Lex/Preprocessor.h" +#include "clang/AST/ASTContext.h" #include "clang/Basic/FileManager.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/SemaConsumer.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/raw_ostream.h" #include <string> @@ -55,10 +55,6 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { Buffer.clear(); } -PPMutationListener *PCHGenerator::GetPPMutationListener() { - return &Writer; -} - ASTMutationListener *PCHGenerator::GetASTMutationListener() { return &Writer; } diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp new file mode 100644 index 0000000..f9acb84 --- /dev/null +++ b/lib/Serialization/GlobalModuleIndex.cpp @@ -0,0 +1,820 @@ +//===--- GlobalModuleIndex.cpp - Global Module Index ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the GlobalModuleIndex class. +// +//===----------------------------------------------------------------------===// + +#include "ASTReaderInternals.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/GlobalModuleIndex.h" +#include "clang/Serialization/Module.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/LockFileManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PathV2.h" +#include <cstdio> +using namespace clang; +using namespace serialization; + +//----------------------------------------------------------------------------// +// Shared constants +//----------------------------------------------------------------------------// +namespace { + enum { + /// \brief The block containing the index. + GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID + }; + + /// \brief Describes the record types in the index. + enum IndexRecordTypes { + /// \brief Contains version information and potentially other metadata, + /// used to determine if we can read this global index file. + INDEX_METADATA, + /// \brief Describes a module, including its file name and dependencies. + MODULE, + /// \brief The index for identifiers. + IDENTIFIER_INDEX + }; +} + +/// \brief The name of the global index file. +static const char * const IndexFileName = "modules.idx"; + +/// \brief The global index file version. +static const unsigned CurrentVersion = 1; + +//----------------------------------------------------------------------------// +// Global module index reader. +//----------------------------------------------------------------------------// + +namespace { + +/// \brief Trait used to read the identifier index from the on-disk hash +/// table. +class IdentifierIndexReaderTrait { +public: + typedef StringRef external_key_type; + typedef StringRef internal_key_type; + typedef SmallVector<unsigned, 2> data_type; + + static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { + return a == b; + } + + static unsigned ComputeHash(const internal_key_type& a) { + return llvm::HashString(a); + } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); + } + + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; } + + static const external_key_type& + GetExternalKey(const internal_key_type& x) { return x; } + + static internal_key_type ReadKey(const unsigned char* d, unsigned n) { + return StringRef((const char *)d, n); + } + + static data_type ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + + data_type Result; + while (DataLen > 0) { + unsigned ID = ReadUnalignedLE32(d); + Result.push_back(ID); + DataLen -= 4; + } + + return Result; + } +}; + +typedef OnDiskChainedHashTable<IdentifierIndexReaderTrait> IdentifierIndexTable; + +} + +GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer, + llvm::BitstreamCursor Cursor) + : Buffer(Buffer), IdentifierIndex(), + NumIdentifierLookups(), NumIdentifierLookupHits() +{ + // Read the global index. + bool InGlobalIndexBlock = false; + bool Done = false; + while (!Done) { + llvm::BitstreamEntry Entry = Cursor.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + return; + + case llvm::BitstreamEntry::EndBlock: + if (InGlobalIndexBlock) { + InGlobalIndexBlock = false; + Done = true; + continue; + } + return; + + + case llvm::BitstreamEntry::Record: + // Entries in the global index block are handled below. + if (InGlobalIndexBlock) + break; + + return; + + case llvm::BitstreamEntry::SubBlock: + if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) { + if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID)) + return; + + InGlobalIndexBlock = true; + } else if (Cursor.SkipBlock()) { + return; + } + continue; + } + + SmallVector<uint64_t, 64> Record; + StringRef Blob; + switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) { + case INDEX_METADATA: + // Make sure that the version matches. + if (Record.size() < 1 || Record[0] != CurrentVersion) + return; + break; + + case MODULE: { + unsigned Idx = 0; + unsigned ID = Record[Idx++]; + + // Make room for this module's information. + if (ID == Modules.size()) + Modules.push_back(ModuleInfo()); + else + Modules.resize(ID + 1); + + // Size/modification time for this module file at the time the + // global index was built. + Modules[ID].Size = Record[Idx++]; + Modules[ID].ModTime = Record[Idx++]; + + // File name. + unsigned NameLen = Record[Idx++]; + Modules[ID].FileName.assign(Record.begin() + Idx, + Record.begin() + Idx + NameLen); + Idx += NameLen; + + // Dependencies + unsigned NumDeps = Record[Idx++]; + Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(), + Record.begin() + Idx, + Record.begin() + Idx + NumDeps); + Idx += NumDeps; + + // Make sure we're at the end of the record. + assert(Idx == Record.size() && "More module info?"); + + // Record this module as an unresolved module. + UnresolvedModules[llvm::sys::path::stem(Modules[ID].FileName)] = ID; + break; + } + + case IDENTIFIER_INDEX: + // Wire up the identifier index. + if (Record[0]) { + IdentifierIndex = IdentifierIndexTable::Create( + (const unsigned char *)Blob.data() + Record[0], + (const unsigned char *)Blob.data(), + IdentifierIndexReaderTrait()); + } + break; + } + } +} + +GlobalModuleIndex::~GlobalModuleIndex() { } + +std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> +GlobalModuleIndex::readIndex(StringRef Path) { + // Load the index file, if it's there. + llvm::SmallString<128> IndexPath; + IndexPath += Path; + llvm::sys::path::append(IndexPath, IndexFileName); + + llvm::OwningPtr<llvm::MemoryBuffer> Buffer; + if (llvm::MemoryBuffer::getFile(IndexPath, Buffer) != llvm::errc::success) + return std::make_pair((GlobalModuleIndex *)0, EC_NotFound); + + /// \brief The bitstream reader from which we'll read the AST file. + llvm::BitstreamReader Reader((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + + /// \brief The main bitstream cursor for the main block. + llvm::BitstreamCursor Cursor(Reader); + + // Sniff for the signature. + if (Cursor.Read(8) != 'B' || + Cursor.Read(8) != 'C' || + Cursor.Read(8) != 'G' || + Cursor.Read(8) != 'I') { + return std::make_pair((GlobalModuleIndex *)0, EC_IOError); + } + + return std::make_pair(new GlobalModuleIndex(Buffer.take(), Cursor), EC_None); +} + +void +GlobalModuleIndex::getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles) { + ModuleFiles.clear(); + for (unsigned I = 0, N = Modules.size(); I != N; ++I) { + if (ModuleFile *MF = Modules[I].File) + ModuleFiles.push_back(MF); + } +} + +void GlobalModuleIndex::getModuleDependencies( + ModuleFile *File, + SmallVectorImpl<ModuleFile *> &Dependencies) { + // Look for information about this module file. + llvm::DenseMap<ModuleFile *, unsigned>::iterator Known + = ModulesByFile.find(File); + if (Known == ModulesByFile.end()) + return; + + // Record dependencies. + Dependencies.clear(); + ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies; + for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) { + if (ModuleFile *MF = Modules[I].File) + Dependencies.push_back(MF); + } +} + +bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) { + Hits.clear(); + + // If there's no identifier index, there is nothing we can do. + if (!IdentifierIndex) + return false; + + // Look into the identifier index. + ++NumIdentifierLookups; + IdentifierIndexTable &Table + = *static_cast<IdentifierIndexTable *>(IdentifierIndex); + IdentifierIndexTable::iterator Known = Table.find(Name); + if (Known == Table.end()) { + return true; + } + + SmallVector<unsigned, 2> ModuleIDs = *Known; + for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) { + if (ModuleFile *MF = Modules[ModuleIDs[I]].File) + Hits.insert(MF); + } + + ++NumIdentifierLookupHits; + return true; +} + +bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) { + // Look for the module in the global module index based on the module name. + StringRef Name = llvm::sys::path::stem(File->FileName); + llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name); + if (Known == UnresolvedModules.end()) { + return true; + } + + // Rectify this module with the global module index. + ModuleInfo &Info = Modules[Known->second]; + + // If the size and modification time match what we expected, record this + // module file. + bool Failed = true; + if (File->File->getSize() == Info.Size && + File->File->getModificationTime() == Info.ModTime) { + Info.File = File; + ModulesByFile[File] = Known->second; + + Failed = false; + } + + // One way or another, we have resolved this module file. + UnresolvedModules.erase(Known); + return Failed; +} + +void GlobalModuleIndex::printStats() { + std::fprintf(stderr, "*** Global Module Index Statistics:\n"); + if (NumIdentifierLookups) { + fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n", + NumIdentifierLookupHits, NumIdentifierLookups, + (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups); + } + std::fprintf(stderr, "\n"); +} + +//----------------------------------------------------------------------------// +// Global module index writer. +//----------------------------------------------------------------------------// + +namespace { + /// \brief Provides information about a specific module file. + struct ModuleFileInfo { + /// \brief The numberic ID for this module file. + unsigned ID; + + /// \brief The set of modules on which this module depends. Each entry is + /// a module ID. + SmallVector<unsigned, 4> Dependencies; + }; + + /// \brief Builder that generates the global module index file. + class GlobalModuleIndexBuilder { + FileManager &FileMgr; + + /// \brief Mapping from files to module file information. + typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap; + + /// \brief Information about each of the known module files. + ModuleFilesMap ModuleFiles; + + /// \brief Mapping from identifiers to the list of module file IDs that + /// consider this identifier to be interesting. + typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap; + + /// \brief A mapping from all interesting identifiers to the set of module + /// files in which those identifiers are considered interesting. + InterestingIdentifierMap InterestingIdentifiers; + + /// \brief Write the block-info block for the global module index file. + void emitBlockInfoBlock(llvm::BitstreamWriter &Stream); + + /// \brief Retrieve the module file information for the given file. + ModuleFileInfo &getModuleFileInfo(const FileEntry *File) { + llvm::MapVector<const FileEntry *, ModuleFileInfo>::iterator Known + = ModuleFiles.find(File); + if (Known != ModuleFiles.end()) + return Known->second; + + unsigned NewID = ModuleFiles.size(); + ModuleFileInfo &Info = ModuleFiles[File]; + Info.ID = NewID; + return Info; + } + + public: + explicit GlobalModuleIndexBuilder(FileManager &FileMgr) : FileMgr(FileMgr){} + + /// \brief Load the contents of the given module file into the builder. + /// + /// \returns true if an error occurred, false otherwise. + bool loadModuleFile(const FileEntry *File); + + /// \brief Write the index to the given bitstream. + void writeIndex(llvm::BitstreamWriter &Stream); + }; +} + +static void emitBlockID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, + SmallVectorImpl<uint64_t> &Record) { + Record.clear(); + Record.push_back(ID); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); + + // Emit the block name if present. + if (Name == 0 || Name[0] == 0) return; + Record.clear(); + while (*Name) + Record.push_back(*Name++); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); +} + +static void emitRecordID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, + SmallVectorImpl<uint64_t> &Record) { + Record.clear(); + Record.push_back(ID); + while (*Name) + Record.push_back(*Name++); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); +} + +void +GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) { + SmallVector<uint64_t, 64> Record; + Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3); + +#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record) +#define RECORD(X) emitRecordID(X, #X, Stream, Record) + BLOCK(GLOBAL_INDEX_BLOCK); + RECORD(INDEX_METADATA); + RECORD(MODULE); + RECORD(IDENTIFIER_INDEX); +#undef RECORD +#undef BLOCK + + Stream.ExitBlock(); +} + +namespace { + class InterestingASTIdentifierLookupTrait + : public serialization::reader::ASTIdentifierLookupTraitBase { + + public: + /// \brief The identifier and whether it is "interesting". + typedef std::pair<StringRef, bool> data_type; + + data_type ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen) { + // The first bit indicates whether this identifier is interesting. + // That's all we care about. + using namespace clang::io; + unsigned RawID = ReadUnalignedLE32(d); + bool IsInteresting = RawID & 0x01; + return std::make_pair(k, IsInteresting); + } + }; +} + +bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { + // Open the module file. + OwningPtr<llvm::MemoryBuffer> Buffer; + std::string ErrorStr; + Buffer.reset(FileMgr.getBufferForFile(File, &ErrorStr, /*isVolatile=*/true)); + if (!Buffer) { + return true; + } + + // Initialize the input stream + llvm::BitstreamReader InStreamFile; + llvm::BitstreamCursor InStream; + InStreamFile.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + InStream.init(InStreamFile); + + // Sniff for the signature. + if (InStream.Read(8) != 'C' || + InStream.Read(8) != 'P' || + InStream.Read(8) != 'C' || + InStream.Read(8) != 'H') { + return true; + } + + // Record this module file and assign it a unique ID (if it doesn't have + // one already). + unsigned ID = getModuleFileInfo(File).ID; + + // Search for the blocks and records we care about. + enum { Other, ControlBlock, ASTBlock } State = Other; + bool Done = false; + while (!Done) { + llvm::BitstreamEntry Entry = InStream.advance(); + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + Done = true; + continue; + + case llvm::BitstreamEntry::Record: + // In the 'other' state, just skip the record. We don't care. + if (State == Other) { + InStream.skipRecord(Entry.ID); + continue; + } + + // Handle potentially-interesting records below. + break; + + case llvm::BitstreamEntry::SubBlock: + if (Entry.ID == CONTROL_BLOCK_ID) { + if (InStream.EnterSubBlock(CONTROL_BLOCK_ID)) + return true; + + // Found the control block. + State = ControlBlock; + continue; + } + + if (Entry.ID == AST_BLOCK_ID) { + if (InStream.EnterSubBlock(AST_BLOCK_ID)) + return true; + + // Found the AST block. + State = ASTBlock; + continue; + } + + if (InStream.SkipBlock()) + return true; + + continue; + + case llvm::BitstreamEntry::EndBlock: + State = Other; + continue; + } + + // Read the given record. + SmallVector<uint64_t, 64> Record; + StringRef Blob; + unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob); + + // Handle module dependencies. + if (State == ControlBlock && Code == IMPORTS) { + // Load each of the imported PCH files. + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + // Read information about the AST file. + + // Skip the imported kind + ++Idx; + + // Skip the import location + ++Idx; + + // Load stored size/modification time. + off_t StoredSize = (off_t)Record[Idx++]; + time_t StoredModTime = (time_t)Record[Idx++]; + + // Retrieve the imported file name. + unsigned Length = Record[Idx++]; + SmallString<128> ImportedFile(Record.begin() + Idx, + Record.begin() + Idx + Length); + Idx += Length; + + // Find the imported module file. + const FileEntry *DependsOnFile + = FileMgr.getFile(ImportedFile, /*openFile=*/false, + /*cacheFailure=*/false); + if (!DependsOnFile || + (StoredSize != DependsOnFile->getSize()) || + (StoredModTime != DependsOnFile->getModificationTime())) + return true; + + // Record the dependency. + unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID; + getModuleFileInfo(File).Dependencies.push_back(DependsOnID); + } + + continue; + } + + // Handle the identifier table + if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) { + typedef OnDiskChainedHashTable<InterestingASTIdentifierLookupTrait> + InterestingIdentifierTable; + llvm::OwningPtr<InterestingIdentifierTable> + Table(InterestingIdentifierTable::Create( + (const unsigned char *)Blob.data() + Record[0], + (const unsigned char *)Blob.data())); + for (InterestingIdentifierTable::data_iterator D = Table->data_begin(), + DEnd = Table->data_end(); + D != DEnd; ++D) { + std::pair<StringRef, bool> Ident = *D; + if (Ident.second) + InterestingIdentifiers[Ident.first].push_back(ID); + else + (void)InterestingIdentifiers[Ident.first]; + } + } + + // We don't care about this record. + } + + return false; +} + +namespace { + +/// \brief Trait used to generate the identifier index as an on-disk hash +/// table. +class IdentifierIndexWriterTrait { +public: + typedef StringRef key_type; + typedef StringRef key_type_ref; + typedef SmallVector<unsigned, 2> data_type; + typedef const SmallVector<unsigned, 2> &data_type_ref; + + static unsigned ComputeHash(key_type_ref Key) { + return llvm::HashString(Key); + } + + std::pair<unsigned,unsigned> + EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) { + unsigned KeyLen = Key.size(); + unsigned DataLen = Data.size() * 4; + clang::io::Emit16(Out, KeyLen); + clang::io::Emit16(Out, DataLen); + return std::make_pair(KeyLen, DataLen); + } + + void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) { + Out.write(Key.data(), KeyLen); + } + + void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data, + unsigned DataLen) { + for (unsigned I = 0, N = Data.size(); I != N; ++I) + clang::io::Emit32(Out, Data[I]); + } +}; + +} + +void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { + using namespace llvm; + + // Emit the file header. + Stream.Emit((unsigned)'B', 8); + Stream.Emit((unsigned)'C', 8); + Stream.Emit((unsigned)'G', 8); + Stream.Emit((unsigned)'I', 8); + + // Write the block-info block, which describes the records in this bitcode + // file. + emitBlockInfoBlock(Stream); + + Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3); + + // Write the metadata. + SmallVector<uint64_t, 2> Record; + Record.push_back(CurrentVersion); + Stream.EmitRecord(INDEX_METADATA, Record); + + // Write the set of known module files. + for (ModuleFilesMap::iterator M = ModuleFiles.begin(), + MEnd = ModuleFiles.end(); + M != MEnd; ++M) { + Record.clear(); + Record.push_back(M->second.ID); + Record.push_back(M->first->getSize()); + Record.push_back(M->first->getModificationTime()); + + // File name + StringRef Name(M->first->getName()); + Record.push_back(Name.size()); + Record.append(Name.begin(), Name.end()); + + // Dependencies + Record.push_back(M->second.Dependencies.size()); + Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end()); + Stream.EmitRecord(MODULE, Record); + } + + // Write the identifier -> module file mapping. + { + OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator; + IdentifierIndexWriterTrait Trait; + + // Populate the hash table. + for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(), + IEnd = InterestingIdentifiers.end(); + I != IEnd; ++I) { + Generator.insert(I->first(), I->second, Trait); + } + + // Create the on-disk hash table in a buffer. + SmallString<4096> IdentifierTable; + uint32_t BucketOffset; + { + llvm::raw_svector_ostream Out(IdentifierTable); + // Make sure that no bucket is at offset 0 + clang::io::Emit32(Out, 0); + BucketOffset = Generator.Emit(Out, Trait); + } + + // Create a blob abbreviation + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the identifier table + Record.clear(); + Record.push_back(IDENTIFIER_INDEX); + Record.push_back(BucketOffset); + Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str()); + } + + Stream.ExitBlock(); +} + +GlobalModuleIndex::ErrorCode +GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) { + llvm::SmallString<128> IndexPath; + IndexPath += Path; + llvm::sys::path::append(IndexPath, IndexFileName); + + // Coordinate building the global index file with other processes that might + // try to do the same. + llvm::LockFileManager Locked(IndexPath); + switch (Locked) { + case llvm::LockFileManager::LFS_Error: + return EC_IOError; + + case llvm::LockFileManager::LFS_Owned: + // We're responsible for building the index ourselves. Do so below. + break; + + case llvm::LockFileManager::LFS_Shared: + // Someone else is responsible for building the index. We don't care + // when they finish, so we're done. + return EC_Building; + } + + // The module index builder. + GlobalModuleIndexBuilder Builder(FileMgr); + + // Load each of the module files. + llvm::error_code EC; + for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd; + D != DEnd && !EC; + D.increment(EC)) { + // If this isn't a module file, we don't care. + if (llvm::sys::path::extension(D->path()) != ".pcm") { + // ... unless it's a .pcm.lock file, which indicates that someone is + // in the process of rebuilding a module. They'll rebuild the index + // at the end of that translation unit, so we don't have to. + if (llvm::sys::path::extension(D->path()) == ".pcm.lock") + return EC_Building; + + continue; + } + + // If we can't find the module file, skip it. + const FileEntry *ModuleFile = FileMgr.getFile(D->path()); + if (!ModuleFile) + continue; + + // Load this module file. + if (Builder.loadModuleFile(ModuleFile)) + return EC_IOError; + } + + // The output buffer, into which the global index will be written. + SmallVector<char, 16> OutputBuffer; + { + llvm::BitstreamWriter OutputStream(OutputBuffer); + Builder.writeIndex(OutputStream); + } + + // Write the global index file to a temporary file. + llvm::SmallString<128> IndexTmpPath; + int TmpFD; + if (llvm::sys::fs::unique_file(IndexPath + "-%%%%%%%%", TmpFD, IndexTmpPath)) + return EC_IOError; + + // Open the temporary global index file for output. + llvm::raw_fd_ostream Out(TmpFD, true); + if (Out.has_error()) + return EC_IOError; + + // Write the index. + Out.write(OutputBuffer.data(), OutputBuffer.size()); + Out.close(); + if (Out.has_error()) + return EC_IOError; + + // Remove the old index file. It isn't relevant any more. + bool OldIndexExisted; + llvm::sys::fs::remove(IndexPath.str(), OldIndexExisted); + + // Rename the newly-written index file to the proper name. + if (llvm::sys::fs::rename(IndexTmpPath.str(), IndexPath.str())) { + // Rename failed; just remove the + llvm::sys::fs::remove(IndexTmpPath.str(), OldIndexExisted); + return EC_IOError; + } + + // We're done. + return EC_None; +} diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp index 5e42ab4..2eb3971 100644 --- a/lib/Serialization/Module.cpp +++ b/lib/Serialization/Module.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// #include "clang/Serialization/Module.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/MemoryBuffer.h" #include "ASTReaderInternals.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace serialization; @@ -33,7 +33,7 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation) PreprocessedEntityOffsets(0), NumPreprocessedEntities(0), LocalNumHeaderFileInfos(0), HeaderFileInfoTableData(0), HeaderFileInfoTable(0), - HeaderFileFrameworkStrings(0), LocalNumSubmodules(0), BaseSubmoduleID(0), + LocalNumSubmodules(0), BaseSubmoduleID(0), LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0), SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), DeclOffsets(0), BaseDeclID(0), diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp index efe4421..f3d53ad 100644 --- a/lib/Serialization/ModuleManager.cpp +++ b/lib/Serialization/ModuleManager.cpp @@ -11,8 +11,11 @@ // modules for the ASTReader. // //===----------------------------------------------------------------------===// +#include "clang/Lex/ModuleMap.h" #include "clang/Serialization/ModuleManager.h" +#include "clang/Serialization/GlobalModuleIndex.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PathV2.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" @@ -24,37 +27,63 @@ using namespace clang; using namespace serialization; ModuleFile *ModuleManager::lookup(StringRef Name) { - const FileEntry *Entry = FileMgr.getFile(Name); - return Modules[Entry]; + const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false, + /*cacheFailure=*/false); + if (Entry) + return lookup(Entry); + + return 0; +} + +ModuleFile *ModuleManager::lookup(const FileEntry *File) { + llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known + = Modules.find(File); + if (Known == Modules.end()) + return 0; + + return Known->second; } llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { - const FileEntry *Entry = FileMgr.getFile(Name); + const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false, + /*cacheFailure=*/false); return InMemoryBuffers[Entry]; } -std::pair<ModuleFile *, bool> -ModuleManager::addModule(StringRef FileName, ModuleKind Type, - ModuleFile *ImportedBy, unsigned Generation, +ModuleManager::AddModuleResult +ModuleManager::addModule(StringRef FileName, ModuleKind Type, + SourceLocation ImportLoc, ModuleFile *ImportedBy, + unsigned Generation, + off_t ExpectedSize, time_t ExpectedModTime, + ModuleFile *&Module, std::string &ErrorStr) { - const FileEntry *Entry = FileMgr.getFile(FileName); + Module = 0; + + // Look for the file entry. This only fails if the expected size or + // modification time differ. + const FileEntry *Entry; + if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) + return OutOfDate; + if (!Entry && FileName != "-") { ErrorStr = "file not found"; - return std::make_pair(static_cast<ModuleFile*>(0), false); + return Missing; } - - // Check whether we already loaded this module, before + + // Check whether we already loaded this module, before ModuleFile *&ModuleEntry = Modules[Entry]; bool NewModule = false; if (!ModuleEntry) { // Allocate a new module. ModuleFile *New = new ModuleFile(Type, Generation); + New->Index = Chain.size(); New->FileName = FileName.str(); New->File = Entry; + New->ImportLoc = ImportLoc; Chain.push_back(New); NewModule = true; ModuleEntry = New; - + // Load the contents of the module if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) { // The buffer was already provided for us. @@ -71,21 +100,26 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr)); if (!New->Buffer) - return std::make_pair(static_cast<ModuleFile*>(0), false); + return Missing; } // Initialize the stream New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), - (const unsigned char *)New->Buffer->getBufferEnd()); } + (const unsigned char *)New->Buffer->getBufferEnd()); + } if (ImportedBy) { ModuleEntry->ImportedBy.insert(ImportedBy); ImportedBy->Imports.insert(ModuleEntry); } else { + if (!ModuleEntry->DirectlyImported) + ModuleEntry->ImportLoc = ImportLoc; + ModuleEntry->DirectlyImported = true; } - - return std::make_pair(ModuleEntry, NewModule); + + Module = ModuleEntry; + return NewModule? NewlyLoaded : AlreadyLoaded; } namespace { @@ -104,7 +138,8 @@ namespace { }; } -void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) { +void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last, + ModuleMap *modMap) { if (first == last) return; @@ -120,6 +155,14 @@ void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) { // Delete the modules and erase them from the various structures. for (ModuleIterator victim = first; victim != last; ++victim) { Modules.erase((*victim)->File); + + FileMgr.invalidateCache((*victim)->File); + if (modMap) { + StringRef ModuleName = llvm::sys::path::stem((*victim)->FileName); + if (Module *mod = modMap->findModule(ModuleName)) { + mod->setASTFile(0); + } + } delete *victim; } @@ -135,79 +178,166 @@ void ModuleManager::addInMemoryBuffer(StringRef FileName, InMemoryBuffers[Entry] = Buffer; } -ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { } +ModuleManager::VisitState *ModuleManager::allocateVisitState() { + // Fast path: if we have a cached state, use it. + if (FirstVisitState) { + VisitState *Result = FirstVisitState; + FirstVisitState = FirstVisitState->NextState; + Result->NextState = 0; + return Result; + } + + // Allocate and return a new state. + return new VisitState(size()); +} + +void ModuleManager::returnVisitState(VisitState *State) { + assert(State->NextState == 0 && "Visited state is in list?"); + State->NextState = FirstVisitState; + FirstVisitState = State; +} + +void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) { + GlobalIndex = Index; + if (!GlobalIndex) { + ModulesInCommonWithGlobalIndex.clear(); + return; + } + + // Notify the global module index about all of the modules we've already + // loaded. + for (unsigned I = 0, N = Chain.size(); I != N; ++I) { + if (!GlobalIndex->loadedModuleFile(Chain[I])) { + ModulesInCommonWithGlobalIndex.push_back(Chain[I]); + } + } +} + +void ModuleManager::moduleFileAccepted(ModuleFile *MF) { + if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF)) + return; + + ModulesInCommonWithGlobalIndex.push_back(MF); +} + +ModuleManager::ModuleManager(FileManager &FileMgr) + : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(0) { } ModuleManager::~ModuleManager() { for (unsigned i = 0, e = Chain.size(); i != e; ++i) delete Chain[e - i - 1]; + delete FirstVisitState; } -void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), - void *UserData) { - unsigned N = size(); - - // Record the number of incoming edges for each module. When we - // encounter a module with no incoming edges, push it into the queue - // to seed the queue. - SmallVector<ModuleFile *, 4> Queue; - Queue.reserve(N); - llvm::DenseMap<ModuleFile *, unsigned> UnusedIncomingEdges; - for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { - if (unsigned Size = (*M)->ImportedBy.size()) - UnusedIncomingEdges[*M] = Size; - else - Queue.push_back(*M); - } - - llvm::SmallPtrSet<ModuleFile *, 4> Skipped; - unsigned QueueStart = 0; - while (QueueStart < Queue.size()) { - ModuleFile *CurrentModule = Queue[QueueStart++]; +void +ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), + void *UserData, + llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit) { + // If the visitation order vector is the wrong size, recompute the order. + if (VisitOrder.size() != Chain.size()) { + unsigned N = size(); + VisitOrder.clear(); + VisitOrder.reserve(N); - // Check whether this module should be skipped. - if (Skipped.count(CurrentModule)) + // Record the number of incoming edges for each module. When we + // encounter a module with no incoming edges, push it into the queue + // to seed the queue. + SmallVector<ModuleFile *, 4> Queue; + Queue.reserve(N); + llvm::SmallVector<unsigned, 4> UnusedIncomingEdges; + UnusedIncomingEdges.reserve(size()); + for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { + if (unsigned Size = (*M)->ImportedBy.size()) + UnusedIncomingEdges.push_back(Size); + else { + UnusedIncomingEdges.push_back(0); + Queue.push_back(*M); + } + } + + // Traverse the graph, making sure to visit a module before visiting any + // of its dependencies. + unsigned QueueStart = 0; + while (QueueStart < Queue.size()) { + ModuleFile *CurrentModule = Queue[QueueStart++]; + VisitOrder.push_back(CurrentModule); + + // For any module that this module depends on, push it on the + // stack (if it hasn't already been marked as visited). + for (llvm::SetVector<ModuleFile *>::iterator + M = CurrentModule->Imports.begin(), + MEnd = CurrentModule->Imports.end(); + M != MEnd; ++M) { + // Remove our current module as an impediment to visiting the + // module we depend on. If we were the last unvisited module + // that depends on this particular module, push it into the + // queue to be visited. + unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index]; + if (NumUnusedEdges && (--NumUnusedEdges == 0)) + Queue.push_back(*M); + } + } + + assert(VisitOrder.size() == N && "Visitation order is wrong?"); + + delete FirstVisitState; + FirstVisitState = 0; + } + + VisitState *State = allocateVisitState(); + unsigned VisitNumber = State->NextVisitNumber++; + + // If the caller has provided us with a hit-set that came from the global + // module index, mark every module file in common with the global module + // index that is *not* in that set as 'visited'. + if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) { + for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I) + { + ModuleFile *M = ModulesInCommonWithGlobalIndex[I]; + if (!ModuleFilesHit->count(M)) + State->VisitNumber[M->Index] = VisitNumber; + } + } + + for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) { + ModuleFile *CurrentModule = VisitOrder[I]; + // Should we skip this module file? + if (State->VisitNumber[CurrentModule->Index] == VisitNumber) continue; - - if (Visitor(*CurrentModule, UserData)) { - // The visitor has requested that cut off visitation of any - // module that the current module depends on. To indicate this - // behavior, we mark all of the reachable modules as having N - // incoming edges (which is impossible otherwise). - SmallVector<ModuleFile *, 4> Stack; - Stack.push_back(CurrentModule); - Skipped.insert(CurrentModule); - while (!Stack.empty()) { - ModuleFile *NextModule = Stack.back(); - Stack.pop_back(); - - // For any module that this module depends on, push it on the - // stack (if it hasn't already been marked as visited). - for (llvm::SetVector<ModuleFile *>::iterator + + // Visit the module. + assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1); + State->VisitNumber[CurrentModule->Index] = VisitNumber; + if (!Visitor(*CurrentModule, UserData)) + continue; + + // The visitor has requested that cut off visitation of any + // module that the current module depends on. To indicate this + // behavior, we mark all of the reachable modules as having been visited. + ModuleFile *NextModule = CurrentModule; + do { + // For any module that this module depends on, push it on the + // stack (if it hasn't already been marked as visited). + for (llvm::SetVector<ModuleFile *>::iterator M = NextModule->Imports.begin(), MEnd = NextModule->Imports.end(); - M != MEnd; ++M) { - if (Skipped.insert(*M)) - Stack.push_back(*M); + M != MEnd; ++M) { + if (State->VisitNumber[(*M)->Index] != VisitNumber) { + State->Stack.push_back(*M); + State->VisitNumber[(*M)->Index] = VisitNumber; } } - continue; - } - - // For any module that this module depends on, push it on the - // stack (if it hasn't already been marked as visited). - for (llvm::SetVector<ModuleFile *>::iterator M = CurrentModule->Imports.begin(), - MEnd = CurrentModule->Imports.end(); - M != MEnd; ++M) { - - // Remove our current module as an impediment to visiting the - // module we depend on. If we were the last unvisited module - // that depends on this particular module, push it into the - // queue to be visited. - unsigned &NumUnusedEdges = UnusedIncomingEdges[*M]; - if (NumUnusedEdges && (--NumUnusedEdges == 0)) - Queue.push_back(*M); - } + + if (State->Stack.empty()) + break; + + // Pop the next module off the stack. + NextModule = State->Stack.back(); + State->Stack.pop_back(); + } while (true); } + + returnVisitState(State); } /// \brief Perform a depth-first visit of the current module. @@ -215,18 +345,19 @@ static bool visitDepthFirst(ModuleFile &M, bool (*Visitor)(ModuleFile &M, bool Preorder, void *UserData), void *UserData, - llvm::SmallPtrSet<ModuleFile *, 4> &Visited) { + SmallVectorImpl<bool> &Visited) { // Preorder visitation if (Visitor(M, /*Preorder=*/true, UserData)) return true; // Visit children for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(), - IMEnd = M.Imports.end(); + IMEnd = M.Imports.end(); IM != IMEnd; ++IM) { - if (!Visited.insert(*IM)) + if (Visited[(*IM)->Index]) continue; - + Visited[(*IM)->Index] = true; + if (visitDepthFirst(**IM, Visitor, UserData, Visited)) return true; } @@ -238,16 +369,35 @@ static bool visitDepthFirst(ModuleFile &M, void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder, void *UserData), void *UserData) { - llvm::SmallPtrSet<ModuleFile *, 4> Visited; + SmallVector<bool, 16> Visited(size(), false); for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (!Visited.insert(Chain[I])) + if (Visited[Chain[I]->Index]) continue; - + Visited[Chain[I]->Index] = true; + if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) return; } } +bool ModuleManager::lookupModuleFile(StringRef FileName, + off_t ExpectedSize, + time_t ExpectedModTime, + const FileEntry *&File) { + File = FileMgr.getFile(FileName, /*openFile=*/false, /*cacheFailure=*/false); + + if (!File && FileName != "-") { + return false; + } + + if ((ExpectedSize && ExpectedSize != File->getSize()) || + (ExpectedModTime && ExpectedModTime != File->getModificationTime())) { + return true; + } + + return false; +} + #ifndef NDEBUG namespace llvm { template<> |