//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/OpenMPKinds.h"
-#include "clang/Serialization/ASTRecordReader.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
-#include "clang/AST/AbstractTypeReader.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/ASTUnresolvedSet.h"
+#include "clang/AST/AbstractTypeReader.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/NestedNameSpecifier.h"
-#include "clang/AST/OpenMPClause.h"
#include "clang/AST/ODRHash.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/RawCommentList.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticError.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Sema/Weak.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/Serialization/ASTRecordReader.h"
#include "clang/Serialization/ContinuousRangeMap.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/InMemoryModuleCache.h"
}
void ASTReader::Error(llvm::Error &&Err) const {
- Error(toString(std::move(Err)));
+ llvm::Error RemainingErr =
+ handleErrors(std::move(Err), [this](const DiagnosticError &E) {
+ auto Diag = E.getDiagnostic().second;
+
+ // Ideally we'd just emit it, but have to handle a possible in-flight
+ // diagnostic. Note that the location is currently ignored as well.
+ auto NumArgs = Diag.getStorage()->NumDiagArgs;
+ assert(NumArgs <= 3 && "Can only have up to 3 arguments");
+ StringRef Arg1, Arg2, Arg3;
+ switch (NumArgs) {
+ case 3:
+ Arg3 = Diag.getStringArg(2);
+ LLVM_FALLTHROUGH;
+ case 2:
+ Arg2 = Diag.getStringArg(1);
+ LLVM_FALLTHROUGH;
+ case 1:
+ Arg1 = Diag.getStringArg(0);
+ }
+ Error(Diag.getDiagID(), Arg1, Arg2, Arg3);
+ });
+ if (RemainingErr)
+ Error(toString(std::move(RemainingErr)));
}
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
/// Read the line table in the source manager block.
-/// \returns true if there was an error.
-bool ASTReader::ParseLineTable(ModuleFile &F,
- const RecordData &Record) {
+void ASTReader::ParseLineTable(ModuleFile &F, const RecordData &Record) {
unsigned Idx = 0;
LineTableInfo &LineTable = SourceMgr.getLineTable();
}
LineTable.AddEntry(FileID::get(FID), Entries);
}
-
- return false;
}
/// Read a source manager block
-bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
+llvm::Error ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
using namespace SrcMgr;
BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
SLocEntryCursor = F.Stream;
// The stream itself is going to skip over the source manager block.
- if (llvm::Error Err = F.Stream.SkipBlock()) {
- Error(std::move(Err));
- return true;
- }
+ if (llvm::Error Err = F.Stream.SkipBlock())
+ return Err;
// Enter the source manager block.
- if (llvm::Error Err =
- SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) {
- Error(std::move(Err));
- return true;
- }
+ if (llvm::Error Err = SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID))
+ return Err;
F.SourceManagerBlockStartOffset = SLocEntryCursor.GetCurrentBitNo();
RecordData Record;
while (true) {
Expected<llvm::BitstreamEntry> MaybeE =
SLocEntryCursor.advanceSkippingSubblocks();
- if (!MaybeE) {
- Error(MaybeE.takeError());
- return true;
- }
+ if (!MaybeE)
+ return MaybeE.takeError();
llvm::BitstreamEntry E = MaybeE.get();
switch (E.Kind) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
- Error("malformed block record in AST file");
- return true;
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "malformed block record in AST file");
case llvm::BitstreamEntry::EndBlock:
- return false;
+ return llvm::Error::success();
case llvm::BitstreamEntry::Record:
// The interesting case.
break;
StringRef Blob;
Expected<unsigned> MaybeRecord =
SLocEntryCursor.readRecord(E.ID, Record, &Blob);
- if (!MaybeRecord) {
- Error(MaybeRecord.takeError());
- return true;
- }
+ if (!MaybeRecord)
+ return MaybeRecord.takeError();
switch (MaybeRecord.get()) {
default: // Default behavior: ignore.
break;
case SM_SLOC_BUFFER_ENTRY:
case SM_SLOC_EXPANSION_ENTRY:
// Once we hit one of the source location entries, we're done.
- return false;
+ return llvm::Error::success();
}
}
}
/// Enter a subblock of the specified BlockID with the specified cursor. Read
/// the abbreviations that are at the top of the block and then leave the cursor
/// pointing into the block.
-bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID,
- uint64_t *StartOfBlockOffset) {
- if (llvm::Error Err = Cursor.EnterSubBlock(BlockID)) {
- // FIXME this drops errors on the floor.
- consumeError(std::move(Err));
- return true;
- }
+llvm::Error ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor,
+ unsigned BlockID,
+ uint64_t *StartOfBlockOffset) {
+ if (llvm::Error Err = Cursor.EnterSubBlock(BlockID))
+ return Err;
if (StartOfBlockOffset)
*StartOfBlockOffset = Cursor.GetCurrentBitNo();
while (true) {
uint64_t Offset = Cursor.GetCurrentBitNo();
Expected<unsigned> MaybeCode = Cursor.ReadCode();
- if (!MaybeCode) {
- // FIXME this drops errors on the floor.
- consumeError(MaybeCode.takeError());
- return true;
- }
+ if (!MaybeCode)
+ return MaybeCode.takeError();
unsigned Code = MaybeCode.get();
// We expect all abbrevs to be at the start of the block.
if (Code != llvm::bitc::DEFINE_ABBREV) {
- if (llvm::Error Err = Cursor.JumpToBit(Offset)) {
- // FIXME this drops errors on the floor.
- consumeError(std::move(Err));
- return true;
- }
- return false;
- }
- if (llvm::Error Err = Cursor.ReadAbbrevRecord()) {
- // FIXME this drops errors on the floor.
- consumeError(std::move(Err));
- return true;
+ if (llvm::Error Err = Cursor.JumpToBit(Offset))
+ return Err;
+ return llvm::Error::success();
}
+ if (llvm::Error Err = Cursor.ReadAbbrevRecord())
+ return Err;
}
}
}
}
-ASTReader::ASTReadResult
-ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
+llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
+ unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
- if (llvm::Error Err = Stream.EnterSubBlock(AST_BLOCK_ID)) {
- Error(std::move(Err));
- return Failure;
- }
+ if (llvm::Error Err = Stream.EnterSubBlock(AST_BLOCK_ID))
+ return Err;
F.ASTBlockStartOffset = Stream.GetCurrentBitNo();
// Read all of the records and blocks for the AST file.
RecordData Record;
while (true) {
Expected<llvm::BitstreamEntry> MaybeEntry = Stream.advance();
- if (!MaybeEntry) {
- Error(MaybeEntry.takeError());
- return Failure;
- }
+ if (!MaybeEntry)
+ return MaybeEntry.takeError();
llvm::BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case llvm::BitstreamEntry::Error:
- Error("error at end of module block in AST file");
- return Failure;
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "error at end of module block in AST file");
case llvm::BitstreamEntry::EndBlock:
// Outside of C++, we do not store a lookup map for the translation unit.
// Instead, mark it as needing a lookup map to be built if this module
DC->setMustBuildLookupTable();
}
- return Success;
+ return llvm::Error::success();
case llvm::BitstreamEntry::SubBlock:
switch (Entry.ID) {
case DECLTYPES_BLOCK_ID:
// cursor to it, enter the block and read the abbrevs in that block.
// With the main cursor, we just skip over it.
F.DeclsCursor = Stream;
- if (llvm::Error Err = Stream.SkipBlock()) {
- Error(std::move(Err));
- return Failure;
- }
- if (ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID,
- &F.DeclsBlockStartOffset)) {
- Error("malformed block record in AST file");
- return Failure;
- }
+ if (llvm::Error Err = Stream.SkipBlock())
+ return Err;
+ if (llvm::Error Err = ReadBlockAbbrevs(
+ F.DeclsCursor, DECLTYPES_BLOCK_ID, &F.DeclsBlockStartOffset))
+ return Err;
break;
case PREPROCESSOR_BLOCK_ID:
if (!PP.getExternalSource())
PP.setExternalSource(this);
- if (llvm::Error Err = Stream.SkipBlock()) {
- Error(std::move(Err));
- return Failure;
- }
- if (ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
- Error("malformed block record in AST file");
- return Failure;
- }
+ if (llvm::Error Err = Stream.SkipBlock())
+ return Err;
+ if (llvm::Error Err =
+ ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID))
+ return Err;
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
F.PreprocessorDetailCursor = Stream;
if (llvm::Error Err = Stream.SkipBlock()) {
- Error(std::move(Err));
- return Failure;
- }
- if (ReadBlockAbbrevs(F.PreprocessorDetailCursor,
- PREPROCESSOR_DETAIL_BLOCK_ID)) {
- Error("malformed preprocessor detail record in AST file");
- return Failure;
+ return Err;
}
+ if (llvm::Error Err = ReadBlockAbbrevs(F.PreprocessorDetailCursor,
+ PREPROCESSOR_DETAIL_BLOCK_ID))
+ return Err;
F.PreprocessorDetailStartOffset
= F.PreprocessorDetailCursor.GetCurrentBitNo();
break;
case SOURCE_MANAGER_BLOCK_ID:
- if (ReadSourceManagerBlock(F))
- return Failure;
+ if (llvm::Error Err = ReadSourceManagerBlock(F))
+ return Err;
break;
case SUBMODULE_BLOCK_ID:
- if (ASTReadResult Result =
- ReadSubmoduleBlock(F, ClientLoadCapabilities))
- return Result;
+ if (llvm::Error Err = ReadSubmoduleBlock(F, ClientLoadCapabilities))
+ return Err;
break;
case COMMENTS_BLOCK_ID: {
BitstreamCursor C = Stream;
- if (llvm::Error Err = Stream.SkipBlock()) {
- Error(std::move(Err));
- return Failure;
- }
- if (ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
- Error("malformed comments block in AST file");
- return Failure;
- }
+ if (llvm::Error Err = Stream.SkipBlock())
+ return Err;
+ if (llvm::Error Err = ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID))
+ return Err;
CommentsCursors.push_back(std::make_pair(C, &F));
break;
}
default:
- if (llvm::Error Err = Stream.SkipBlock()) {
- Error(std::move(Err));
- return Failure;
- }
+ if (llvm::Error Err = Stream.SkipBlock())
+ return Err;
break;
}
continue;
StringRef Blob;
Expected<unsigned> MaybeRecordType =
Stream.readRecord(Entry.ID, Record, &Blob);
- if (!MaybeRecordType) {
- Error(MaybeRecordType.takeError());
- return Failure;
- }
+ if (!MaybeRecordType)
+ return MaybeRecordType.takeError();
ASTRecordTypes RecordType = (ASTRecordTypes)MaybeRecordType.get();
// If we're not loading an AST context, we don't care about most records.
break;
case TYPE_OFFSET: {
- if (F.LocalNumTypes != 0) {
- Error("duplicate TYPE_OFFSET record in AST file");
- return Failure;
- }
+ if (F.LocalNumTypes != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "duplicate TYPE_OFFSET record in AST file");
F.TypeOffsets = reinterpret_cast<const UnderalignedInt64 *>(Blob.data());
F.LocalNumTypes = Record[0];
unsigned LocalBaseTypeIndex = Record[1];
}
case DECL_OFFSET: {
- if (F.LocalNumDecls != 0) {
- Error("duplicate DECL_OFFSET record in AST file");
- return Failure;
- }
+ if (F.LocalNumDecls != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "duplicate DECL_OFFSET record in AST file");
F.DeclOffsets = (const DeclOffset *)Blob.data();
F.LocalNumDecls = Record[0];
unsigned LocalBaseDeclID = Record[1];
break;
case IDENTIFIER_OFFSET: {
- if (F.LocalNumIdentifiers != 0) {
- Error("duplicate IDENTIFIER_OFFSET record in AST file");
- return Failure;
- }
+ if (F.LocalNumIdentifiers != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "duplicate IDENTIFIER_OFFSET record in AST file");
F.IdentifierOffsets = (const uint32_t *)Blob.data();
F.LocalNumIdentifiers = Record[0];
unsigned LocalBaseIdentifierID = Record[1];
break;
}
- if (SpecialTypes.size() != Record.size()) {
- Error("invalid special-types record");
- return Failure;
- }
+ if (SpecialTypes.size() != Record.size())
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid special-types record");
for (unsigned I = 0, N = Record.size(); I != N; ++I) {
serialization::TypeID ID = getGlobalTypeID(F, Record[I]);
break;
case WEAK_UNDECLARED_IDENTIFIERS:
- if (Record.size() % 4 != 0) {
- Error("invalid weak identifiers record");
- return Failure;
- }
+ if (Record.size() % 4 != 0)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid weak identifiers record");
// FIXME: Ignore weak undeclared identifiers from non-original PCH
// files. This isn't the way to do it :)
std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
SLocSpaceSize);
- if (!F.SLocEntryBaseID) {
- Error("ran out of source locations");
- break;
- }
+ if (!F.SLocEntryBaseID)
+ return llvm::createStringError(std::errc::invalid_argument,
+ "ran out of source locations");
// 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.
break;
case SOURCE_MANAGER_LINE_TABLE:
- if (ParseLineTable(F, Record)) {
- Error("malformed SOURCE_MANAGER_LINE_TABLE in AST file");
- return Failure;
- }
+ ParseLineTable(F, Record);
break;
case SOURCE_LOCATION_PRELOADS: {
// Need to transform from the local view (1-based IDs) to the global view,
// which is based off F.SLocEntryBaseID.
- if (!F.PreloadSLocEntries.empty()) {
- Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
- return Failure;
- }
+ if (!F.PreloadSLocEntries.empty())
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "Multiple SOURCE_LOCATION_PRELOADS records in AST file");
F.PreloadSLocEntries.swap(Record);
break;
break;
case VTABLE_USES:
- if (Record.size() % 3 != 0) {
- Error("Invalid VTABLE_USES record");
- return Failure;
- }
+ if (Record.size() % 3 != 0)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "Invalid VTABLE_USES record");
// Later tables overwrite earlier ones.
// FIXME: Modules will have some trouble with this. This is clearly not
break;
case PENDING_IMPLICIT_INSTANTIATIONS:
- if (PendingInstantiations.size() % 2 != 0) {
- Error("Invalid existing PendingInstantiations");
- return Failure;
- }
+ if (PendingInstantiations.size() % 2 != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "Invalid existing PendingInstantiations");
- if (Record.size() % 2 != 0) {
- Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
- return Failure;
- }
+ if (Record.size() % 2 != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++]));
break;
case SEMA_DECL_REFS:
- if (Record.size() != 3) {
- Error("Invalid SEMA_DECL_REFS block");
- return Failure;
- }
+ if (Record.size() != 3)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "Invalid SEMA_DECL_REFS block");
for (unsigned I = 0, N = Record.size(); I != N; ++I)
SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
break;
}
case DECL_UPDATE_OFFSETS:
- if (Record.size() % 2 != 0) {
- Error("invalid DECL_UPDATE_OFFSETS block in AST file");
- return Failure;
- }
+ if (Record.size() % 2 != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "invalid DECL_UPDATE_OFFSETS block in AST file");
for (unsigned I = 0, N = Record.size(); I != N; I += 2) {
GlobalDeclID ID = getGlobalDeclID(F, Record[I]);
DeclUpdateOffsets[ID].push_back(std::make_pair(&F, Record[I + 1]));
break;
case OBJC_CATEGORIES_MAP:
- if (F.LocalNumObjCCategoriesInMap != 0) {
- Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
- return Failure;
- }
+ if (F.LocalNumObjCCategoriesInMap != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "duplicate OBJC_CATEGORIES_MAP record in AST file");
F.LocalNumObjCCategoriesInMap = Record[0];
F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data();
break;
case UNDEFINED_BUT_USED:
- if (UndefinedButUsed.size() % 2 != 0) {
- Error("Invalid existing UndefinedButUsed");
- return Failure;
- }
+ if (UndefinedButUsed.size() % 2 != 0)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "Invalid existing UndefinedButUsed");
- if (Record.size() % 2 != 0) {
- Error("invalid undefined-but-used record");
- return Failure;
- }
+ if (Record.size() % 2 != 0)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid undefined-but-used record");
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++]));
UndefinedButUsed.push_back(
break;
case MACRO_OFFSET: {
- if (F.LocalNumMacros != 0) {
- Error("duplicate MACRO_OFFSET record in AST file");
- return Failure;
- }
+ if (F.LocalNumMacros != 0)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "duplicate MACRO_OFFSET record in AST file");
F.MacroOffsets = (const uint32_t *)Blob.data();
F.LocalNumMacros = Record[0];
unsigned LocalBaseMacroID = Record[1];
break;
case OPTIMIZE_PRAGMA_OPTIONS:
- if (Record.size() != 1) {
- Error("invalid pragma optimize record");
- return Failure;
- }
+ if (Record.size() != 1)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid pragma optimize record");
OptimizeOffPragmaLocation = ReadSourceLocation(F, Record[0]);
break;
case MSSTRUCT_PRAGMA_OPTIONS:
- if (Record.size() != 1) {
- Error("invalid pragma ms_struct record");
- return Failure;
- }
+ if (Record.size() != 1)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid pragma ms_struct record");
PragmaMSStructState = Record[0];
break;
case POINTERS_TO_MEMBERS_PRAGMA_OPTIONS:
- if (Record.size() != 2) {
- Error("invalid pragma ms_struct record");
- return Failure;
- }
+ if (Record.size() != 2)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "invalid pragma pointers to members record");
PragmaMSPointersToMembersState = Record[0];
PointersToMembersPragmaLocation = ReadSourceLocation(F, Record[1]);
break;
break;
case CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH:
- if (Record.size() != 1) {
- Error("invalid cuda pragma options record");
- return Failure;
- }
+ if (Record.size() != 1)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid cuda pragma options record");
ForceCUDAHostDeviceDepth = Record[0];
break;
case ALIGN_PACK_PRAGMA_OPTIONS: {
- if (Record.size() < 3) {
- Error("invalid pragma pack record");
- return Failure;
- }
+ if (Record.size() < 3)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid pragma pack record");
PragmaAlignPackCurrentValue = ReadAlignPackInfo(Record[0]);
PragmaAlignPackCurrentLocation = ReadSourceLocation(F, Record[1]);
unsigned NumStackEntries = Record[2];
}
case FLOAT_CONTROL_PRAGMA_OPTIONS: {
- if (Record.size() < 3) {
- Error("invalid pragma pack record");
- return Failure;
- }
+ if (Record.size() < 3)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "invalid pragma float control record");
FpPragmaCurrentValue = FPOptionsOverride::getFromOpaqueInt(Record[0]);
FpPragmaCurrentLocation = ReadSourceLocation(F, Record[1]);
unsigned NumStackEntries = Record[2];
return ReadResult;
}
- // Here comes stuff that we only do once the entire chain is loaded.
+ // Here comes stuff that we only do once the entire chain is loaded. Do *not*
+ // remove modules from this point. Various fields are updated during reading
+ // the AST block and removing the modules would result in dangling pointers.
+ // They are generally only incidentally dereferenced, ie. a binary search
+ // runs over `GlobalSLocEntryMap`, which could cause an invalid module to
+ // be dereferenced but it wouldn't actually be used.
- // Load the AST blocks of all of the modules that we loaded. We can still
+ // Load the AST blocks of all of the modules that we loaded. We can still
// hit errors parsing the ASTs at this point.
for (ImportedModule &M : Loaded) {
ModuleFile &F = *M.Mod;
// Read the AST block.
- if (ReadASTBlock(F, ClientLoadCapabilities))
+ if (llvm::Error Err = ReadASTBlock(F, ClientLoadCapabilities)) {
+ Error(std::move(Err));
return Failure;
+ }
// The AST block should always have a definition for the main module.
if (F.isModule() && !F.DidReadTopLevelSubmodule) {
// Read the extension blocks.
while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) {
- if (ReadExtensionBlock(F))
+ if (llvm::Error Err = ReadExtensionBlock(F)) {
+ Error(std::move(Err));
return Failure;
+ }
}
// Once read, set the ModuleFile bit base offset and update the size in
return false;
}
-ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) {
+llvm::Error ASTReader::ReadExtensionBlock(ModuleFile &F) {
BitstreamCursor &Stream = F.Stream;
RecordData Record;
while (true) {
Expected<llvm::BitstreamEntry> MaybeEntry = Stream.advance();
- if (!MaybeEntry) {
- Error(MaybeEntry.takeError());
- return Failure;
- }
+ if (!MaybeEntry)
+ return MaybeEntry.takeError();
llvm::BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case llvm::BitstreamEntry::SubBlock:
- if (llvm::Error Err = Stream.SkipBlock()) {
- Error(std::move(Err));
- return Failure;
- }
+ if (llvm::Error Err = Stream.SkipBlock())
+ return Err;
continue;
-
case llvm::BitstreamEntry::EndBlock:
- return Success;
-
+ return llvm::Error::success();
case llvm::BitstreamEntry::Error:
- return HadErrors;
-
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "malformed block record in AST file");
case llvm::BitstreamEntry::Record:
break;
}
StringRef Blob;
Expected<unsigned> MaybeRecCode =
Stream.readRecord(Entry.ID, Record, &Blob);
- if (!MaybeRecCode) {
- Error(MaybeRecCode.takeError());
- return Failure;
- }
+ if (!MaybeRecCode)
+ return MaybeRecCode.takeError();
switch (MaybeRecCode.get()) {
case EXTENSION_METADATA: {
ModuleFileExtensionMetadata Metadata;
- if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) {
- Error("malformed EXTENSION_METADATA in AST file");
- return Failure;
- }
+ if (parseModuleFileExtensionMetadata(Record, Blob, Metadata))
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "malformed EXTENSION_METADATA in AST file");
// Find a module file extension with this block name.
auto Known = ModuleFileExtensions.find(Metadata.BlockName);
}
}
- return Success;
+ return llvm::Error::success();
}
void ASTReader::InitializeContext() {
/*ValidateDiagnosticOptions=*/true);
}
-ASTReader::ASTReadResult
-ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
+llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
+ unsigned ClientLoadCapabilities) {
// Enter the submodule block.
- if (llvm::Error Err = F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
- Error(std::move(Err));
- return Failure;
- }
+ if (llvm::Error Err = F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID))
+ return Err;
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
bool First = true;
while (true) {
Expected<llvm::BitstreamEntry> MaybeEntry =
F.Stream.advanceSkippingSubblocks();
- if (!MaybeEntry) {
- Error(MaybeEntry.takeError());
- return Failure;
- }
+ if (!MaybeEntry)
+ return MaybeEntry.takeError();
llvm::BitstreamEntry Entry = MaybeEntry.get();
switch (Entry.Kind) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
- Error("malformed block record in AST file");
- return Failure;
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "malformed block record in AST file");
case llvm::BitstreamEntry::EndBlock:
- return Success;
+ return llvm::Error::success();
case llvm::BitstreamEntry::Record:
// The interesting case.
break;
StringRef Blob;
Record.clear();
Expected<unsigned> MaybeKind = F.Stream.readRecord(Entry.ID, Record, &Blob);
- if (!MaybeKind) {
- Error(MaybeKind.takeError());
- return Failure;
- }
+ if (!MaybeKind)
+ return MaybeKind.takeError();
unsigned Kind = MaybeKind.get();
- if ((Kind == SUBMODULE_METADATA) != First) {
- Error("submodule metadata record should be at beginning of block");
- return Failure;
- }
+ if ((Kind == SUBMODULE_METADATA) != First)
+ return llvm::createStringError(
+ std::errc::illegal_byte_sequence,
+ "submodule metadata record should be at beginning of block");
First = false;
// Submodule information is only valid if we have a current module.
break;
case SUBMODULE_DEFINITION: {
- if (Record.size() < 12) {
- Error("malformed module definition");
- return Failure;
- }
+ if (Record.size() < 12)
+ return llvm::createStringError(std::errc::illegal_byte_sequence,
+ "malformed module definition");
StringRef Name = Blob;
unsigned Idx = 0;
SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
if (GlobalIndex >= SubmodulesLoaded.size() ||
- SubmodulesLoaded[GlobalIndex]) {
- Error("too many submodules");
- return Failure;
- }
+ SubmodulesLoaded[GlobalIndex])
+ return llvm::createStringError(std::errc::invalid_argument,
+ "too many submodules");
if (!ParentModule) {
if (const FileEntry *CurFile = CurrentModule->getASTFile()) {
if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation &
DisableValidationForModuleKind::Module) &&
CurFile != F.File) {
- Error(diag::err_module_file_conflict,
- CurrentModule->getTopLevelModuleName(), CurFile->getName(),
- F.File->getName());
- return Failure;
+ auto ConflictError =
+ PartialDiagnostic(diag::err_module_file_conflict,
+ ContextObj->DiagAllocator)
+ << CurrentModule->getTopLevelModuleName() << CurFile->getName()
+ << F.File->getName();
+ return DiagnosticError::create(CurrentImportLoc, ConflictError);
}
}