Index: clang-tools-extra/clang-doc/BitcodeReader.h =================================================================== --- clang-tools-extra/clang-doc/BitcodeReader.h +++ clang-tools-extra/clang-doc/BitcodeReader.h @@ -19,6 +19,7 @@ #include "BitcodeWriter.h" #include "Representation.h" #include "clang/AST/AST.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Bitcode/BitstreamReader.h" @@ -31,36 +32,37 @@ ClangDocBitcodeReader(llvm::BitstreamCursor &Stream) : Stream(Stream) {} // Main entry point, calls readBlock to read each block in the given stream. - std::vector> readBitcode(); + llvm::Expected>> readBitcode(); private: enum class Cursor { BadBlock = 1, Record, BlockEnd, BlockBegin }; // Top level parsing - bool validateStream(); - bool readVersion(); - bool readBlockInfoBlock(); + llvm::Error validateStream(); + llvm::Error readVersion(); + llvm::Error readBlockInfoBlock(); // Read a block of records into a single Info struct, calls readRecord on each // record found. - template bool readBlock(unsigned ID, T I); + template llvm::Error readBlock(unsigned ID, T I); // Step through a block of records to find the next data field. - template bool readSubBlock(unsigned ID, T I); + template llvm::Error readSubBlock(unsigned ID, T I); // Read record data into the given Info data field, calling the appropriate // parseRecord functions to parse and store the data. - template bool readRecord(unsigned ID, T I); + template llvm::Error readRecord(unsigned ID, T I); // Allocate the relevant type of info and add read data to the object. - template std::unique_ptr createInfo(unsigned ID); + template + llvm::Expected> createInfo(unsigned ID); // Helper function to step through blocks to find and dispatch the next record // or block to be read. Cursor skipUntilRecordOrBlock(unsigned &BlockOrRecordID); // Helper function to set up the approriate type of Info. - std::unique_ptr readBlockToInfo(unsigned ID); + llvm::Expected> readBlockToInfo(unsigned ID); llvm::BitstreamCursor &Stream; Optional BlockInfo; Index: clang-tools-extra/clang-doc/BitcodeReader.cpp =================================================================== --- clang-tools-extra/clang-doc/BitcodeReader.cpp +++ clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -17,49 +17,53 @@ using Record = llvm::SmallVector; -bool decodeRecord(Record R, llvm::SmallVectorImpl &Field, - llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, llvm::SmallVectorImpl &Field, + llvm::StringRef Blob) { Field.assign(Blob.begin(), Blob.end()); - return true; + return llvm::Error::success(); } -bool decodeRecord(Record R, SymbolID &Field, llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, SymbolID &Field, llvm::StringRef Blob) { if (R[0] != BitCodeConstants::USRHashSize) - return false; + return llvm::make_error("Incorrect USR size.\n", + llvm::inconvertibleErrorCode()); // First position in the record is the length of the following array, so we // copy the following elements to the field. for (int I = 0, E = R[0]; I < E; ++I) Field[I] = R[I + 1]; - return true; + return llvm::Error::success(); } -bool decodeRecord(Record R, bool &Field, llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, bool &Field, llvm::StringRef Blob) { Field = R[0] != 0; - return true; + return llvm::Error::success(); } -bool decodeRecord(Record R, int &Field, llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, int &Field, llvm::StringRef Blob) { if (R[0] > INT_MAX) - return false; + return llvm::make_error("Integer too large to parse.\n", + llvm::inconvertibleErrorCode()); Field = (int)R[0]; - return true; + return llvm::Error::success(); } -bool decodeRecord(Record R, AccessSpecifier &Field, llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, AccessSpecifier &Field, + llvm::StringRef Blob) { switch (R[0]) { case AS_public: case AS_private: case AS_protected: case AS_none: Field = (AccessSpecifier)R[0]; - return true; + return llvm::Error::success(); default: - return false; + return llvm::make_error( + "Invalid value for AccessSpecifier.\n", llvm::inconvertibleErrorCode()); } } -bool decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) { switch (R[0]) { case TTK_Struct: case TTK_Interface: @@ -67,21 +71,23 @@ case TTK_Class: case TTK_Enum: Field = (TagTypeKind)R[0]; - return true; + return llvm::Error::success(); default: - return false; + return llvm::make_error( + "Invalid value for TagTypeKind.\n", llvm::inconvertibleErrorCode()); } } -bool decodeRecord(Record R, llvm::Optional &Field, - llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, llvm::Optional &Field, + llvm::StringRef Blob) { if (R[0] > INT_MAX) - return false; + return llvm::make_error("Integer too large to parse.\n", + llvm::inconvertibleErrorCode()); Field.emplace((int)R[0], Blob); - return true; + return llvm::Error::success(); } -bool decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) { switch (auto IT = static_cast(R[0])) { case InfoType::IT_namespace: case InfoType::IT_record: @@ -89,12 +95,13 @@ case InfoType::IT_default: case InfoType::IT_enum: Field = IT; - return true; + return llvm::Error::success(); } - return false; + return llvm::make_error("Invalid value for InfoType.\n", + llvm::inconvertibleErrorCode()); } -bool decodeRecord(Record R, FieldId &Field, llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, FieldId &Field, llvm::StringRef Blob) { switch (auto F = static_cast(R[0])) { case FieldId::F_namespace: case FieldId::F_parent: @@ -102,45 +109,51 @@ case FieldId::F_type: case FieldId::F_default: Field = F; - return true; + return llvm::Error::success(); } - return false; + return llvm::make_error("Invalid value for FieldId.\n", + llvm::inconvertibleErrorCode()); } -bool decodeRecord(Record R, llvm::SmallVectorImpl> &Field, - llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, + llvm::SmallVectorImpl> &Field, + llvm::StringRef Blob) { Field.push_back(Blob); - return true; + return llvm::Error::success(); } -bool decodeRecord(Record R, llvm::SmallVectorImpl &Field, - llvm::StringRef Blob) { +llvm::Error decodeRecord(Record R, llvm::SmallVectorImpl &Field, + llvm::StringRef Blob) { if (R[0] > INT_MAX) - return false; + return llvm::make_error("Integer too large to parse.\n", + llvm::inconvertibleErrorCode()); Field.emplace_back((int)R[0], Blob); - return true; + return llvm::Error::success(); } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, - const unsigned VersionNo) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + const unsigned VersionNo) { if (ID == VERSION && R[0] == VersionNo) - return true; - return false; + return llvm::Error::success(); + return llvm::make_error( + "Mismatched bitcode version number.\n", llvm::inconvertibleErrorCode()); } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, - NamespaceInfo *I) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + NamespaceInfo *I) { switch (ID) { case NAMESPACE_USR: return decodeRecord(R, I->USR, Blob); case NAMESPACE_NAME: return decodeRecord(R, I->Name, Blob); default: - return false; + return llvm::make_error( + "Invalid field for NamespaceInfo.\n", llvm::inconvertibleErrorCode()); } } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, RecordInfo *I) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + RecordInfo *I) { switch (ID) { case RECORD_USR: return decodeRecord(R, I->USR, Blob); @@ -153,11 +166,13 @@ case RECORD_TAG_TYPE: return decodeRecord(R, I->TagType, Blob); default: - return false; + return llvm::make_error( + "Invalid field for RecordInfo.\n", llvm::inconvertibleErrorCode()); } } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, EnumInfo *I) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + EnumInfo *I) { switch (ID) { case ENUM_USR: return decodeRecord(R, I->USR, Blob); @@ -172,11 +187,13 @@ case ENUM_SCOPED: return decodeRecord(R, I->Scoped, Blob); default: - return false; + return llvm::make_error("Invalid field for EnumInfo.\n", + llvm::inconvertibleErrorCode()); } } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, FunctionInfo *I) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + FunctionInfo *I) { switch (ID) { case FUNCTION_USR: return decodeRecord(R, I->USR, Blob); @@ -191,37 +208,42 @@ case FUNCTION_IS_METHOD: return decodeRecord(R, I->IsMethod, Blob); default: - return false; + return llvm::make_error( + "Invalid field for FunctionInfo.\n", llvm::inconvertibleErrorCode()); } } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, TypeInfo *I) { - return true; +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + TypeInfo *I) { + return llvm::Error::success(); } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, - FieldTypeInfo *I) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + FieldTypeInfo *I) { switch (ID) { case FIELD_TYPE_NAME: return decodeRecord(R, I->Name, Blob); default: - return false; + return llvm::make_error("Invalid field for TypeInfo.\n", + llvm::inconvertibleErrorCode()); } } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, - MemberTypeInfo *I) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + MemberTypeInfo *I) { switch (ID) { case MEMBER_TYPE_NAME: return decodeRecord(R, I->Name, Blob); case MEMBER_TYPE_ACCESS: return decodeRecord(R, I->Access, Blob); default: - return false; + return llvm::make_error( + "Invalid field for MemberTypeInfo.\n", llvm::inconvertibleErrorCode()); } } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, CommentInfo *I) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + CommentInfo *I) { switch (ID) { case COMMENT_KIND: return decodeRecord(R, I->Kind, Blob); @@ -246,12 +268,13 @@ case COMMENT_EXPLICIT: return decodeRecord(R, I->Explicit, Blob); default: - return false; + return llvm::make_error( + "Invalid field for CommentInfo.\n", llvm::inconvertibleErrorCode()); } } -bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, Reference *I, - FieldId &F) { +llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob, + Reference *I, FieldId &F) { switch (ID) { case REFERENCE_USR: return decodeRecord(R, I->USR, Blob); @@ -262,162 +285,183 @@ case REFERENCE_FIELD: return decodeRecord(R, F, Blob); default: - return false; + return llvm::make_error("Invalid field for Reference.\n", + llvm::inconvertibleErrorCode()); } } -template CommentInfo *getCommentInfo(T I) { - llvm::errs() << "Cannot have comment subblock.\n"; - exit(1); +template llvm::Expected getCommentInfo(T I) { + return llvm::make_error( + "Invalid type cannot contain CommentInfo.\n", + llvm::inconvertibleErrorCode()); } -template <> CommentInfo *getCommentInfo(FunctionInfo *I) { +template <> llvm::Expected getCommentInfo(FunctionInfo *I) { I->Description.emplace_back(); return &I->Description.back(); } -template <> CommentInfo *getCommentInfo(NamespaceInfo *I) { +template <> llvm::Expected getCommentInfo(NamespaceInfo *I) { I->Description.emplace_back(); return &I->Description.back(); } -template <> CommentInfo *getCommentInfo(RecordInfo *I) { +template <> llvm::Expected getCommentInfo(RecordInfo *I) { I->Description.emplace_back(); return &I->Description.back(); } -template <> CommentInfo *getCommentInfo(EnumInfo *I) { +template <> llvm::Expected getCommentInfo(EnumInfo *I) { I->Description.emplace_back(); return &I->Description.back(); } -template <> CommentInfo *getCommentInfo(CommentInfo *I) { +template <> llvm::Expected getCommentInfo(CommentInfo *I) { I->Children.emplace_back(llvm::make_unique()); return I->Children.back().get(); } -template <> CommentInfo *getCommentInfo(std::unique_ptr &I) { +template <> +llvm::Expected getCommentInfo(std::unique_ptr &I) { return getCommentInfo(I.get()); } template -void addTypeInfo(T I, TTypeInfo &&TI) { - llvm::errs() << "Invalid type for info.\n"; - exit(1); +llvm::Error addTypeInfo(T I, TTypeInfo &&TI) { + return llvm::make_error( + "Invalid type cannot contain TypeInfo.\n", + llvm::inconvertibleErrorCode()); } -template <> void addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) { +template <> llvm::Error addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) { I->Members.emplace_back(std::move(T)); + return llvm::Error::success(); } -template <> void addTypeInfo(FunctionInfo *I, TypeInfo &&T) { +template <> llvm::Error addTypeInfo(FunctionInfo *I, TypeInfo &&T) { I->ReturnType = std::move(T); + return llvm::Error::success(); } -template <> void addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) { +template <> llvm::Error addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) { I->Params.emplace_back(std::move(T)); + return llvm::Error::success(); } -template void addReference(T I, Reference &&R, FieldId F) { - llvm::errs() << "Invalid field type for info.\n"; - exit(1); +template llvm::Error addReference(T I, Reference &&R, FieldId F) { + return llvm::make_error( + "Invalid type cannot contain Reference\n", + llvm::inconvertibleErrorCode()); } -template <> void addReference(TypeInfo *I, Reference &&R, FieldId F) { +template <> llvm::Error addReference(TypeInfo *I, Reference &&R, FieldId F) { switch (F) { case FieldId::F_type: I->Type = std::move(R); - break; + return llvm::Error::success(); default: - llvm::errs() << "Invalid field type for info.\n"; - exit(1); + return llvm::make_error( + "Invalid type cannot contain Reference.\n", + llvm::inconvertibleErrorCode()); } } -template <> void addReference(FieldTypeInfo *I, Reference &&R, FieldId F) { +template <> +llvm::Error addReference(FieldTypeInfo *I, Reference &&R, FieldId F) { switch (F) { case FieldId::F_type: I->Type = std::move(R); - break; + return llvm::Error::success(); default: - llvm::errs() << "Invalid field type for info.\n"; - exit(1); + return llvm::make_error( + "Invalid type cannot contain Reference.\n", + llvm::inconvertibleErrorCode()); } } -template <> void addReference(MemberTypeInfo *I, Reference &&R, FieldId F) { +template <> +llvm::Error addReference(MemberTypeInfo *I, Reference &&R, FieldId F) { switch (F) { case FieldId::F_type: I->Type = std::move(R); - break; + return llvm::Error::success(); default: - llvm::errs() << "Invalid field type for info.\n"; - exit(1); + return llvm::make_error( + "Invalid type cannot contain Reference.\n", + llvm::inconvertibleErrorCode()); } } -template <> void addReference(EnumInfo *I, Reference &&R, FieldId F) { +template <> llvm::Error addReference(EnumInfo *I, Reference &&R, FieldId F) { switch (F) { case FieldId::F_namespace: I->Namespace.emplace_back(std::move(R)); - break; + return llvm::Error::success(); default: - llvm::errs() << "Invalid field type for info.\n"; - exit(1); + return llvm::make_error( + "Invalid type cannot contain Reference.\n", + llvm::inconvertibleErrorCode()); } } -template <> void addReference(NamespaceInfo *I, Reference &&R, FieldId F) { +template <> +llvm::Error addReference(NamespaceInfo *I, Reference &&R, FieldId F) { switch (F) { case FieldId::F_namespace: I->Namespace.emplace_back(std::move(R)); - break; + return llvm::Error::success(); default: - llvm::errs() << "Invalid field type for info.\n"; - exit(1); + return llvm::make_error( + "Invalid type cannot contain Reference.\n", + llvm::inconvertibleErrorCode()); } } -template <> void addReference(FunctionInfo *I, Reference &&R, FieldId F) { +template <> +llvm::Error addReference(FunctionInfo *I, Reference &&R, FieldId F) { switch (F) { case FieldId::F_namespace: I->Namespace.emplace_back(std::move(R)); - break; + return llvm::Error::success(); case FieldId::F_parent: I->Parent = std::move(R); - break; + return llvm::Error::success(); default: - llvm::errs() << "Invalid field type for info.\n"; - exit(1); + return llvm::make_error( + "Invalid type cannot contain Reference.\n", + llvm::inconvertibleErrorCode()); } } -template <> void addReference(RecordInfo *I, Reference &&R, FieldId F) { +template <> llvm::Error addReference(RecordInfo *I, Reference &&R, FieldId F) { switch (F) { case FieldId::F_namespace: I->Namespace.emplace_back(std::move(R)); - break; + return llvm::Error::success(); case FieldId::F_parent: I->Parents.emplace_back(std::move(R)); - break; + return llvm::Error::success(); case FieldId::F_vparent: I->VirtualParents.emplace_back(std::move(R)); - break; + return llvm::Error::success(); default: - llvm::errs() << "Invalid field type for info.\n"; - exit(1); + return llvm::make_error( + "Invalid type cannot contain Reference.\n", + llvm::inconvertibleErrorCode()); } } // Read records from bitcode into a given info. -template bool ClangDocBitcodeReader::readRecord(unsigned ID, T I) { +template +llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) { Record R; llvm::StringRef Blob; unsigned RecID = Stream.readRecord(ID, R, &Blob); return parseRecord(R, RecID, Blob, I); } -template <> bool ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) { +template <> +llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) { Record R; llvm::StringRef Blob; unsigned RecID = Stream.readRecord(ID, R, &Blob); @@ -425,9 +469,11 @@ } // Read a block of records into a single info. -template bool ClangDocBitcodeReader::readBlock(unsigned ID, T I) { +template +llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) { if (Stream.EnterSubBlock(ID)) - return false; + return llvm::make_error("Unable to enter subblock.\n", + llvm::inconvertibleErrorCode()); while (true) { unsigned BlockOrCode = 0; @@ -435,66 +481,69 @@ switch (Res) { case Cursor::BadBlock: - return false; + return llvm::make_error( + "Bad block found.\n", llvm::inconvertibleErrorCode()); case Cursor::BlockEnd: - return true; - case Cursor::BlockBegin: - if (readSubBlock(BlockOrCode, I)) + return llvm::Error::success(); + + case Cursor::BlockBegin: { + auto Err = readSubBlock(BlockOrCode, I); + if (!Err) continue; if (!Stream.SkipBlock()) - return false; + return std::move(Err); continue; + } case Cursor::Record: break; } - if (!readRecord(BlockOrCode, I)) - return false; + auto Err = readRecord(BlockOrCode, I); + if (Err) + return Err; } } template -bool ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { +llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { switch (ID) { // Blocks can only have Comment, Reference, or TypeInfo subblocks - case BI_COMMENT_BLOCK_ID: - if (readBlock(ID, getCommentInfo(I))) - return true; - return false; + case BI_COMMENT_BLOCK_ID: { + auto Comment = getCommentInfo(I); + if (!Comment) + return Comment.takeError(); + return readBlock(ID, Comment.get()); + } case BI_TYPE_BLOCK_ID: { TypeInfo TI; - if (readBlock(ID, &TI)) { - addTypeInfo(I, std::move(TI)); - return true; - } - return false; + auto Err = readBlock(ID, &TI); + if (Err) + return Err; + return addTypeInfo(I, std::move(TI)); } case BI_FIELD_TYPE_BLOCK_ID: { FieldTypeInfo TI; - if (readBlock(ID, &TI)) { - addTypeInfo(I, std::move(TI)); - return true; - } - return false; + auto Err = readBlock(ID, &TI); + if (Err) + return Err; + return addTypeInfo(I, std::move(TI)); } case BI_MEMBER_TYPE_BLOCK_ID: { MemberTypeInfo TI; - if (readBlock(ID, &TI)) { - addTypeInfo(I, std::move(TI)); - return true; - } - return false; + auto Err = readBlock(ID, &TI); + if (Err) + return Err; + return addTypeInfo(I, std::move(TI)); } case BI_REFERENCE_BLOCK_ID: { Reference R; - if (readBlock(ID, &R)) { - addReference(I, std::move(R), CurrentReferenceField); - return true; - } - return false; + auto Err = readBlock(ID, &R); + if (Err) + return Err; + return addReference(I, std::move(R), CurrentReferenceField); } default: - llvm::errs() << "Invalid subblock type.\n"; - return false; + return llvm::make_error("Invalid subblock type.\n", + llvm::inconvertibleErrorCode()); } } @@ -526,37 +575,43 @@ llvm_unreachable("Premature stream end."); } -bool ClangDocBitcodeReader::validateStream() { +llvm::Error ClangDocBitcodeReader::validateStream() { if (Stream.AtEndOfStream()) - return false; + return llvm::make_error("Premature end of stream.\n", + llvm::inconvertibleErrorCode()); // Sniff for the signature. if (Stream.Read(8) != BitCodeConstants::Signature[0] || Stream.Read(8) != BitCodeConstants::Signature[1] || Stream.Read(8) != BitCodeConstants::Signature[2] || Stream.Read(8) != BitCodeConstants::Signature[3]) - return false; - return true; + return llvm::make_error("Invalid bitcode signature.\n", + llvm::inconvertibleErrorCode()); + return llvm::Error::success(); } -bool ClangDocBitcodeReader::readBlockInfoBlock() { +llvm::Error ClangDocBitcodeReader::readBlockInfoBlock() { BlockInfo = Stream.ReadBlockInfoBlock(); if (!BlockInfo) - return false; + return llvm::make_error( + "Unable to parse BlockInfoBlock.\n", llvm::inconvertibleErrorCode()); Stream.setBlockInfo(&*BlockInfo); - return true; + return llvm::Error::success(); } template -std::unique_ptr ClangDocBitcodeReader::createInfo(unsigned ID) { +llvm::Expected> +ClangDocBitcodeReader::createInfo(unsigned ID) { std::unique_ptr I = llvm::make_unique(); - if (readBlock(ID, static_cast(I.get()))) - return I; - llvm::errs() << "Error reading from block.\n"; - return nullptr; + auto Err = readBlock(ID, static_cast(I.get())); + if (Err) + return std::move(Err); + + return I; } -std::unique_ptr ClangDocBitcodeReader::readBlockToInfo(unsigned ID) { +llvm::Expected> +ClangDocBitcodeReader::readBlockToInfo(unsigned ID) { switch (ID) { case BI_NAMESPACE_BLOCK_ID: return createInfo(ID); @@ -567,23 +622,25 @@ case BI_FUNCTION_BLOCK_ID: return createInfo(ID); default: - llvm::errs() << "Error reading from block.\n"; - return nullptr; + return llvm::make_error("Cannot create info.\n", + llvm::inconvertibleErrorCode()); } } // Entry point -std::vector> ClangDocBitcodeReader::readBitcode() { +llvm::Expected>> +ClangDocBitcodeReader::readBitcode() { std::vector> Infos; - if (!validateStream()) - return Infos; + auto Err = validateStream(); + if (Err) + return std::move(Err); // Read the top level blocks. while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code != llvm::bitc::ENTER_SUBBLOCK) - return Infos; - + return llvm::make_error( + "No blocks in input.\n", llvm::inconvertibleErrorCode()); unsigned ID = Stream.ReadSubBlockID(); switch (ID) { // NamedType and Comment blocks should not appear at the top level @@ -592,24 +649,30 @@ case BI_MEMBER_TYPE_BLOCK_ID: case BI_COMMENT_BLOCK_ID: case BI_REFERENCE_BLOCK_ID: - llvm::errs() << "Invalid top level block.\n"; - return Infos; + return llvm::make_error( + "Invalid top level block.\n", llvm::inconvertibleErrorCode()); case BI_NAMESPACE_BLOCK_ID: case BI_RECORD_BLOCK_ID: case BI_ENUM_BLOCK_ID: - case BI_FUNCTION_BLOCK_ID: - if (std::unique_ptr I = readBlockToInfo(ID)) { - Infos.emplace_back(std::move(I)); - } - return Infos; - case BI_VERSION_BLOCK_ID: - if (readBlock(ID, VersionNumber)) - continue; - return Infos; - case llvm::bitc::BLOCKINFO_BLOCK_ID: - if (readBlockInfoBlock()) - continue; - return Infos; + case BI_FUNCTION_BLOCK_ID: { + auto I = readBlockToInfo(ID); + if (!I) + return I.takeError(); + Infos.emplace_back(std::move(I.get())); + continue; + } + case BI_VERSION_BLOCK_ID: { + auto Err = readBlock(ID, VersionNumber); + if (Err) + return std::move(Err); + continue; + } + case llvm::bitc::BLOCKINFO_BLOCK_ID: { + auto Err = readBlockInfoBlock(); + if (Err) + return std::move(Err); + continue; + } default: if (!Stream.SkipBlock()) continue; Index: clang-tools-extra/clang-doc/tool/ClangDocMain.cpp =================================================================== --- clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -201,7 +201,11 @@ llvm::BitstreamCursor Stream(Value); doc::ClangDocBitcodeReader Reader(Stream); auto Infos = Reader.readBitcode(); - for (auto &I : Infos) { + if (!Infos) { + llvm::errs() << llvm::toString(Infos.takeError()) << "\n"; + return; + } + for (auto &I : Infos.get()) { auto R = MapOutput.try_emplace(Key, std::vector>()); R.first->second.emplace_back(std::move(I));