summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp2047
1 files changed, 1104 insertions, 943 deletions
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
index 9fbf55b..7d88a31 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
@@ -138,23 +139,33 @@ bool ChainedASTReaderListener::needsSystemInputFileVisitation() {
return First->needsSystemInputFileVisitation() ||
Second->needsSystemInputFileVisitation();
}
-void ChainedASTReaderListener::visitModuleFile(StringRef Filename) {
- First->visitModuleFile(Filename);
- Second->visitModuleFile(Filename);
+void ChainedASTReaderListener::visitModuleFile(StringRef Filename,
+ ModuleKind Kind) {
+ First->visitModuleFile(Filename, Kind);
+ Second->visitModuleFile(Filename, Kind);
}
bool ChainedASTReaderListener::visitInputFile(StringRef Filename,
bool isSystem,
- bool isOverridden) {
+ bool isOverridden,
+ bool isExplicitModule) {
bool Continue = false;
if (First->needsInputFileVisitation() &&
(!isSystem || First->needsSystemInputFileVisitation()))
- Continue |= First->visitInputFile(Filename, isSystem, isOverridden);
+ Continue |= First->visitInputFile(Filename, isSystem, isOverridden,
+ isExplicitModule);
if (Second->needsInputFileVisitation() &&
(!isSystem || Second->needsSystemInputFileVisitation()))
- Continue |= Second->visitInputFile(Filename, isSystem, isOverridden);
+ Continue |= Second->visitInputFile(Filename, isSystem, isOverridden,
+ isExplicitModule);
return Continue;
}
+void ChainedASTReaderListener::readModuleFileExtension(
+ const ModuleFileExtensionMetadata &Metadata) {
+ First->readModuleFileExtension(Metadata);
+ Second->readModuleFileExtension(Metadata);
+}
+
//===----------------------------------------------------------------------===//
// PCH validator implementation
//===----------------------------------------------------------------------===//
@@ -735,13 +746,26 @@ ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) {
}
/// \brief Whether the given identifier is "interesting".
-static bool isInterestingIdentifier(IdentifierInfo &II) {
- return II.isPoisoned() ||
- II.isExtensionToken() ||
- II.getObjCOrBuiltinID() ||
+static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II,
+ bool IsModule) {
+ return II.hadMacroDefinition() ||
+ II.isPoisoned() ||
+ (IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) ||
II.hasRevertedTokenIDToIdentifier() ||
- II.hadMacroDefinition() ||
- II.getFETokenInfo<void>();
+ (!(IsModule && Reader.getContext().getLangOpts().CPlusPlus) &&
+ II.getFETokenInfo<void>());
+}
+
+static bool readBit(unsigned &Bits) {
+ bool Value = Bits & 0x1;
+ Bits >>= 1;
+ return Value;
+}
+
+IdentID ASTIdentifierLookupTrait::ReadIdentifierID(const unsigned char *d) {
+ using namespace llvm::support;
+ unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d);
+ return Reader.getGlobalIdentifierID(F, RawID >> 1);
}
IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
@@ -754,62 +778,52 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// Wipe out the "is interesting" bit.
RawID = RawID >> 1;
+ // Build the IdentifierInfo and link the identifier ID with it.
+ IdentifierInfo *II = KnownII;
+ if (!II) {
+ II = &Reader.getIdentifierTable().getOwn(k);
+ KnownII = II;
+ }
+ if (!II->isFromAST()) {
+ II->setIsFromAST();
+ bool IsModule = Reader.PP.getCurrentModule() != nullptr;
+ if (isInterestingIdentifier(Reader, *II, IsModule))
+ II->setChangedSinceDeserialization();
+ }
+ Reader.markIdentifierUpToDate(II);
+
IdentID ID = Reader.getGlobalIdentifierID(F, RawID);
if (!IsInteresting) {
- // For uninteresting identifiers, just build the IdentifierInfo
- // and associate it with the persistent ID.
- IdentifierInfo *II = KnownII;
- if (!II) {
- II = &Reader.getIdentifierTable().getOwn(k);
- KnownII = II;
- }
+ // For uninteresting identifiers, there's nothing else to do. Just notify
+ // the reader that we've finished loading this identifier.
Reader.SetIdentifierInfo(ID, II);
- if (!II->isFromAST()) {
- bool WasInteresting = isInterestingIdentifier(*II);
- II->setIsFromAST();
- if (WasInteresting)
- II->setChangedSinceDeserialization();
- }
- Reader.markIdentifierUpToDate(II);
return II;
}
unsigned ObjCOrBuiltinID = endian::readNext<uint16_t, little, unaligned>(d);
unsigned Bits = endian::readNext<uint16_t, little, unaligned>(d);
- bool CPlusPlusOperatorKeyword = Bits & 0x01;
- Bits >>= 1;
- bool HasRevertedTokenIDToIdentifier = Bits & 0x01;
- Bits >>= 1;
- bool Poisoned = Bits & 0x01;
- Bits >>= 1;
- bool ExtensionToken = Bits & 0x01;
- Bits >>= 1;
- bool hadMacroDefinition = Bits & 0x01;
- Bits >>= 1;
+ bool CPlusPlusOperatorKeyword = readBit(Bits);
+ bool HasRevertedTokenIDToIdentifier = readBit(Bits);
+ bool HasRevertedBuiltin = readBit(Bits);
+ bool Poisoned = readBit(Bits);
+ bool ExtensionToken = readBit(Bits);
+ bool HadMacroDefinition = readBit(Bits);
assert(Bits == 0 && "Extra bits in the identifier?");
DataLen -= 8;
- // Build the IdentifierInfo itself and link the identifier ID with
- // the new IdentifierInfo.
- IdentifierInfo *II = KnownII;
- if (!II) {
- II = &Reader.getIdentifierTable().getOwn(StringRef(k));
- KnownII = II;
- }
- Reader.markIdentifierUpToDate(II);
- 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 && II->getTokenID() != tok::identifier)
- II->RevertTokenIDToIdentifier();
- II->setObjCOrBuiltinID(ObjCOrBuiltinID);
+ II->revertTokenIDToIdentifier();
+ if (!F.isModule())
+ II->setObjCOrBuiltinID(ObjCOrBuiltinID);
+ else if (HasRevertedBuiltin && II->getBuiltinID()) {
+ II->revertBuiltin();
+ assert((II->hasRevertedBuiltin() ||
+ II->getObjCOrBuiltinID() == ObjCOrBuiltinID) &&
+ "Incorrect ObjC keyword or builtin ID");
+ }
assert(II->isExtensionToken() == ExtensionToken &&
"Incorrect extension token flag");
(void)ExtensionToken;
@@ -821,7 +835,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// If this identifier is a macro, deserialize the macro
// definition.
- if (hadMacroDefinition) {
+ if (HadMacroDefinition) {
uint32_t MacroDirectivesOffset =
endian::readNext<uint32_t, little, unaligned>(d);
DataLen -= 4;
@@ -844,168 +858,187 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
return II;
}
-unsigned
-ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) {
- llvm::FoldingSetNodeID ID;
- ID.AddInteger(Key.Kind);
-
- switch (Key.Kind) {
+DeclarationNameKey::DeclarationNameKey(DeclarationName Name)
+ : Kind(Name.getNameKind()) {
+ switch (Kind) {
case DeclarationName::Identifier:
- case DeclarationName::CXXLiteralOperatorName:
- ID.AddString(((IdentifierInfo*)Key.Data)->getName());
+ Data = (uint64_t)Name.getAsIdentifierInfo();
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- ID.AddInteger(serialization::ComputeHash(Selector(Key.Data)));
+ Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr();
break;
case DeclarationName::CXXOperatorName:
- ID.AddInteger((OverloadedOperatorKind)Key.Data);
+ Data = Name.getCXXOverloadedOperator();
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ Data = (uint64_t)Name.getCXXLiteralIdentifier();
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
+ Data = 0;
break;
}
-
- return ID.ComputeHash();
}
-ASTDeclContextNameLookupTrait::internal_key_type
-ASTDeclContextNameLookupTrait::GetInternalKey(
- const external_key_type& Name) {
- DeclNameKey Key;
- Key.Kind = Name.getNameKind();
- switch (Name.getNameKind()) {
+unsigned DeclarationNameKey::getHash() const {
+ llvm::FoldingSetNodeID ID;
+ ID.AddInteger(Kind);
+
+ switch (Kind) {
case DeclarationName::Identifier:
- Key.Data = (uint64_t)Name.getAsIdentifierInfo();
+ case DeclarationName::CXXLiteralOperatorName:
+ ID.AddString(((IdentifierInfo*)Data)->getName());
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr();
+ ID.AddInteger(serialization::ComputeHash(Selector(Data)));
break;
case DeclarationName::CXXOperatorName:
- Key.Data = Name.getCXXOverloadedOperator();
- break;
- case DeclarationName::CXXLiteralOperatorName:
- Key.Data = (uint64_t)Name.getCXXLiteralIdentifier();
+ ID.AddInteger((OverloadedOperatorKind)Data);
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
- Key.Data = 0;
break;
}
- return Key;
+ return ID.ComputeHash();
+}
+
+ModuleFile *
+ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) {
+ using namespace llvm::support;
+ uint32_t ModuleFileID = endian::readNext<uint32_t, little, unaligned>(d);
+ return Reader.getLocalModuleFile(F, ModuleFileID);
}
std::pair<unsigned, unsigned>
-ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char *&d) {
using namespace llvm::support;
unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
return std::make_pair(KeyLen, DataLen);
}
-ASTDeclContextNameLookupTrait::internal_key_type
-ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) {
+ASTDeclContextNameLookupTrait::internal_key_type
+ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) {
using namespace llvm::support;
- DeclNameKey Key;
- Key.Kind = (DeclarationName::NameKind)*d++;
- switch (Key.Kind) {
+ auto Kind = (DeclarationName::NameKind)*d++;
+ uint64_t Data;
+ switch (Kind) {
case DeclarationName::Identifier:
- Key.Data = (uint64_t)Reader.getLocalIdentifier(
+ Data = (uint64_t)Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, little, unaligned>(d));
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- Key.Data =
+ Data =
(uint64_t)Reader.getLocalSelector(
F, endian::readNext<uint32_t, little, unaligned>(
d)).getAsOpaquePtr();
break;
case DeclarationName::CXXOperatorName:
- Key.Data = *d++; // OverloadedOperatorKind
+ Data = *d++; // OverloadedOperatorKind
break;
case DeclarationName::CXXLiteralOperatorName:
- Key.Data = (uint64_t)Reader.getLocalIdentifier(
+ Data = (uint64_t)Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, little, unaligned>(d));
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXUsingDirective:
- Key.Data = 0;
+ Data = 0;
break;
}
- return Key;
+ return DeclarationNameKey(Kind, Data);
}
-ASTDeclContextNameLookupTrait::data_type
-ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
- const unsigned char* d,
- unsigned DataLen) {
+void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type,
+ const unsigned char *d,
+ unsigned DataLen,
+ data_type_builder &Val) {
using namespace llvm::support;
- unsigned NumDecls = endian::readNext<uint16_t, little, unaligned>(d);
- LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
- const_cast<unsigned char *>(d));
- return std::make_pair(Start, Start + NumDecls);
+ for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) {
+ uint32_t LocalID = endian::readNext<uint32_t, little, unaligned>(d);
+ Val.insert(Reader.getGlobalDeclID(F, LocalID));
+ }
}
-bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
- BitstreamCursor &Cursor,
- const std::pair<uint64_t, uint64_t> &Offsets,
- DeclContextInfo &Info) {
- SavedStreamPosition SavedPosition(Cursor);
- // First the lexical decls.
- if (Offsets.first != 0) {
- Cursor.JumpToBit(Offsets.first);
+bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M,
+ BitstreamCursor &Cursor,
+ uint64_t Offset,
+ DeclContext *DC) {
+ assert(Offset != 0);
- RecordData Record;
- StringRef Blob;
- unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
- if (RecCode != DECL_CONTEXT_LEXICAL) {
- Error("Expected lexical block");
- return true;
- }
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Offset);
- Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob.data());
- Info.NumLexicalDecls = Blob.size() / sizeof(KindDeclIDPair);
+ RecordData Record;
+ StringRef Blob;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
+ if (RecCode != DECL_CONTEXT_LEXICAL) {
+ Error("Expected lexical block");
+ return true;
}
- // Now the lookup table.
- if (Offsets.second != 0) {
- Cursor.JumpToBit(Offsets.second);
+ assert(!isa<TranslationUnitDecl>(DC) &&
+ "expected a TU_UPDATE_LEXICAL record for TU");
+ // If we are handling a C++ class template instantiation, we can see multiple
+ // lexical updates for the same record. It's important that we select only one
+ // of them, so that field numbering works properly. Just pick the first one we
+ // see.
+ auto &Lex = LexicalDecls[DC];
+ if (!Lex.first) {
+ Lex = std::make_pair(
+ &M, llvm::makeArrayRef(
+ reinterpret_cast<const llvm::support::unaligned_uint32_t *>(
+ Blob.data()),
+ Blob.size() / 4));
+ }
+ DC->setHasExternalLexicalStorage(true);
+ return false;
+}
- RecordData Record;
- StringRef Blob;
- unsigned Code = Cursor.ReadCode();
- 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.data() + Record[0],
- (const unsigned char *)Blob.data() + sizeof(uint32_t),
- (const unsigned char *)Blob.data(),
- ASTDeclContextNameLookupTrait(*this, M));
+bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M,
+ BitstreamCursor &Cursor,
+ uint64_t Offset,
+ DeclID ID) {
+ assert(Offset != 0);
+
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Offset);
+
+ RecordData Record;
+ StringRef Blob;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
+ if (RecCode != DECL_CONTEXT_VISIBLE) {
+ Error("Expected visible lookup table block");
+ return true;
}
+ // We can't safely determine the primary context yet, so delay attaching the
+ // lookup table until we're done with recursive deserialization.
+ auto *Data = (const unsigned char*)Blob.data();
+ PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data});
return false;
}
void ASTReader::Error(StringRef Msg) {
Error(diag::err_fe_pch_malformed, Msg);
- if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight()) {
+ if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight() &&
+ !PP.getHeaderSearchInfo().getModuleCachePath().empty()) {
Diag(diag::note_module_cache_path)
<< PP.getHeaderSearchInfo().getModuleCachePath();
}
@@ -1032,11 +1065,12 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
// Parse the file names
std::map<int, int> FileIDs;
- for (int I = 0, N = Record[Idx++]; I != N; ++I) {
+ for (unsigned I = 0; Record[Idx]; ++I) {
// Extract the file name
auto Filename = ReadPath(F, Record, Idx);
FileIDs[I] = LineTable.getLineTableFilenameID(Filename);
}
+ ++Idx;
// Parse the line entries
std::vector<LineEntry> Entries;
@@ -1048,7 +1082,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
// Extract the line entries
unsigned NumEntries = Record[Idx++];
- assert(NumEntries && "Numentries is 00000");
+ assert(NumEntries && "no line entries for file ID");
Entries.clear();
Entries.reserve(NumEntries);
for (unsigned I = 0; I != NumEntries; ++I) {
@@ -1225,7 +1259,8 @@ bool ASTReader::ReadSLocEntry(int ID) {
= SourceMgr.getOrCreateContentCache(File,
/*isSystemFile=*/FileCharacter != SrcMgr::C_User);
if (OverriddenBuffer && !ContentCache->BufferOverridden &&
- ContentCache->ContentsEntry == ContentCache->OrigEntry) {
+ ContentCache->ContentsEntry == ContentCache->OrigEntry &&
+ !ContentCache->getRawBuffer()) {
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob);
@@ -1313,7 +1348,7 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
// location of its includer.
if (F->ImportedBy.empty() || !F->ImportedBy[0]) {
// Main file is the importer.
- assert(!SourceMgr.getMainFileID().isInvalid() && "missing main file");
+ assert(SourceMgr.getMainFileID().isValid() && "missing main file");
return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
}
return F->ImportedBy[0]->FirstLoc;
@@ -1323,10 +1358,8 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
/// 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(BitstreamCursor &Cursor, unsigned BlockID) {
- if (Cursor.EnterSubBlock(BlockID)) {
- Error("malformed block record in AST file");
- return Failure;
- }
+ if (Cursor.EnterSubBlock(BlockID))
+ return true;
while (true) {
uint64_t Offset = Cursor.GetCurrentBitNo();
@@ -1425,8 +1458,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
if (isC99VarArgs) MI->setIsC99Varargs();
if (isGNUVarArgs) MI->setIsGNUVarargs();
if (hasCommaPasting) MI->setHasCommaPasting();
- MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
- PP.getPreprocessorAllocator());
+ MI->setArgumentList(MacroArgs, PP.getPreprocessorAllocator());
}
// Remember that we saw this macro last so that we add the tokens that
@@ -1481,13 +1513,14 @@ unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
HeaderFileInfoTrait::internal_key_type
HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
- internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
- FE->getName(), /*Imported*/false };
+ internal_key_type ikey = {FE->getSize(),
+ M.HasTimestamps ? FE->getModificationTime() : 0,
+ FE->getName(), /*Imported*/ false};
return ikey;
}
bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
- if (a.Size != b.Size || a.ModTime != b.ModTime)
+ if (a.Size != b.Size || (a.ModTime && b.ModTime && a.ModTime != b.ModTime))
return false;
if (llvm::sys::path::is_absolute(a.Filename) &&
@@ -1536,14 +1569,15 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
using namespace llvm::support;
HeaderFileInfo HFI;
unsigned Flags = *d++;
- HFI.HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>
- ((Flags >> 6) & 0x03);
- HFI.isImport = (Flags >> 5) & 0x01;
- HFI.isPragmaOnce = (Flags >> 4) & 0x01;
- HFI.DirInfo = (Flags >> 2) & 0x03;
- HFI.Resolved = (Flags >> 1) & 0x01;
+ // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp.
+ HFI.isImport |= (Flags >> 4) & 0x01;
+ HFI.isPragmaOnce |= (Flags >> 3) & 0x01;
+ HFI.DirInfo = (Flags >> 1) & 0x03;
HFI.IndexHeaderMapHeader = Flags & 0x01;
- HFI.NumIncludes = endian::readNext<uint16_t, little, unaligned>(d);
+ // FIXME: Find a better way to handle this. Maybe just store a
+ // "has been included" flag?
+ HFI.NumIncludes = std::max(endian::readNext<uint16_t, little, unaligned>(d),
+ HFI.NumIncludes);
HFI.ControllingMacroID = Reader.getGlobalIdentifierID(
M, endian::readNext<uint32_t, little, unaligned>(d));
if (unsigned FrameworkOffset =
@@ -1553,34 +1587,36 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
}
-
- if (d != End) {
+
+ assert((End - d) % 4 == 0 &&
+ "Wrong data length in HeaderFileInfo deserialization");
+ while (d != End) {
uint32_t LocalSMID = endian::readNext<uint32_t, little, unaligned>(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();
- // FIXME: This information should be propagated through the
- // SUBMODULE_HEADER etc records rather than from here.
- // FIXME: We don't ever mark excluded headers.
- std::string Filename = key.Filename;
- if (key.Imported)
- Reader.ResolveImportedPath(M, Filename);
- Module::Header H = { key.Filename, FileMgr.getFile(Filename) };
- ModMap.addHeader(Mod, H, HFI.getHeaderRole());
- }
- }
-
- assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
- (void)End;
-
+ auto HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>(LocalSMID & 3);
+ LocalSMID >>= 2;
+
+ // 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);
+ FileManager &FileMgr = Reader.getFileManager();
+ ModuleMap &ModMap =
+ Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+
+ std::string Filename = key.Filename;
+ if (key.Imported)
+ Reader.ResolveImportedPath(M, Filename);
+ // FIXME: This is not always the right filename-as-written, but we're not
+ // going to use this information to rebuild the module, so it doesn't make
+ // a lot of difference.
+ Module::Header H = { key.Filename, FileMgr.getFile(Filename) };
+ ModMap.addHeader(Mod, H, HeaderRole, /*Imported*/true);
+ HFI.isModuleHeader |= !(HeaderRole & ModuleMap::TextualHeader);
+ }
+
// This HeaderFileInfo was externally loaded.
HFI.External = true;
+ HFI.IsValid = true;
return HFI;
}
@@ -1595,16 +1631,15 @@ void ASTReader::ReadDefinedMacros() {
// Note that we are loading defined macros.
Deserializing Macros(this);
- for (ModuleReverseIterator I = ModuleMgr.rbegin(),
- E = ModuleMgr.rend(); I != E; ++I) {
- BitstreamCursor &MacroCursor = (*I)->MacroCursor;
+ for (auto &I : llvm::reverse(ModuleMgr)) {
+ BitstreamCursor &MacroCursor = I->MacroCursor;
// If there was no preprocessor block, skip this file.
if (!MacroCursor.getBitStreamReader())
continue;
BitstreamCursor Cursor = MacroCursor;
- Cursor.JumpToBit((*I)->MacroStartOffset);
+ Cursor.JumpToBit(I->MacroStartOffset);
RecordData Record;
while (true) {
@@ -1626,7 +1661,7 @@ void ASTReader::ReadDefinedMacros() {
case PP_MACRO_OBJECT_LIKE:
case PP_MACRO_FUNCTION_LIKE:
- getLocalIdentifier(**I, Record[0]);
+ getLocalIdentifier(*I, Record[0]);
break;
case PP_TOKEN:
@@ -1661,33 +1696,30 @@ namespace {
Found()
{
}
-
- static bool visit(ModuleFile &M, void *UserData) {
- IdentifierLookupVisitor *This
- = static_cast<IdentifierLookupVisitor *>(UserData);
-
+
+ bool operator()(ModuleFile &M) {
// If we've already searched this module file, skip it now.
- if (M.Generation <= This->PriorGeneration)
+ if (M.Generation <= PriorGeneration)
return true;
ASTIdentifierLookupTable *IdTable
= (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
if (!IdTable)
return false;
-
- ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
- M, This->Found);
- ++This->NumIdentifierLookups;
+
+ ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M,
+ Found);
+ ++NumIdentifierLookups;
ASTIdentifierLookupTable::iterator Pos =
- IdTable->find_hashed(This->Name, This->NameHash, &Trait);
+ IdTable->find_hashed(Name, NameHash, &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;
+ ++NumIdentifierLookupHits;
+ Found = *Pos;
return true;
}
@@ -1718,7 +1750,7 @@ void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration,
NumIdentifierLookups,
NumIdentifierLookupHits);
- ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
+ ModuleMgr.visit(Visitor, HitsPtr);
markIdentifierUpToDate(&II);
}
@@ -1859,26 +1891,17 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
"invalid record type for input file");
(void)Result;
- std::string Filename;
- off_t StoredSize;
- time_t StoredTime;
- bool Overridden;
-
assert(Record[0] == ID && "Bogus stored ID or offset");
- StoredSize = static_cast<off_t>(Record[1]);
- StoredTime = static_cast<time_t>(Record[2]);
- Overridden = static_cast<bool>(Record[3]);
- Filename = Blob;
- ResolveImportedPath(F, Filename);
-
- InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden };
+ InputFileInfo R;
+ R.StoredSize = static_cast<off_t>(Record[1]);
+ R.StoredTime = static_cast<time_t>(Record[2]);
+ R.Overridden = static_cast<bool>(Record[3]);
+ R.Transient = static_cast<bool>(Record[4]);
+ R.Filename = Blob;
+ ResolveImportedPath(F, R.Filename);
return R;
}
-std::string ASTReader::getInputFileName(ModuleFile &F, unsigned int ID) {
- return readInputFileInfo(F, ID).Filename;
-}
-
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())
@@ -1900,11 +1923,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
off_t StoredSize = FI.StoredSize;
time_t StoredTime = FI.StoredTime;
bool Overridden = FI.Overridden;
+ bool Transient = FI.Transient;
StringRef Filename = FI.Filename;
- const FileEntry *File
- = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
- : FileMgr.getFile(Filename, /*OpenFile=*/false);
+ const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false);
// If we didn't find the file, resolve it relative to the
// original directory from which this AST file was created.
@@ -1919,15 +1941,16 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// For an overridden file, create a virtual file with the stored
// size/timestamp.
- if (Overridden && File == nullptr) {
+ if ((Overridden || Transient) && File == nullptr)
File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
- }
if (File == nullptr) {
if (Complain) {
std::string ErrorStr = "could not find file '";
ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
+ ErrorStr += "' referenced by AST file '";
+ ErrorStr += F.FileName;
+ ErrorStr += "'";
Error(ErrorStr.c_str());
}
// Record that we didn't find the file.
@@ -1940,11 +1963,17 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// can lead to problems when lexing using the source locations from the
// PCH.
SourceManager &SM = getSourceManager();
- if (!Overridden && SM.isFileOverridden(File)) {
+ // FIXME: Reject if the overrides are different.
+ if ((!Overridden && !Transient) && SM.isFileOverridden(File)) {
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.
+ //
+ // FIXME: This recovery is just as broken as the original state; there may
+ // be another precompiled module that's using the overridden contents, or
+ // we might be half way through parsing it. Instead, we should treat the
+ // overridden contents as belonging to a separate FileEntry.
SM.disableFileContentsOverride(File);
// The FileEntry is a virtual file entry with the size of the contents
// that would override the original contents. Set it to the original's
@@ -1965,14 +1994,9 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// have inconsistent modification times that sometimes
// erroneously trigger this error-handling path.
//
- // This also happens in networked file systems, so disable this
- // check if validation is disabled or if we have an explicitly
- // built PCM file.
- //
- // FIXME: Should we also do this for PCH files? They could also
- // reasonably get shared across a network during a distributed build.
- (StoredTime != File->getModificationTime() && !DisableValidation &&
- F.Kind != MK_ExplicitModule)
+ // FIXME: This probably also breaks HeaderFileInfo lookups on Windows.
+ (StoredTime && StoredTime != File->getModificationTime() &&
+ !DisableValidation)
#endif
)) {
if (Complain) {
@@ -2000,8 +2024,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
IsOutOfDate = true;
}
+ // FIXME: If the file is overridden and we've already opened it,
+ // issue an error (or split it into a separate FileEntry).
- InputFile IF = InputFile(File, Overridden, IsOutOfDate);
+ InputFile IF = InputFile(File, Overridden || Transient, IsOutOfDate);
// Note that we've loaded this input file.
F.InputFilesLoaded[ID-1] = IF;
@@ -2026,24 +2052,114 @@ void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) {
Filename.assign(Buffer.begin(), Buffer.end());
}
+static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) {
+ switch (ARR) {
+ case ASTReader::Failure: return true;
+ case ASTReader::Missing: return !(Caps & ASTReader::ARR_Missing);
+ case ASTReader::OutOfDate: return !(Caps & ASTReader::ARR_OutOfDate);
+ case ASTReader::VersionMismatch: return !(Caps & ASTReader::ARR_VersionMismatch);
+ case ASTReader::ConfigurationMismatch:
+ return !(Caps & ASTReader::ARR_ConfigurationMismatch);
+ case ASTReader::HadErrors: return true;
+ case ASTReader::Success: return false;
+ }
+
+ llvm_unreachable("unknown ASTReadResult");
+}
+
+ASTReader::ASTReadResult ASTReader::ReadOptionsBlock(
+ BitstreamCursor &Stream, unsigned ClientLoadCapabilities,
+ bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener,
+ std::string &SuggestedPredefines) {
+ if (Stream.EnterSubBlock(OPTIONS_BLOCK_ID))
+ return Failure;
+
+ // Read all of the records in the options block.
+ RecordData Record;
+ ASTReadResult Result = Success;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::SubBlock:
+ return Failure;
+
+ case llvm::BitstreamEntry::EndBlock:
+ return Result;
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ switch ((OptionsRecordTypes)Stream.readRecord(Entry.ID, Record)) {
+ case LANGUAGE_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (ParseLanguageOptions(Record, Complain, Listener,
+ AllowCompatibleConfigurationMismatch))
+ Result = ConfigurationMismatch;
+ break;
+ }
+
+ case TARGET_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (ParseTargetOptions(Record, Complain, Listener,
+ AllowCompatibleConfigurationMismatch))
+ Result = ConfigurationMismatch;
+ break;
+ }
+
+ case DIAGNOSTIC_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
+ if (!AllowCompatibleConfigurationMismatch &&
+ ParseDiagnosticOptions(Record, Complain, Listener))
+ return OutOfDate;
+ break;
+ }
+
+ case FILE_SYSTEM_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (!AllowCompatibleConfigurationMismatch &&
+ ParseFileSystemOptions(Record, Complain, Listener))
+ Result = ConfigurationMismatch;
+ break;
+ }
+
+ case HEADER_SEARCH_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (!AllowCompatibleConfigurationMismatch &&
+ ParseHeaderSearchOptions(Record, Complain, Listener))
+ Result = ConfigurationMismatch;
+ break;
+ }
+
+ case PREPROCESSOR_OPTIONS:
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (!AllowCompatibleConfigurationMismatch &&
+ ParsePreprocessorOptions(Record, Complain, Listener,
+ SuggestedPredefines))
+ Result = ConfigurationMismatch;
+ break;
+ }
+ }
+}
+
ASTReader::ASTReadResult
ASTReader::ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
const ModuleFile *ImportedBy,
unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
+ ASTReadResult Result = Success;
if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Error("malformed block record in AST file");
return Failure;
}
- // Should we allow the configuration of the module file to differ from the
- // configuration of the current translation unit in a compatible way?
- //
- // FIXME: Allow this for files explicitly specified with -include-pch too.
- bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule;
-
// Read all of the records and blocks in the control block.
RecordData Record;
unsigned NumInputs = 0;
@@ -2061,8 +2177,9 @@ ASTReader::ReadControlBlock(ModuleFile &F,
PP.getHeaderSearchInfo().getHeaderSearchOpts();
// All user input files reside at the index range [0, NumUserInputs), and
- // system input files reside at [NumUserInputs, NumInputs).
- if (!DisableValidation) {
+ // system input files reside at [NumUserInputs, NumInputs). For explicitly
+ // loaded module files, ignore missing inputs.
+ if (!DisableValidation && F.Kind != MK_ExplicitModule) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
// If we are reading a module, we will create a verification timestamp,
@@ -2084,7 +2201,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
}
if (Listener)
- Listener->visitModuleFile(F.FileName);
+ Listener->visitModuleFile(F.FileName, F.Kind);
if (Listener && Listener->needsInputFileVisitation()) {
unsigned N = Listener->needsSystemInputFileVisitation() ? NumInputs
@@ -2092,11 +2209,12 @@ ASTReader::ReadControlBlock(ModuleFile &F,
for (unsigned I = 0; I < N; ++I) {
bool IsSystem = I >= NumUserInputs;
InputFileInfo FI = readInputFileInfo(F, I+1);
- Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden);
+ Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden,
+ F.Kind == MK_ExplicitModule);
}
}
- return Success;
+ return Result;
}
case llvm::BitstreamEntry::SubBlock:
@@ -2110,6 +2228,41 @@ ASTReader::ReadControlBlock(ModuleFile &F,
return Failure;
}
continue;
+
+ case OPTIONS_BLOCK_ID:
+ // If we're reading the first module for this group, check its options
+ // are compatible with ours. For modules it imports, no further checking
+ // is required, because we checked them when we built it.
+ if (Listener && !ImportedBy) {
+ // Should we allow the configuration of the module file to differ from
+ // the configuration of the current translation unit in a compatible
+ // way?
+ //
+ // FIXME: Allow this for files explicitly specified with -include-pch.
+ bool AllowCompatibleConfigurationMismatch =
+ F.Kind == MK_ExplicitModule;
+
+ Result = ReadOptionsBlock(Stream, ClientLoadCapabilities,
+ AllowCompatibleConfigurationMismatch,
+ *Listener, SuggestedPredefines);
+ if (Result == Failure) {
+ Error("malformed block record in AST file");
+ return Result;
+ }
+
+ if (DisableValidation ||
+ (AllowConfigurationMismatch && Result == ConfigurationMismatch))
+ Result = Success;
+
+ // If we've diagnosed a problem, we're done.
+ if (Result != Success &&
+ isDiagnosedResult(Result, ClientLoadCapabilities))
+ return Result;
+ } else if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
default:
if (Stream.SkipBlock()) {
@@ -2136,7 +2289,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
return VersionMismatch;
}
- bool hasErrors = Record[5];
+ bool hasErrors = Record[6];
if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) {
Diag(diag::err_pch_with_compiler_errors);
return HadErrors;
@@ -2147,6 +2300,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
if (F.RelocatablePCH)
F.BaseDirectory = isysroot.empty() ? "/" : isysroot;
+ F.HasTimestamps = Record[5];
+
const std::string &CurBranch = getClangFullRepositoryVersion();
StringRef ASTBranch = Blob;
if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
@@ -2178,10 +2333,23 @@ ASTReader::ReadControlBlock(ModuleFile &F,
ASTFileSignature StoredSignature = Record[Idx++];
auto ImportedFile = ReadPath(F, Record, Idx);
+ // If our client can't cope with us being out of date, we can't cope with
+ // our dependency being missing.
+ unsigned Capabilities = ClientLoadCapabilities;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Capabilities &= ~ARR_Missing;
+
// Load the AST file.
- switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
- StoredSize, StoredModTime, StoredSignature,
- ClientLoadCapabilities)) {
+ auto Result = ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F,
+ Loaded, StoredSize, StoredModTime,
+ StoredSignature, Capabilities);
+
+ // If we diagnosed a problem, produce a backtrace.
+ if (isDiagnosedResult(Result, Capabilities))
+ Diag(diag::note_module_file_imported_by)
+ << F.FileName << !F.ModuleName.empty() << F.ModuleName;
+
+ switch (Result) {
case Failure: return Failure;
// If we have to ignore the dependency, we'll have to ignore this too.
case Missing:
@@ -2195,71 +2363,6 @@ ASTReader::ReadControlBlock(ModuleFile &F,
break;
}
- case KNOWN_MODULE_FILES:
- break;
-
- case LANGUAGE_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
- // FIXME: The &F == *ModuleMgr.begin() check is wrong for modules.
- if (Listener && &F == *ModuleMgr.begin() &&
- ParseLanguageOptions(Record, Complain, *Listener,
- AllowCompatibleConfigurationMismatch) &&
- !DisableValidation && !AllowConfigurationMismatch)
- return ConfigurationMismatch;
- break;
- }
-
- case TARGET_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- ParseTargetOptions(Record, Complain, *Listener,
- AllowCompatibleConfigurationMismatch) &&
- !DisableValidation && !AllowConfigurationMismatch)
- return ConfigurationMismatch;
- break;
- }
-
- case DIAGNOSTIC_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_OutOfDate)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- !AllowCompatibleConfigurationMismatch &&
- ParseDiagnosticOptions(Record, Complain, *Listener) &&
- !DisableValidation)
- return OutOfDate;
- break;
- }
-
- case FILE_SYSTEM_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- !AllowCompatibleConfigurationMismatch &&
- ParseFileSystemOptions(Record, Complain, *Listener) &&
- !DisableValidation && !AllowConfigurationMismatch)
- return ConfigurationMismatch;
- break;
- }
-
- case HEADER_SEARCH_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- !AllowCompatibleConfigurationMismatch &&
- ParseHeaderSearchOptions(Record, Complain, *Listener) &&
- !DisableValidation && !AllowConfigurationMismatch)
- return ConfigurationMismatch;
- break;
- }
-
- case PREPROCESSOR_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
- if (Listener && &F == *ModuleMgr.begin() &&
- !AllowCompatibleConfigurationMismatch &&
- ParsePreprocessorOptions(Record, Complain, *Listener,
- SuggestedPredefines) &&
- !DisableValidation && !AllowConfigurationMismatch)
- return ConfigurationMismatch;
- break;
- }
-
case ORIGINAL_FILE:
F.OriginalSourceFileID = FileID::get(Record[0]);
F.ActualOriginalSourceFileName = Blob;
@@ -2499,10 +2602,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
case TU_UPDATE_LEXICAL: {
DeclContext *TU = Context.getTranslationUnitDecl();
- DeclContextInfo &Info = F.DeclContextInfos[TU];
- Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(Blob.data());
- Info.NumLexicalDecls
- = static_cast<unsigned int>(Blob.size() / sizeof(KindDeclIDPair));
+ LexicalContents Contents(
+ reinterpret_cast<const llvm::support::unaligned_uint32_t *>(
+ Blob.data()),
+ static_cast<unsigned int>(Blob.size() / 4));
+ TULexicalDecls.push_back(std::make_pair(&F, Contents));
TU->setHasExternalLexicalStorage(true);
break;
}
@@ -2510,20 +2614,12 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
case UPDATE_VISIBLE: {
unsigned Idx = 0;
serialization::DeclID ID = ReadDeclID(F, Record, Idx);
- ASTDeclContextNameLookupTable *Table =
- ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)Blob.data() + Record[Idx++],
- (const unsigned char *)Blob.data() + sizeof(uint32_t),
- (const unsigned char *)Blob.data(),
- ASTDeclContextNameLookupTrait(*this, F));
- if (Decl *D = GetExistingDecl(ID)) {
- auto *DC = cast<DeclContext>(D);
- DC->getPrimaryContext()->setHasExternalVisibleStorage(true);
- auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData;
- delete LookupTable;
- LookupTable = Table;
- } else
- PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F));
+ auto *Data = (const unsigned char*)Blob.data();
+ PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data});
+ // If we've already loaded the decl, perform the updates when we finish
+ // loading this block.
+ if (Decl *D = GetExistingDecl(ID))
+ PendingUpdateRecords.push_back(std::make_pair(ID, D));
break;
}
@@ -2568,6 +2664,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
+ case INTERESTING_IDENTIFIERS:
+ F.PreloadIdentifierOffsets.assign(Record.begin(), Record.end());
+ break;
+
case EAGERLY_DESERIALIZED_DECLS:
// FIXME: Skip reading this record if our ASTConsumer doesn't care
// about "interesting" decls (for instance, if we're building a module).
@@ -2696,6 +2796,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
SLocSpaceSize);
+ if (!F.SLocEntryBaseID) {
+ Error("ran out of source locations");
+ break;
+ }
// Make our entry in the range map. BaseID is negative and growing, so
// we invert it. Because we invert it, though, we need the other end of
// the range.
@@ -2744,7 +2848,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
RemapBuilder DeclRemap(F.DeclRemap);
RemapBuilder TypeRemap(F.TypeRemap);
- while(Data < DataEnd) {
+ while (Data < DataEnd) {
using namespace llvm::support;
uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data);
StringRef Name = StringRef((const char*)Data, Len);
@@ -3060,22 +3164,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
- case LOCAL_REDECLARATIONS: {
- F.RedeclarationChains.swap(Record);
- break;
- }
-
- case LOCAL_REDECLARATIONS_MAP: {
- if (F.LocalNumRedeclarationsInMap != 0) {
- Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
- return Failure;
- }
-
- F.LocalNumRedeclarationsInMap = Record[0];
- F.RedeclarationsMap = (const LocalRedeclarationsInfo *)Blob.data();
- break;
- }
-
case MACRO_OFFSET: {
if (F.LocalNumMacros != 0) {
Error("duplicate MACRO_OFFSET record in AST file");
@@ -3150,11 +3238,18 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr;
if (!ModMap) {
assert(ImportedBy && "top-level import should be verified");
- if ((ClientLoadCapabilities & ARR_Missing) == 0)
- Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName
- << ImportedBy->FileName
- << F.ModuleMapPath;
- return Missing;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) {
+ if (auto *ASTFE = M ? M->getASTFile() : nullptr)
+ // This module was defined by an imported (explicit) module.
+ Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName
+ << ASTFE->getName();
+ else
+ // This module was built with a different module map.
+ Diag(diag::err_imported_module_not_found)
+ << F.ModuleName << F.FileName << ImportedBy->FileName
+ << F.ModuleMapPath;
+ }
+ return OutOfDate;
}
assert(M->Name == F.ModuleName && "found module with different name");
@@ -3342,6 +3437,36 @@ static void updateModuleTimestamp(ModuleFile &MF) {
OS << "Timestamp file\n";
}
+/// \brief Given a cursor at the start of an AST file, scan ahead and drop the
+/// cursor into the start of the given block ID, returning false on success and
+/// true on failure.
+static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) {
+ 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 == BlockID) {
+ if (Cursor.EnterSubBlock(BlockID))
+ return true;
+ // Found it!
+ return false;
+ }
+
+ if (Cursor.SkipBlock())
+ return true;
+ }
+ }
+}
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type,
SourceLocation ImportLoc,
@@ -3399,6 +3524,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities))
return Result;
+ // Read the extension blocks.
+ while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) {
+ if (ASTReadResult Result = ReadExtensionBlock(F))
+ return Result;
+ }
+
// Once read, set the ModuleFile bit base offset and update the size in
// bits of all files we've seen.
F.GlobalBitOffset = TotalModulesSizeInBits;
@@ -3414,6 +3545,32 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// SourceManager.
SourceMgr.getLoadedSLocEntryByID(Index);
}
+
+ // Preload all the pending interesting identifiers by marking them out of
+ // date.
+ for (auto Offset : F.PreloadIdentifierOffsets) {
+ const unsigned char *Data = reinterpret_cast<const unsigned char *>(
+ F.IdentifierTableData + Offset);
+
+ ASTIdentifierLookupTrait Trait(*this, F);
+ auto KeyDataLen = Trait.ReadKeyDataLength(Data);
+ auto Key = Trait.ReadKey(Data, KeyDataLen.first);
+ auto &II = PP.getIdentifierTable().getOwn(Key);
+ II.setOutOfDate(true);
+
+ // Mark this identifier as being from an AST file so that we can track
+ // whether we need to serialize it.
+ if (!II.isFromAST()) {
+ II.setIsFromAST();
+ bool IsModule = PP.getCurrentModule() != nullptr;
+ if (isInterestingIdentifier(*this, II, IsModule))
+ II.setChangedSinceDeserialization();
+ }
+
+ // Associate the ID with the identifier so that the writer can reuse it.
+ auto ID = Trait.ReadIdentifierID(Data + KeyDataLen.first);
+ SetIdentifierInfo(ID, &II);
+ }
}
// Setup the import locations and notify the module manager that we've
@@ -3434,13 +3591,20 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
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.
- for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),
- IdEnd = PP.getIdentifierTable().end();
- Id != IdEnd; ++Id)
- Id->second->setOutOfDate(true);
+ if (!Context.getLangOpts().CPlusPlus ||
+ (Type != MK_ImplicitModule && Type != MK_ExplicitModule)) {
+ // 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.
+ //
+ // For C++ modules, we don't need information on many identifiers (just
+ // those that provide macros or are poisoned), so we mark all of
+ // the interesting ones via PreloadIdentifierOffsets.
+ for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),
+ IdEnd = PP.getIdentifierTable().end();
+ Id != IdEnd; ++Id)
+ Id->second->setOutOfDate(true);
+ }
// Resolve any unresolved module exports.
for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) {
@@ -3485,7 +3649,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
DeserializationListener->ReaderInitialized(this);
ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
- if (!PrimaryModule.OriginalSourceFileID.isInvalid()) {
+ if (PrimaryModule.OriginalSourceFileID.isValid()) {
PrimaryModule.OriginalSourceFileID
= FileID::get(PrimaryModule.SLocEntryBaseID
+ PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
@@ -3536,6 +3700,20 @@ static bool startsWithASTFileMagic(BitstreamCursor &Stream) {
Stream.Read(8) == 'H';
}
+static unsigned moduleKindForDiagnostic(ModuleKind Kind) {
+ switch (Kind) {
+ case MK_PCH:
+ return 0; // PCH
+ case MK_ImplicitModule:
+ case MK_ExplicitModule:
+ return 1; // module
+ case MK_MainFile:
+ case MK_Preamble:
+ return 2; // main source file
+ }
+ llvm_unreachable("unknown module kind");
+}
+
ASTReader::ASTReadResult
ASTReader::ReadASTCore(StringRef FileName,
ModuleKind Type,
@@ -3568,11 +3746,9 @@ ASTReader::ReadASTCore(StringRef FileName,
return Missing;
// Otherwise, return an error.
- {
- std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
- + ErrorStr;
- Error(Msg);
- }
+ Diag(diag::err_module_file_not_found) << moduleKindForDiagnostic(Type)
+ << FileName << ErrorStr.empty()
+ << ErrorStr;
return Failure;
case ModuleManager::OutOfDate:
@@ -3582,11 +3758,9 @@ ASTReader::ReadASTCore(StringRef FileName,
return OutOfDate;
// Otherwise, return an error.
- {
- std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
- + ErrorStr;
- Error(Msg);
- }
+ Diag(diag::err_module_file_out_of_date) << moduleKindForDiagnostic(Type)
+ << FileName << ErrorStr.empty()
+ << ErrorStr;
return Failure;
}
@@ -3607,20 +3781,20 @@ ASTReader::ReadASTCore(StringRef FileName,
// Sniff for the signature.
if (!startsWithASTFileMagic(Stream)) {
- Diag(diag::err_not_a_pch_file) << FileName;
+ Diag(diag::err_module_file_invalid) << moduleKindForDiagnostic(Type)
+ << FileName;
return Failure;
}
// This is used for compatibility with older PCH formats.
bool HaveReadControlBlock = false;
-
while (1) {
llvm::BitstreamEntry Entry = Stream.advance();
switch (Entry.Kind) {
case llvm::BitstreamEntry::Error:
- case llvm::BitstreamEntry::EndBlock:
case llvm::BitstreamEntry::Record:
+ case llvm::BitstreamEntry::EndBlock:
Error("invalid record at top-level of AST file");
return Failure;
@@ -3628,18 +3802,23 @@ ASTReader::ReadASTCore(StringRef FileName,
break;
}
- // We only know the control subblock ID.
switch (Entry.ID) {
- case llvm::bitc::BLOCKINFO_BLOCK_ID:
- if (Stream.ReadBlockInfoBlock()) {
- Error("malformed BlockInfoBlock in AST file");
- return Failure;
- }
- break;
case CONTROL_BLOCK_ID:
HaveReadControlBlock = true;
switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) {
case Success:
+ // Check that we didn't try to load a non-module AST file as a module.
+ //
+ // FIXME: Should we also perform the converse check? Loading a module as
+ // a PCH file sort of works, but it's a bit wonky.
+ if ((Type == MK_ImplicitModule || Type == MK_ExplicitModule) &&
+ F.ModuleName.empty()) {
+ auto Result = (Type == MK_ImplicitModule) ? OutOfDate : Failure;
+ if (Result != OutOfDate ||
+ (ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_module_file_not_module) << FileName;
+ return Result;
+ }
break;
case Failure: return Failure;
@@ -3650,6 +3829,7 @@ ASTReader::ReadASTCore(StringRef FileName,
case HadErrors: return HadErrors;
}
break;
+
case AST_BLOCK_ID:
if (!HaveReadControlBlock) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
@@ -3669,7 +3849,78 @@ ASTReader::ReadASTCore(StringRef FileName,
break;
}
}
-
+
+ return Success;
+}
+
+/// Parse a record and blob containing module file extension metadata.
+static bool parseModuleFileExtensionMetadata(
+ const SmallVectorImpl<uint64_t> &Record,
+ StringRef Blob,
+ ModuleFileExtensionMetadata &Metadata) {
+ if (Record.size() < 4) return true;
+
+ Metadata.MajorVersion = Record[0];
+ Metadata.MinorVersion = Record[1];
+
+ unsigned BlockNameLen = Record[2];
+ unsigned UserInfoLen = Record[3];
+
+ if (BlockNameLen + UserInfoLen > Blob.size()) return true;
+
+ Metadata.BlockName = std::string(Blob.data(), Blob.data() + BlockNameLen);
+ Metadata.UserInfo = std::string(Blob.data() + BlockNameLen,
+ Blob.data() + BlockNameLen + UserInfoLen);
+ return false;
+}
+
+ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) {
+ BitstreamCursor &Stream = F.Stream;
+
+ RecordData Record;
+ while (true) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock:
+ if (Stream.SkipBlock())
+ return Failure;
+
+ continue;
+
+ case llvm::BitstreamEntry::EndBlock:
+ return Success;
+
+ case llvm::BitstreamEntry::Error:
+ return HadErrors;
+
+ case llvm::BitstreamEntry::Record:
+ break;
+ }
+
+ Record.clear();
+ StringRef Blob;
+ unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
+ switch (RecCode) {
+ case EXTENSION_METADATA: {
+ ModuleFileExtensionMetadata Metadata;
+ if (parseModuleFileExtensionMetadata(Record, Blob, Metadata))
+ return Failure;
+
+ // Find a module file extension with this block name.
+ auto Known = ModuleFileExtensions.find(Metadata.BlockName);
+ if (Known == ModuleFileExtensions.end()) break;
+
+ // Form a reader.
+ if (auto Reader = Known->second->createExtensionReader(Metadata, *this,
+ F, Stream)) {
+ F.ExtensionReaders.push_back(std::move(Reader));
+ }
+
+ break;
+ }
+ }
+ }
+
return Success;
}
@@ -3811,36 +4062,6 @@ void ASTReader::finalizeForWriting() {
// Nothing to do for now.
}
-/// \brief Given a cursor at the start of an AST file, scan ahead and drop the
-/// cursor into the start of the given block ID, returning false on success and
-/// true on failure.
-static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) {
- 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 == BlockID) {
- if (Cursor.EnterSubBlock(BlockID))
- return true;
- // Found it!
- return false;
- }
-
- if (Cursor.SkipBlock())
- return true;
- }
- }
-}
-
/// \brief Reads and return the signature record from \p StreamFile's control
/// block, or else returns 0.
static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile){
@@ -3968,6 +4189,7 @@ namespace {
bool ASTReader::readASTFileControlBlock(
StringRef Filename, FileManager &FileMgr,
const PCHContainerReader &PCHContainerRdr,
+ bool FindModuleFileExtensions,
ASTReaderListener &Listener) {
// Open the AST file.
// FIXME: This allows use of the VFS; we do not allow use of the
@@ -3994,36 +4216,55 @@ bool ASTReader::readASTFileControlBlock(
bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation();
bool NeedsImports = Listener.needsImportVisitation();
BitstreamCursor InputFilesCursor;
- if (NeedsInputFiles) {
- InputFilesCursor = Stream;
- if (SkipCursorToBlock(InputFilesCursor, INPUT_FILES_BLOCK_ID))
- return true;
- // Read the abbreviations
- while (true) {
- uint64_t Offset = InputFilesCursor.GetCurrentBitNo();
- unsigned Code = InputFilesCursor.ReadCode();
+ RecordData Record;
+ std::string ModuleDir;
+ bool DoneWithControlBlock = false;
+ while (!DoneWithControlBlock) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: {
+ switch (Entry.ID) {
+ case OPTIONS_BLOCK_ID: {
+ std::string IgnoredSuggestedPredefines;
+ if (ReadOptionsBlock(Stream, ARR_ConfigurationMismatch | ARR_OutOfDate,
+ /*AllowCompatibleConfigurationMismatch*/ false,
+ Listener, IgnoredSuggestedPredefines) != Success)
+ return true;
+ break;
+ }
+
+ case INPUT_FILES_BLOCK_ID:
+ InputFilesCursor = Stream;
+ if (Stream.SkipBlock() ||
+ (NeedsInputFiles &&
+ ReadBlockAbbrevs(InputFilesCursor, INPUT_FILES_BLOCK_ID)))
+ return true;
+ break;
- // We expect all abbrevs to be at the start of the block.
- if (Code != llvm::bitc::DEFINE_ABBREV) {
- InputFilesCursor.JumpToBit(Offset);
+ default:
+ if (Stream.SkipBlock())
+ return true;
break;
}
- InputFilesCursor.ReadAbbrevRecord();
+
+ continue;
}
- }
-
- // Scan for ORIGINAL_FILE inside the control block.
- RecordData Record;
- std::string ModuleDir;
- while (1) {
- llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
- if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
- return false;
-
- if (Entry.Kind != llvm::BitstreamEntry::Record)
+
+ case llvm::BitstreamEntry::EndBlock:
+ DoneWithControlBlock = true;
+ break;
+
+ case llvm::BitstreamEntry::Error:
return true;
-
+
+ case llvm::BitstreamEntry::Record:
+ break;
+ }
+
+ if (DoneWithControlBlock) break;
+
Record.clear();
StringRef Blob;
unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
@@ -4050,41 +4291,6 @@ bool ASTReader::readASTFileControlBlock(
Listener.ReadModuleMapFile(Path);
break;
}
- case LANGUAGE_OPTIONS:
- if (ParseLanguageOptions(Record, false, Listener,
- /*AllowCompatibleConfigurationMismatch*/false))
- return true;
- break;
-
- case TARGET_OPTIONS:
- if (ParseTargetOptions(Record, false, Listener,
- /*AllowCompatibleConfigurationMismatch*/ false))
- 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 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 INPUT_FILE_OFFSETS: {
if (!NeedsInputFiles)
break;
@@ -4112,8 +4318,8 @@ bool ASTReader::readASTFileControlBlock(
bool Overridden = static_cast<bool>(Record[3]);
std::string Filename = Blob;
ResolveImportedPath(Filename, ModuleDir);
- shouldContinue =
- Listener.visitInputFile(Filename, isSystemFile, Overridden);
+ shouldContinue = Listener.visitInputFile(
+ Filename, isSystemFile, Overridden, /*IsExplicitModule*/false);
break;
}
if (!shouldContinue)
@@ -4137,25 +4343,55 @@ bool ASTReader::readASTFileControlBlock(
break;
}
- case KNOWN_MODULE_FILES: {
- // Known-but-not-technically-used module files are treated as imports.
- if (!NeedsImports)
- break;
-
- unsigned Idx = 0, N = Record.size();
- while (Idx < N) {
- std::string Filename = ReadString(Record, Idx);
- ResolveImportedPath(Filename, ModuleDir);
- Listener.visitImport(Filename);
- }
- break;
- }
-
default:
// No other validation to perform.
break;
}
}
+
+ // Look for module file extension blocks, if requested.
+ if (FindModuleFileExtensions) {
+ while (!SkipCursorToBlock(Stream, EXTENSION_BLOCK_ID)) {
+ bool DoneWithExtensionBlock = false;
+ while (!DoneWithExtensionBlock) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock:
+ if (Stream.SkipBlock())
+ return true;
+
+ continue;
+
+ case llvm::BitstreamEntry::EndBlock:
+ DoneWithExtensionBlock = true;
+ continue;
+
+ case llvm::BitstreamEntry::Error:
+ return true;
+
+ case llvm::BitstreamEntry::Record:
+ break;
+ }
+
+ Record.clear();
+ StringRef Blob;
+ unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
+ switch (RecCode) {
+ case EXTENSION_METADATA: {
+ ModuleFileExtensionMetadata Metadata;
+ if (parseModuleFileExtensionMetadata(Record, Blob, Metadata))
+ return true;
+
+ Listener.readModuleFileExtension(Metadata);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
}
bool ASTReader::isAcceptableASTFile(
@@ -4166,6 +4402,7 @@ bool ASTReader::isAcceptableASTFile(
SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts,
ExistingModuleCachePath, FileMgr);
return !readASTFileControlBlock(Filename, FileMgr, PCHContainerRdr,
+ /*FindModuleFileExtensions=*/false,
validator);
}
@@ -4846,22 +5083,19 @@ namespace {
public:
explicit HeaderFileInfoVisitor(const FileEntry *FE)
: FE(FE) { }
-
- static bool visit(ModuleFile &M, void *UserData) {
- HeaderFileInfoVisitor *This
- = static_cast<HeaderFileInfoVisitor *>(UserData);
-
+
+ bool operator()(ModuleFile &M) {
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);
+ HeaderFileInfoLookupTable::iterator Pos = Table->find(FE);
if (Pos == Table->end())
return false;
- This->HFI = *Pos;
+ HFI = *Pos;
return true;
}
@@ -4871,7 +5105,7 @@ namespace {
HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
HeaderFileInfoVisitor Visitor(FE);
- ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
+ ModuleMgr.visit(Visitor);
if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo())
return *HFI;
@@ -5181,9 +5415,9 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
case TYPE_AUTO: {
QualType Deduced = readType(*Loc.F, Record, Idx);
- bool IsDecltypeAuto = Record[Idx++];
+ AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++];
bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
- return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent);
+ return Context.getAutoType(Deduced, Keyword, IsDependent);
}
case TYPE_RECORD: {
@@ -5335,7 +5569,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
unsigned Idx = 0;
ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
- const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
+ const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx);
QualType Canon = readType(*Loc.F, Record, Idx);
if (!Canon.isNull())
Canon = Context.getCanonicalType(Canon);
@@ -5346,7 +5580,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
unsigned Idx = 0;
ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++];
NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx);
- const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx);
+ const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx);
unsigned NumArgs = Record[Idx++];
SmallVector<TemplateArgument, 8> Args;
Args.reserve(NumArgs);
@@ -5692,9 +5926,14 @@ QualType ASTReader::GetType(TypeID ID) {
if (Index < NUM_PREDEF_TYPE_IDS) {
QualType T;
switch ((PredefinedTypeIDs)Index) {
- case PREDEF_TYPE_NULL_ID: return QualType();
- case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
- case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
+ case PREDEF_TYPE_NULL_ID:
+ return QualType();
+ case PREDEF_TYPE_VOID_ID:
+ T = Context.VoidTy;
+ break;
+ case PREDEF_TYPE_BOOL_ID:
+ T = Context.BoolTy;
+ break;
case PREDEF_TYPE_CHAR_U_ID:
case PREDEF_TYPE_CHAR_S_ID:
@@ -5702,59 +5941,163 @@ QualType ASTReader::GetType(TypeID ID) {
T = Context.CharTy;
break;
- case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break;
- case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break;
- case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break;
- case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break;
- case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break;
- case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break;
- case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break;
- case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break;
- case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break;
- case PREDEF_TYPE_INT_ID: T = Context.IntTy; break;
- case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break;
- case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break;
- case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break;
- case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break;
- case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break;
- case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break;
- case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
- case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
- case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break;
- case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break;
- case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
- case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
- case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;
- case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break;
- case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break;
- 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:
- T = Context.getAutoRRefDeductType();
+ case PREDEF_TYPE_UCHAR_ID:
+ T = Context.UnsignedCharTy;
+ break;
+ case PREDEF_TYPE_USHORT_ID:
+ T = Context.UnsignedShortTy;
+ break;
+ case PREDEF_TYPE_UINT_ID:
+ T = Context.UnsignedIntTy;
+ break;
+ case PREDEF_TYPE_ULONG_ID:
+ T = Context.UnsignedLongTy;
+ break;
+ case PREDEF_TYPE_ULONGLONG_ID:
+ T = Context.UnsignedLongLongTy;
+ break;
+ case PREDEF_TYPE_UINT128_ID:
+ T = Context.UnsignedInt128Ty;
+ break;
+ case PREDEF_TYPE_SCHAR_ID:
+ T = Context.SignedCharTy;
+ break;
+ case PREDEF_TYPE_WCHAR_ID:
+ T = Context.WCharTy;
+ break;
+ case PREDEF_TYPE_SHORT_ID:
+ T = Context.ShortTy;
+ break;
+ case PREDEF_TYPE_INT_ID:
+ T = Context.IntTy;
+ break;
+ case PREDEF_TYPE_LONG_ID:
+ T = Context.LongTy;
+ break;
+ case PREDEF_TYPE_LONGLONG_ID:
+ T = Context.LongLongTy;
+ break;
+ case PREDEF_TYPE_INT128_ID:
+ T = Context.Int128Ty;
+ break;
+ case PREDEF_TYPE_HALF_ID:
+ T = Context.HalfTy;
+ break;
+ case PREDEF_TYPE_FLOAT_ID:
+ T = Context.FloatTy;
+ break;
+ case PREDEF_TYPE_DOUBLE_ID:
+ T = Context.DoubleTy;
+ break;
+ case PREDEF_TYPE_LONGDOUBLE_ID:
+ T = Context.LongDoubleTy;
+ break;
+ case PREDEF_TYPE_OVERLOAD_ID:
+ T = Context.OverloadTy;
+ break;
+ case PREDEF_TYPE_BOUND_MEMBER:
+ T = Context.BoundMemberTy;
+ break;
+ case PREDEF_TYPE_PSEUDO_OBJECT:
+ T = Context.PseudoObjectTy;
+ break;
+ case PREDEF_TYPE_DEPENDENT_ID:
+ T = Context.DependentTy;
+ break;
+ case PREDEF_TYPE_UNKNOWN_ANY:
+ T = Context.UnknownAnyTy;
+ break;
+ case PREDEF_TYPE_NULLPTR_ID:
+ T = Context.NullPtrTy;
+ break;
+ case PREDEF_TYPE_CHAR16_ID:
+ T = Context.Char16Ty;
+ break;
+ case PREDEF_TYPE_CHAR32_ID:
+ T = Context.Char32Ty;
+ break;
+ 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_IMAGE2D_DEP_ID:
+ T = Context.OCLImage2dDepthTy;
+ break;
+ case PREDEF_TYPE_IMAGE2D_ARR_DEP_ID:
+ T = Context.OCLImage2dArrayDepthTy;
+ break;
+ case PREDEF_TYPE_IMAGE2D_MSAA_ID:
+ T = Context.OCLImage2dMSAATy;
+ break;
+ case PREDEF_TYPE_IMAGE2D_ARR_MSAA_ID:
+ T = Context.OCLImage2dArrayMSAATy;
+ break;
+ case PREDEF_TYPE_IMAGE2D_MSAA_DEP_ID:
+ T = Context.OCLImage2dMSAADepthTy;
+ break;
+ case PREDEF_TYPE_IMAGE2D_ARR_MSAA_DEPTH_ID:
+ T = Context.OCLImage2dArrayMSAADepthTy;
+ 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_CLK_EVENT_ID:
+ T = Context.OCLClkEventTy;
+ break;
+ case PREDEF_TYPE_QUEUE_ID:
+ T = Context.OCLQueueTy;
+ break;
+ case PREDEF_TYPE_NDRANGE_ID:
+ T = Context.OCLNDRangeTy;
+ break;
+ case PREDEF_TYPE_RESERVE_ID_ID:
+ T = Context.OCLReserveIDTy;
+ break;
+ case PREDEF_TYPE_AUTO_DEDUCT:
+ T = Context.getAutoDeductType();
break;
- case PREDEF_TYPE_ARC_UNBRIDGED_CAST:
- T = Context.ARCUnbridgedCastTy;
+ case PREDEF_TYPE_AUTO_RREF_DEDUCT:
+ T = Context.getAutoRRefDeductType();
break;
- case PREDEF_TYPE_VA_LIST_TAG:
- T = Context.getVaListTagType();
+ case PREDEF_TYPE_ARC_UNBRIDGED_CAST:
+ T = Context.ARCUnbridgedCastTy;
break;
case PREDEF_TYPE_BUILTIN_FN:
T = Context.BuiltinFnTy;
break;
+
+ case PREDEF_TYPE_OMP_ARRAY_SECTION:
+ T = Context.OMPArraySectionTy;
+ break;
}
assert(!T.isNull() && "Unknown predefined type");
@@ -5889,17 +6232,25 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC) ||
isa<CXXRecordDecl>(DC) || isa<EnumDecl>(DC)) {
if (DeclarationName Name = cast<NamedDecl>(D)->getDeclName()) {
- auto *II = Name.getAsIdentifierInfo();
- if (isa<TranslationUnitDecl>(DC) && II) {
+ if (!getContext().getLangOpts().CPlusPlus &&
+ isa<TranslationUnitDecl>(DC)) {
// Outside of C++, we don't have a lookup table for the TU, so update
- // the identifier instead. In C++, either way should work fine.
+ // the identifier instead. (For C++ modules, we don't store decls
+ // in the serialized identifier table, so we do the lookup in the TU.)
+ auto *II = Name.getAsIdentifierInfo();
+ assert(II && "non-identifier name in C?");
if (II->isOutOfDate())
updateOutOfDateIdentifier(*II);
} else
DC->lookup(Name);
} else if (needsAnonymousDeclarationNumber(cast<NamedDecl>(D))) {
- // FIXME: It'd be nice to do something a bit more targeted here.
- D->getDeclContext()->decls_begin();
+ // Find all declarations of this kind from the relevant context.
+ for (auto *DCDecl : cast<Decl>(D->getLexicalDeclContext())->redecls()) {
+ auto *DC = cast<DeclContext>(DCDecl);
+ SmallVector<Decl*, 8> Decls;
+ FindExternalLexicalDecls(
+ DC, [&](Decl::Kind K) { return K == D->getKind(); }, Decls);
+ }
}
}
@@ -6061,8 +6412,17 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
case PREDEF_DECL_BUILTIN_VA_LIST_ID:
return Context.getBuiltinVaListDecl();
+ case PREDEF_DECL_VA_LIST_TAG:
+ return Context.getVaListTagDecl();
+
+ case PREDEF_DECL_BUILTIN_MS_VA_LIST_ID:
+ return Context.getBuiltinMSVaListDecl();
+
case PREDEF_DECL_EXTERN_C_CONTEXT_ID:
return Context.getExternCContextDecl();
+
+ case PREDEF_DECL_MAKE_INTEGER_SEQ_ID:
+ return Context.getMakeIntegerSeqDecl();
}
llvm_unreachable("PredefinedDeclIDs unknown enum value");
}
@@ -6155,71 +6515,47 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
return ReadStmtFromStream(*Loc.F);
}
-namespace {
- class FindExternalLexicalDeclsVisitor {
- ASTReader &Reader;
- const DeclContext *DC;
- bool (*isKindWeWant)(Decl::Kind);
-
- SmallVectorImpl<Decl*> &Decls;
- bool PredefsVisited[NUM_PREDEF_DECL_IDS];
-
- public:
- FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC,
- bool (*isKindWeWant)(Decl::Kind),
- SmallVectorImpl<Decl*> &Decls)
- : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls)
- {
- for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I)
- PredefsVisited[I] = false;
- }
+void ASTReader::FindExternalLexicalDecls(
+ const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
+ SmallVectorImpl<Decl *> &Decls) {
+ bool PredefsVisited[NUM_PREDEF_DECL_IDS] = {};
- static bool visitPostorder(ModuleFile &M, void *UserData) {
- FindExternalLexicalDeclsVisitor *This
- = static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
+ auto Visit = [&] (ModuleFile *M, LexicalContents LexicalDecls) {
+ assert(LexicalDecls.size() % 2 == 0 && "expected an even number of entries");
+ for (int I = 0, N = LexicalDecls.size(); I != N; I += 2) {
+ auto K = (Decl::Kind)+LexicalDecls[I];
+ if (!IsKindWeWant(K))
+ continue;
- ModuleFile::DeclContextInfosMap::iterator Info
- = M.DeclContextInfos.find(This->DC);
- if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls)
- return false;
+ auto ID = (serialization::DeclID)+LexicalDecls[I + 1];
- // Load all of the declaration IDs
- for (const KindDeclIDPair *ID = Info->second.LexicalDecls,
- *IDE = ID + Info->second.NumLexicalDecls;
- ID != IDE; ++ID) {
- if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first))
+ // Don't add predefined declarations to the lexical context more
+ // than once.
+ if (ID < NUM_PREDEF_DECL_IDS) {
+ if (PredefsVisited[ID])
continue;
- // Don't add predefined declarations to the lexical context more
- // than once.
- if (ID->second < NUM_PREDEF_DECL_IDS) {
- if (This->PredefsVisited[ID->second])
- continue;
-
- This->PredefsVisited[ID->second] = true;
- }
-
- if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) {
- if (!This->DC->isDeclInLexicalTraversal(D))
- This->Decls.push_back(D);
- }
+ PredefsVisited[ID] = true;
}
- return false;
+ if (Decl *D = GetLocalDecl(*M, ID)) {
+ assert(D->getKind() == K && "wrong kind for lexical decl");
+ if (!DC->isDeclInLexicalTraversal(D))
+ Decls.push_back(D);
+ }
}
};
-}
-ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
- bool (*isKindWeWant)(Decl::Kind),
- SmallVectorImpl<Decl*> &Decls) {
- // There might be lexical decls in multiple modules, for the TU at
- // least. Walk all of the modules in the order they were loaded.
- FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
- ModuleMgr.visitDepthFirst(
- nullptr, &FindExternalLexicalDeclsVisitor::visitPostorder, &Visitor);
+ if (isa<TranslationUnitDecl>(DC)) {
+ for (auto Lexical : TULexicalDecls)
+ Visit(Lexical.first, Lexical.second);
+ } else {
+ auto I = LexicalDecls.find(DC);
+ if (I != LexicalDecls.end())
+ Visit(I->second.first, I->second.second);
+ }
+
++NumLexicalDeclContextsRead;
- return ELR_Success;
}
namespace {
@@ -6298,168 +6634,26 @@ void ASTReader::FindFileRegionDecls(FileID File,
Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
}
-/// \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 nullptr;
-}
-
-namespace {
- /// \brief ModuleFile visitor used to perform name lookup into a
- /// declaration context.
- class DeclContextNameLookupVisitor {
- ASTReader &Reader;
- ArrayRef<const DeclContext *> Contexts;
- DeclarationName Name;
- ASTDeclContextNameLookupTrait::DeclNameKey NameKey;
- unsigned NameHash;
- SmallVectorImpl<NamedDecl *> &Decls;
- llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet;
-
- public:
- DeclContextNameLookupVisitor(ASTReader &Reader,
- DeclarationName Name,
- SmallVectorImpl<NamedDecl *> &Decls,
- llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet)
- : Reader(Reader), Name(Name),
- NameKey(ASTDeclContextNameLookupTrait::GetInternalKey(Name)),
- NameHash(ASTDeclContextNameLookupTrait::ComputeHash(NameKey)),
- Decls(Decls), DeclSet(DeclSet) {}
-
- void visitContexts(ArrayRef<const DeclContext*> Contexts) {
- if (Contexts.empty())
- return;
- this->Contexts = Contexts;
-
- // 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(Contexts[0], Reader))) {
- visit(*Definitive, this);
- } else {
- Reader.getModuleManager().visit(&visit, this);
- }
- }
-
- private:
- static bool visit(ModuleFile &M, void *UserData) {
- DeclContextNameLookupVisitor *This
- = static_cast<DeclContextNameLookupVisitor *>(UserData);
-
- // Check whether we have any visible declaration information for
- // this context in this module.
- ModuleFile::DeclContextInfosMap::iterator Info;
- bool FoundInfo = false;
- for (auto *DC : This->Contexts) {
- Info = M.DeclContextInfos.find(DC);
- if (Info != M.DeclContextInfos.end() &&
- Info->second.NameLookupTableData) {
- FoundInfo = true;
- break;
- }
- }
-
- if (!FoundInfo)
- return false;
-
- // Look for this name within this module.
- ASTDeclContextNameLookupTable *LookupTable =
- Info->second.NameLookupTableData;
- ASTDeclContextNameLookupTable::iterator Pos
- = LookupTable->find_hashed(This->NameKey, This->NameHash);
- if (Pos == LookupTable->end())
- return false;
-
- bool FoundAnything = false;
- ASTDeclContextNameLookupTrait::data_type Data = *Pos;
- for (; Data.first != Data.second; ++Data.first) {
- NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
- if (!ND)
- continue;
-
- if (ND->getDeclName() != This->Name) {
- // A name might be null because the decl's redeclarable part is
- // currently read before reading its name. The lookup is triggered by
- // building that decl (likely indirectly), and so it is later in the
- // sense of "already existing" and can be ignored here.
- // FIXME: This should not happen; deserializing declarations should
- // not perform lookups since that can lead to deserialization cycles.
- continue;
- }
-
- // Record this declaration.
- FoundAnything = true;
- if (This->DeclSet.insert(ND).second)
- This->Decls.push_back(ND);
- }
-
- return FoundAnything;
- }
- };
-}
-
bool
ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
- assert(DC->hasExternalVisibleStorage() &&
+ assert(DC->hasExternalVisibleStorage() && DC == DC->getPrimaryContext() &&
"DeclContext has no visible decls in storage");
if (!Name)
return false;
+ auto It = Lookups.find(DC);
+ if (It == Lookups.end())
+ return false;
+
Deserializing LookupResults(this);
+ // Load the list of declarations.
SmallVector<NamedDecl *, 64> Decls;
- llvm::SmallPtrSet<NamedDecl*, 64> DeclSet;
-
- // Compute the declaration contexts we need to look into. Multiple such
- // declaration contexts occur when two declaration contexts from disjoint
- // modules get merged, e.g., when two namespaces with the same name are
- // independently defined in separate modules.
- SmallVector<const DeclContext *, 2> Contexts;
- Contexts.push_back(DC);
-
- if (DC->isNamespace()) {
- auto Key = KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
- if (Key != KeyDecls.end()) {
- for (unsigned I = 0, N = Key->second.size(); I != N; ++I)
- Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I])));
- }
- }
-
- DeclContextNameLookupVisitor Visitor(*this, Name, Decls, DeclSet);
- Visitor.visitContexts(Contexts);
-
- // If this might be an implicit special member function, then also search
- // all merged definitions of the surrounding class. We need to search them
- // individually, because finding an entity in one of them doesn't imply that
- // we can't find a different entity in another one.
- if (isa<CXXRecordDecl>(DC)) {
- auto Merged = MergedLookups.find(DC);
- if (Merged != MergedLookups.end()) {
- for (unsigned I = 0; I != Merged->second.size(); ++I) {
- const DeclContext *Context = Merged->second[I];
- Visitor.visitContexts(Context);
- // We might have just added some more merged lookups. If so, our
- // iterator is now invalid, so grab a fresh one before continuing.
- Merged = MergedLookups.find(DC);
- }
- }
+ for (DeclID ID : It->second.Table.find(Name)) {
+ NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
+ if (ND->getDeclName() == Name)
+ Decls.push_back(ND);
}
++NumVisibleDeclContextsRead;
@@ -6467,92 +6661,21 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
return !Decls.empty();
}
-namespace {
- /// \brief ModuleFile visitor used to retrieve all visible names in a
- /// declaration context.
- class DeclContextAllNamesVisitor {
- ASTReader &Reader;
- SmallVectorImpl<const DeclContext *> &Contexts;
- DeclsMap &Decls;
- llvm::SmallPtrSet<NamedDecl *, 256> DeclSet;
- bool VisitAll;
-
- public:
- DeclContextAllNamesVisitor(ASTReader &Reader,
- SmallVectorImpl<const DeclContext *> &Contexts,
- DeclsMap &Decls, bool VisitAll)
- : Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { }
-
- static bool visit(ModuleFile &M, void *UserData) {
- DeclContextAllNamesVisitor *This
- = static_cast<DeclContextAllNamesVisitor *>(UserData);
-
- // Check whether we have any visible declaration information for
- // this context in this module.
- ModuleFile::DeclContextInfosMap::iterator Info;
- bool FoundInfo = false;
- for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
- Info = M.DeclContextInfos.find(This->Contexts[I]);
- if (Info != M.DeclContextInfos.end() &&
- Info->second.NameLookupTableData) {
- FoundInfo = true;
- break;
- }
- }
-
- if (!FoundInfo)
- return false;
-
- ASTDeclContextNameLookupTable *LookupTable =
- Info->second.NameLookupTableData;
- bool FoundAnything = false;
- for (ASTDeclContextNameLookupTable::data_iterator
- 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,
- *Data.first);
- if (!ND)
- continue;
-
- // Record this declaration.
- FoundAnything = true;
- if (This->DeclSet.insert(ND).second)
- This->Decls[ND->getDeclName()].push_back(ND);
- }
- }
-
- return FoundAnything && !This->VisitAll;
- }
- };
-}
-
void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
if (!DC->hasExternalVisibleStorage())
return;
- DeclsMap Decls;
- // Compute the declaration contexts we need to look into. Multiple such
- // declaration contexts occur when two declaration contexts from disjoint
- // modules get merged, e.g., when two namespaces with the same name are
- // independently defined in separate modules.
- SmallVector<const DeclContext *, 2> Contexts;
- Contexts.push_back(DC);
+ auto It = Lookups.find(DC);
+ assert(It != Lookups.end() &&
+ "have external visible storage but no lookup tables");
- if (DC->isNamespace()) {
- KeyDeclsMap::iterator Key =
- KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
- if (Key != KeyDecls.end()) {
- for (unsigned I = 0, N = Key->second.size(); I != N; ++I)
- Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I])));
- }
+ DeclsMap Decls;
+
+ for (DeclID ID : It->second.Table.findAll()) {
+ NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
+ Decls[ND->getDeclName()].push_back(ND);
}
- DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls,
- /*VisitAll=*/DC->isFileContext());
- ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor);
++NumVisibleDeclContextsRead;
for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
@@ -6561,6 +6684,12 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
}
+const serialization::reader::DeclContextLookupTable *
+ASTReader::getLoadedLookupTables(DeclContext *Primary) const {
+ auto I = Lookups.find(Primary);
+ return I == Lookups.end() ? nullptr : &I->second;
+}
+
/// \brief Under non-PCH compilation the consumer receives the objc methods
/// before receiving the implementation, and codegen depends on this.
/// We simulate this by deserializing and passing to consumer the methods of the
@@ -6824,24 +6953,36 @@ void ASTReader::UpdateSema() {
SemaObj->ActOnPragmaOptimize(/* IsOn = */ false, OptimizeOffPragmaLocation);
}
-IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
+IdentifierInfo *ASTReader::get(StringRef Name) {
// Note that we are loading an identifier.
Deserializing AnIdentifier(this);
- 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 = nullptr;
- if (!loadGlobalIndex()) {
- if (GlobalIndex->lookupIdentifier(Name, Hits)) {
- HitsPtr = &Hits;
- }
- }
IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0,
NumIdentifierLookups,
NumIdentifierLookupHits);
- ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
+
+ // We don't need to do identifier table lookups in C++ modules (we preload
+ // all interesting declarations, and don't need to use the scope for name
+ // lookups). Perform the lookup in PCH files, though, since we don't build
+ // a complete initial identifier table if we're carrying on from a PCH.
+ if (Context.getLangOpts().CPlusPlus) {
+ for (auto F : ModuleMgr.pch_modules())
+ if (Visitor(*F))
+ break;
+ } else {
+ // 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 = nullptr;
+ if (!loadGlobalIndex()) {
+ if (GlobalIndex->lookupIdentifier(Name, Hits)) {
+ HitsPtr = &Hits;
+ }
+ }
+
+ ModuleMgr.visit(Visitor, HitsPtr);
+ }
+
IdentifierInfo *II = Visitor.getIdentifierInfo();
markIdentifierUpToDate(II);
return II;
@@ -6928,41 +7069,37 @@ namespace clang { namespace serialization {
InstanceBits(0), FactoryBits(0), InstanceHasMoreThanOneDecl(false),
FactoryHasMoreThanOneDecl(false) {}
- static bool visit(ModuleFile &M, void *UserData) {
- ReadMethodPoolVisitor *This
- = static_cast<ReadMethodPoolVisitor *>(UserData);
-
+ bool operator()(ModuleFile &M) {
if (!M.SelectorLookupTable)
return false;
// If we've already searched this module file, skip it now.
- if (M.Generation <= This->PriorGeneration)
+ if (M.Generation <= PriorGeneration)
return true;
- ++This->Reader.NumMethodPoolTableLookups;
+ ++Reader.NumMethodPoolTableLookups;
ASTSelectorLookupTable *PoolTable
= (ASTSelectorLookupTable*)M.SelectorLookupTable;
- ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
+ ASTSelectorLookupTable::iterator Pos = PoolTable->find(Sel);
if (Pos == PoolTable->end())
return false;
- ++This->Reader.NumMethodPoolTableHits;
- ++This->Reader.NumSelectorsRead;
+ ++Reader.NumMethodPoolTableHits;
+ ++Reader.NumSelectorsRead;
// FIXME: Not quite happy with the statistics here. We probably should
// disable this tracking when called via LoadSelector.
// Also, should entries without methods count as misses?
- ++This->Reader.NumMethodPoolEntriesRead;
+ ++Reader.NumMethodPoolEntriesRead;
ASTSelectorLookupTrait::data_type Data = *Pos;
- if (This->Reader.DeserializationListener)
- This->Reader.DeserializationListener->SelectorRead(Data.ID,
- This->Sel);
-
- This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end());
- This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
- This->InstanceBits = Data.InstanceBits;
- This->FactoryBits = Data.FactoryBits;
- This->InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl;
- This->FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl;
+ if (Reader.DeserializationListener)
+ Reader.DeserializationListener->SelectorRead(Data.ID, Sel);
+
+ InstanceMethods.append(Data.Instance.begin(), Data.Instance.end());
+ FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
+ InstanceBits = Data.InstanceBits;
+ FactoryBits = Data.FactoryBits;
+ InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl;
+ FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl;
return true;
}
@@ -7002,8 +7139,8 @@ void ASTReader::ReadMethodPool(Selector Sel) {
// Search for methods defined with this selector.
++NumMethodPoolLookups;
ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration);
- ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
-
+ ModuleMgr.visit(Visitor);
+
if (Visitor.getInstanceMethods().empty() &&
Visitor.getFactoryMethods().empty())
return;
@@ -7384,33 +7521,47 @@ Module *ASTReader::getModule(unsigned ID) {
return getSubmodule(ID);
}
-ExternalASTSource::ASTSourceDescriptor
-ASTReader::getSourceDescriptor(const Module &M) {
- StringRef Dir, Filename;
- if (M.Directory)
- Dir = M.Directory->getName();
- if (auto *File = M.getASTFile())
- Filename = File->getName();
- return ASTReader::ASTSourceDescriptor{
- M.getFullModuleName(), Dir, Filename,
- M.Signature
- };
+ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) {
+ if (ID & 1) {
+ // It's a module, look it up by submodule ID.
+ auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(F, ID >> 1));
+ return I == GlobalSubmoduleMap.end() ? nullptr : I->second;
+ } else {
+ // It's a prefix (preamble, PCH, ...). Look it up by index.
+ unsigned IndexFromEnd = ID >> 1;
+ assert(IndexFromEnd && "got reference to unknown module file");
+ return getModuleManager().pch_modules().end()[-IndexFromEnd];
+ }
+}
+
+unsigned ASTReader::getModuleFileID(ModuleFile *F) {
+ if (!F)
+ return 1;
+
+ // For a file representing a module, use the submodule ID of the top-level
+ // module as the file ID. For any other kind of file, the number of such
+ // files loaded beforehand will be the same on reload.
+ // FIXME: Is this true even if we have an explicit module file and a PCH?
+ if (F->isModule())
+ return ((F->BaseSubmoduleID + NUM_PREDEF_SUBMODULE_IDS) << 1) | 1;
+
+ auto PCHModules = getModuleManager().pch_modules();
+ auto I = std::find(PCHModules.begin(), PCHModules.end(), F);
+ assert(I != PCHModules.end() && "emitting reference to unknown file");
+ return (I - PCHModules.end()) << 1;
}
llvm::Optional<ExternalASTSource::ASTSourceDescriptor>
ASTReader::getSourceDescriptor(unsigned ID) {
if (const Module *M = getSubmodule(ID))
- return getSourceDescriptor(*M);
+ return ExternalASTSource::ASTSourceDescriptor(*M);
// If there is only a single PCH, return it instead.
// Chained PCH are not suported.
if (ModuleMgr.size() == 1) {
ModuleFile &MF = ModuleMgr.getPrimaryModule();
- return ASTReader::ASTSourceDescriptor{
- MF.OriginalSourceFileName, MF.OriginalDir,
- MF.FileName,
- MF.Signature
- };
+ return ASTReader::ASTSourceDescriptor(
+ MF.OriginalSourceFileName, MF.OriginalDir, MF.FileName, MF.Signature);
}
return None;
}
@@ -7619,9 +7770,19 @@ ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
llvm_unreachable("Unhandled template name kind!");
}
-TemplateArgument
-ASTReader::ReadTemplateArgument(ModuleFile &F,
- const RecordData &Record, unsigned &Idx) {
+TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F,
+ const RecordData &Record,
+ unsigned &Idx,
+ bool Canonicalize) {
+ if (Canonicalize) {
+ // The caller wants a canonical template argument. Sometimes the AST only
+ // wants template arguments in canonical form (particularly as the template
+ // argument lists of template specializations) so ensure we preserve that
+ // canonical form across serialization.
+ TemplateArgument Arg = ReadTemplateArgument(F, Record, Idx, false);
+ return Context.getCanonicalTemplateArgument(Arg);
+ }
+
TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++];
switch (Kind) {
case TemplateArgument::Null:
@@ -7655,7 +7816,7 @@ ASTReader::ReadTemplateArgument(ModuleFile &F,
TemplateArgument *Args = new (Context) TemplateArgument[NumArgs];
for (unsigned I = 0; I != NumArgs; ++I)
Args[I] = ReadTemplateArgument(F, Record, Idx);
- return TemplateArgument(Args, NumArgs);
+ return TemplateArgument(llvm::makeArrayRef(Args, NumArgs));
}
}
@@ -7677,7 +7838,7 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F,
TemplateParameterList* TemplateParams =
TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- Params.data(), Params.size(), RAngleLoc);
+ Params, RAngleLoc);
return TemplateParams;
}
@@ -7685,11 +7846,11 @@ void
ASTReader::
ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
ModuleFile &F, const RecordData &Record,
- unsigned &Idx) {
+ unsigned &Idx, bool Canonicalize) {
unsigned NumTemplateArgs = Record[Idx++];
TemplArgs.reserve(NumTemplateArgs);
while (NumTemplateArgs--)
- TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx));
+ TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx, Canonicalize));
}
/// \brief Read a UnresolvedSet structure.
@@ -8070,14 +8231,6 @@ void ASTReader::ReadComments() {
}
}
-void ASTReader::getInputFiles(ModuleFile &F,
- SmallVectorImpl<serialization::InputFile> &Files) {
- for (unsigned I = 0, E = F.InputFilesLoaded.size(); I != E; ++I) {
- unsigned ID = I+1;
- Files.push_back(getInputFile(F, ID));
- }
-}
-
std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
// If we know the owning module, use it.
if (Module *M = D->getImportedOwningModule())
@@ -8119,11 +8272,8 @@ void ASTReader::finishPendingActions() {
PendingIncompleteDeclChains.clear();
// Load pending declaration chains.
- for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
- PendingDeclChainsKnown.erase(PendingDeclChains[I]);
- loadPendingDeclChain(PendingDeclChains[I]);
- }
- assert(PendingDeclChainsKnown.empty());
+ for (unsigned I = 0; I != PendingDeclChains.size(); ++I)
+ loadPendingDeclChain(PendingDeclChains[I].first, PendingDeclChains[I].second);
PendingDeclChains.clear();
// Make the most recent of the top-level declarations visible.
@@ -8232,9 +8382,8 @@ void ASTReader::finishPendingActions() {
// Load the bodies of any functions or methods we've encountered. We do
// this now (delayed) so that we can be sure that the declaration chains
- // have been fully wired up.
- // FIXME: There seems to be no point in delaying this, it does not depend
- // on the redecl chains having been wired up.
+ // have been fully wired up (hasBody relies on this).
+ // FIXME: We shouldn't require complete redeclaration chains here.
for (PendingBodiesMap::iterator PB = PendingBodies.begin(),
PBEnd = PendingBodies.end();
PB != PBEnd; ++PB) {
@@ -8310,21 +8459,26 @@ void ASTReader::diagnoseOdrViolations() {
if (Found)
continue;
+ // Quick check failed, time to do the slow thing. Note, we can't just
+ // look up the name of D in CanonDef here, because the member that is
+ // in CanonDef might not be found by name lookup (it might have been
+ // replaced by a more recent declaration in the lookup table), and we
+ // can't necessarily find it in the redeclaration chain because it might
+ // be merely mergeable, not redeclarable.
llvm::SmallVector<const NamedDecl*, 4> Candidates;
- DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName());
- for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
- !Found && I != E; ++I) {
- for (auto RI : (*I)->redecls()) {
- if (RI->getLexicalDeclContext() == CanonDef) {
- // This declaration is present in the canonical definition. If it's
- // in the same redecl chain, it's the one we're looking for.
- if (RI->getCanonicalDecl() == DCanon)
- Found = true;
- else
- Candidates.push_back(cast<NamedDecl>(RI));
- break;
- }
+ for (auto *CanonMember : CanonDef->decls()) {
+ if (CanonMember->getCanonicalDecl() == DCanon) {
+ // This can happen if the declaration is merely mergeable and not
+ // actually redeclarable (we looked for redeclarations earlier).
+ //
+ // FIXME: We should be able to detect this more efficiently, without
+ // pulling in all of the members of CanonDef.
+ Found = true;
+ break;
}
+ if (auto *ND = dyn_cast<NamedDecl>(CanonMember))
+ if (ND->getDeclName() == D->getDeclName())
+ Candidates.push_back(ND);
}
if (!Found) {
@@ -8428,16 +8582,19 @@ void ASTReader::FinishedDeserializing() {
PendingExceptionSpecUpdates.clear();
for (auto Update : Updates) {
auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
- SemaObj->UpdateExceptionSpec(Update.second,
- FPT->getExtProtoInfo().ExceptionSpec);
+ auto ESI = FPT->getExtProtoInfo().ExceptionSpec;
+ if (auto *Listener = Context.getASTMutationListener())
+ Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second));
+ for (auto *Redecl : Update.second->redecls())
+ Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
}
}
- diagnoseOdrViolations();
-
if (ReadTimer)
ReadTimer->stopTimer();
+ diagnoseOdrViolations();
+
// We are not in recursive loading, so it's safe to pass the "interesting"
// decls to the consumer.
if (Consumer)
@@ -8450,7 +8607,7 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
// Remove any fake results before adding any real ones.
auto It = PendingFakeLookupResults.find(II);
if (It != PendingFakeLookupResults.end()) {
- for (auto *ND : PendingFakeLookupResults[II])
+ for (auto *ND : It->second)
SemaObj->IdResolver.RemoveDecl(ND);
// FIXME: this works around module+PCH performance issue.
// Rather than erase the result from the map, which is O(n), just clear
@@ -8471,13 +8628,15 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
}
}
-ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
- const PCHContainerReader &PCHContainerRdr,
- StringRef isysroot, bool DisableValidation,
- bool AllowASTWithCompilerErrors,
- bool AllowConfigurationMismatch, bool ValidateSystemInputs,
- bool UseGlobalIndex,
- std::unique_ptr<llvm::Timer> ReadTimer)
+ASTReader::ASTReader(
+ Preprocessor &PP, ASTContext &Context,
+ const PCHContainerReader &PCHContainerRdr,
+ ArrayRef<IntrusiveRefCntPtr<ModuleFileExtension>> Extensions,
+ StringRef isysroot, bool DisableValidation,
+ bool AllowASTWithCompilerErrors,
+ bool AllowConfigurationMismatch, bool ValidateSystemInputs,
+ bool UseGlobalIndex,
+ std::unique_ptr<llvm::Timer> ReadTimer)
: Listener(new PCHValidator(PP, *this)), DeserializationListener(nullptr),
OwnsDeserializationListener(false), SourceMgr(PP.getSourceManager()),
FileMgr(PP.getFileManager()), PCHContainerRdr(PCHContainerRdr),
@@ -8501,19 +8660,21 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
PassingDeclsToConsumer(false), ReadingKind(Read_None) {
SourceMgr.setExternalSLocEntrySource(this);
+
+ for (const auto &Ext : Extensions) {
+ auto BlockName = Ext->getExtensionMetadata().BlockName;
+ auto Known = ModuleFileExtensions.find(BlockName);
+ if (Known != ModuleFileExtensions.end()) {
+ Diags.Report(diag::warn_duplicate_module_file_extension)
+ << BlockName;
+ continue;
+ }
+
+ ModuleFileExtensions.insert({BlockName, Ext});
+ }
}
ASTReader::~ASTReader() {
if (OwnsDeserializationListener)
delete DeserializationListener;
-
- for (DeclContextVisibleUpdatesPending::iterator
- I = PendingVisibleUpdates.begin(),
- E = PendingVisibleUpdates.end();
- I != E; ++I) {
- for (DeclContextVisibleUpdates::iterator J = I->second.begin(),
- F = I->second.end();
- J != F; ++J)
- delete J->first;
- }
}
OpenPOWER on IntegriCloud