summaryrefslogtreecommitdiffstats
path: root/lib/Serialization
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Serialization')
-rw-r--r--lib/Serialization/ASTCommon.cpp134
-rw-r--r--lib/Serialization/ASTCommon.h17
-rw-r--r--lib/Serialization/ASTReader.cpp2238
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp200
-rw-r--r--lib/Serialization/ASTReaderInternals.h128
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp55
-rw-r--r--lib/Serialization/ASTWriter.cpp974
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp78
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp13
-rw-r--r--lib/Serialization/CMakeLists.txt3
-rw-r--r--lib/Serialization/GeneratePCH.cpp10
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp820
-rw-r--r--lib/Serialization/Module.cpp6
-rw-r--r--lib/Serialization/ModuleManager.cpp316
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<>
OpenPOWER on IntegriCloud