|
@@ -160,6 +160,12 @@ bool ChainedASTReaderListener::visitInputFile(StringRef Filename,
|
|
|
return Continue;
|
|
|
}
|
|
|
|
|
|
+void ChainedASTReaderListener::readModuleFileExtension(
|
|
|
+ const ModuleFileExtensionMetadata &Metadata) {
|
|
|
+ First->readModuleFileExtension(Metadata);
|
|
|
+ Second->readModuleFileExtension(Metadata);
|
|
|
+}
|
|
|
+
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
// PCH validator implementation
|
|
|
//===----------------------------------------------------------------------===//
|
|
@@ -3423,6 +3429,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,
|
|
@@ -3480,6 +3516,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;
|
|
@@ -3738,14 +3780,13 @@ ASTReader::ReadASTCore(StringRef FileName,
|
|
|
|
|
|
// 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;
|
|
|
|
|
@@ -3800,6 +3841,79 @@ 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;
|
|
|
}
|
|
|
|
|
|
void ASTReader::InitializeContext() {
|
|
@@ -3940,36 +4054,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){
|
|
@@ -4097,6 +4181,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
|
|
@@ -4126,7 +4211,8 @@ bool ASTReader::readASTFileControlBlock(
|
|
|
|
|
|
RecordData Record;
|
|
|
std::string ModuleDir;
|
|
|
- while (1) {
|
|
|
+ bool DoneWithControlBlock = false;
|
|
|
+ while (!DoneWithControlBlock) {
|
|
|
llvm::BitstreamEntry Entry = Stream.advance();
|
|
|
|
|
|
switch (Entry.Kind) {
|
|
@@ -4159,7 +4245,8 @@ bool ASTReader::readASTFileControlBlock(
|
|
|
}
|
|
|
|
|
|
case llvm::BitstreamEntry::EndBlock:
|
|
|
- return false;
|
|
|
+ DoneWithControlBlock = true;
|
|
|
+ break;
|
|
|
|
|
|
case llvm::BitstreamEntry::Error:
|
|
|
return true;
|
|
@@ -4168,6 +4255,8 @@ bool ASTReader::readASTFileControlBlock(
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ if (DoneWithControlBlock) break;
|
|
|
+
|
|
|
Record.clear();
|
|
|
StringRef Blob;
|
|
|
unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
|
|
@@ -4251,6 +4340,50 @@ bool ASTReader::readASTFileControlBlock(
|
|
|
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(
|
|
@@ -4261,6 +4394,7 @@ bool ASTReader::isAcceptableASTFile(
|
|
|
SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts,
|
|
|
ExistingModuleCachePath, FileMgr);
|
|
|
return !readASTFileControlBlock(Filename, FileMgr, PCHContainerRdr,
|
|
|
+ /*FindModuleFileExtensions=*/false,
|
|
|
validator);
|
|
|
}
|
|
|
|
|
@@ -8483,13 +8617,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),
|
|
@@ -8513,6 +8649,18 @@ 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() {
|