xref: /freebsd-src/contrib/llvm-project/clang/lib/Frontend/SerializedDiagnosticReader.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "clang/Frontend/SerializedDiagnosticReader.h"
100b57cec5SDimitry Andric #include "clang/Basic/FileManager.h"
110b57cec5SDimitry Andric #include "clang/Basic/FileSystemOptions.h"
120b57cec5SDimitry Andric #include "clang/Frontend/SerializedDiagnostics.h"
130b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
140b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
150b57cec5SDimitry Andric #include "llvm/Bitstream/BitCodes.h"
160b57cec5SDimitry Andric #include "llvm/Bitstream/BitstreamReader.h"
170b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
180b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
190b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
200b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h"
210b57cec5SDimitry Andric #include <cstdint>
22*bdd1243dSDimitry Andric #include <optional>
230b57cec5SDimitry Andric #include <system_error>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace clang;
260b57cec5SDimitry Andric using namespace serialized_diags;
270b57cec5SDimitry Andric 
readDiagnostics(StringRef File)280b57cec5SDimitry Andric std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
290b57cec5SDimitry Andric   // Open the diagnostics file.
300b57cec5SDimitry Andric   FileSystemOptions FO;
310b57cec5SDimitry Andric   FileManager FileMgr(FO);
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   auto Buffer = FileMgr.getBufferForFile(File);
340b57cec5SDimitry Andric   if (!Buffer)
350b57cec5SDimitry Andric     return SDError::CouldNotLoad;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   llvm::BitstreamCursor Stream(**Buffer);
38*bdd1243dSDimitry Andric   std::optional<llvm::BitstreamBlockInfo> BlockInfo;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   if (Stream.AtEndOfStream())
410b57cec5SDimitry Andric     return SDError::InvalidSignature;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   // Sniff for the signature.
440b57cec5SDimitry Andric   for (unsigned char C : {'D', 'I', 'A', 'G'}) {
450b57cec5SDimitry Andric     if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) {
460b57cec5SDimitry Andric       if (Res.get() == C)
470b57cec5SDimitry Andric         continue;
480b57cec5SDimitry Andric     } else {
490b57cec5SDimitry Andric       // FIXME this drops the error on the floor.
500b57cec5SDimitry Andric       consumeError(Res.takeError());
510b57cec5SDimitry Andric     }
520b57cec5SDimitry Andric     return SDError::InvalidSignature;
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   // Read the top level blocks.
560b57cec5SDimitry Andric   while (!Stream.AtEndOfStream()) {
570b57cec5SDimitry Andric     if (Expected<unsigned> Res = Stream.ReadCode()) {
580b57cec5SDimitry Andric       if (Res.get() != llvm::bitc::ENTER_SUBBLOCK)
590b57cec5SDimitry Andric         return SDError::InvalidDiagnostics;
600b57cec5SDimitry Andric     } else {
610b57cec5SDimitry Andric       // FIXME this drops the error on the floor.
620b57cec5SDimitry Andric       consumeError(Res.takeError());
630b57cec5SDimitry Andric       return SDError::InvalidDiagnostics;
640b57cec5SDimitry Andric     }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric     std::error_code EC;
670b57cec5SDimitry Andric     Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID();
680b57cec5SDimitry Andric     if (!MaybeSubBlockID) {
690b57cec5SDimitry Andric       // FIXME this drops the error on the floor.
700b57cec5SDimitry Andric       consumeError(MaybeSubBlockID.takeError());
710b57cec5SDimitry Andric       return SDError::InvalidDiagnostics;
720b57cec5SDimitry Andric     }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric     switch (MaybeSubBlockID.get()) {
750b57cec5SDimitry Andric     case llvm::bitc::BLOCKINFO_BLOCK_ID: {
76*bdd1243dSDimitry Andric       Expected<std::optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =
770b57cec5SDimitry Andric           Stream.ReadBlockInfoBlock();
780b57cec5SDimitry Andric       if (!MaybeBlockInfo) {
790b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
800b57cec5SDimitry Andric         consumeError(MaybeBlockInfo.takeError());
810b57cec5SDimitry Andric         return SDError::InvalidDiagnostics;
820b57cec5SDimitry Andric       }
830b57cec5SDimitry Andric       BlockInfo = std::move(MaybeBlockInfo.get());
840b57cec5SDimitry Andric     }
850b57cec5SDimitry Andric       if (!BlockInfo)
860b57cec5SDimitry Andric         return SDError::MalformedBlockInfoBlock;
870b57cec5SDimitry Andric       Stream.setBlockInfo(&*BlockInfo);
880b57cec5SDimitry Andric       continue;
890b57cec5SDimitry Andric     case BLOCK_META:
900b57cec5SDimitry Andric       if ((EC = readMetaBlock(Stream)))
910b57cec5SDimitry Andric         return EC;
920b57cec5SDimitry Andric       continue;
930b57cec5SDimitry Andric     case BLOCK_DIAG:
940b57cec5SDimitry Andric       if ((EC = readDiagnosticBlock(Stream)))
950b57cec5SDimitry Andric         return EC;
960b57cec5SDimitry Andric       continue;
970b57cec5SDimitry Andric     default:
980b57cec5SDimitry Andric       if (llvm::Error Err = Stream.SkipBlock()) {
990b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
1000b57cec5SDimitry Andric         consumeError(std::move(Err));
1010b57cec5SDimitry Andric         return SDError::MalformedTopLevelBlock;
1020b57cec5SDimitry Andric       }
1030b57cec5SDimitry Andric       continue;
1040b57cec5SDimitry Andric     }
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric   return {};
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric enum class SerializedDiagnosticReader::Cursor {
1100b57cec5SDimitry Andric   Record = 1,
1110b57cec5SDimitry Andric   BlockEnd,
1120b57cec5SDimitry Andric   BlockBegin
1130b57cec5SDimitry Andric };
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
skipUntilRecordOrBlock(llvm::BitstreamCursor & Stream,unsigned & BlockOrRecordID)1160b57cec5SDimitry Andric SerializedDiagnosticReader::skipUntilRecordOrBlock(
1170b57cec5SDimitry Andric     llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
1180b57cec5SDimitry Andric   BlockOrRecordID = 0;
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   while (!Stream.AtEndOfStream()) {
1210b57cec5SDimitry Andric     unsigned Code;
1220b57cec5SDimitry Andric     if (Expected<unsigned> Res = Stream.ReadCode())
1230b57cec5SDimitry Andric       Code = Res.get();
1240b57cec5SDimitry Andric     else
1250b57cec5SDimitry Andric       return llvm::errorToErrorCode(Res.takeError());
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric     if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) {
1280b57cec5SDimitry Andric       // We found a record.
1290b57cec5SDimitry Andric       BlockOrRecordID = Code;
1300b57cec5SDimitry Andric       return Cursor::Record;
1310b57cec5SDimitry Andric     }
1320b57cec5SDimitry Andric     switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) {
1330b57cec5SDimitry Andric     case llvm::bitc::ENTER_SUBBLOCK:
1340b57cec5SDimitry Andric       if (Expected<unsigned> Res = Stream.ReadSubBlockID())
1350b57cec5SDimitry Andric         BlockOrRecordID = Res.get();
1360b57cec5SDimitry Andric       else
1370b57cec5SDimitry Andric         return llvm::errorToErrorCode(Res.takeError());
1380b57cec5SDimitry Andric       return Cursor::BlockBegin;
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric     case llvm::bitc::END_BLOCK:
1410b57cec5SDimitry Andric       if (Stream.ReadBlockEnd())
1420b57cec5SDimitry Andric         return SDError::InvalidDiagnostics;
1430b57cec5SDimitry Andric       return Cursor::BlockEnd;
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric     case llvm::bitc::DEFINE_ABBREV:
1460b57cec5SDimitry Andric       if (llvm::Error Err = Stream.ReadAbbrevRecord())
1470b57cec5SDimitry Andric         return llvm::errorToErrorCode(std::move(Err));
1480b57cec5SDimitry Andric       continue;
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric     case llvm::bitc::UNABBREV_RECORD:
1510b57cec5SDimitry Andric       return SDError::UnsupportedConstruct;
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric     case llvm::bitc::FIRST_APPLICATION_ABBREV:
1540b57cec5SDimitry Andric       llvm_unreachable("Unexpected abbrev id.");
1550b57cec5SDimitry Andric     }
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   return SDError::InvalidDiagnostics;
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric std::error_code
readMetaBlock(llvm::BitstreamCursor & Stream)1620b57cec5SDimitry Andric SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
1630b57cec5SDimitry Andric   if (llvm::Error Err =
1640b57cec5SDimitry Andric           Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
1650b57cec5SDimitry Andric     // FIXME this drops the error on the floor.
1660b57cec5SDimitry Andric     consumeError(std::move(Err));
1670b57cec5SDimitry Andric     return SDError::MalformedMetadataBlock;
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   bool VersionChecked = false;
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   while (true) {
1730b57cec5SDimitry Andric     unsigned BlockOrCode = 0;
1740b57cec5SDimitry Andric     llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
1750b57cec5SDimitry Andric     if (!Res)
1760b57cec5SDimitry Andric       Res.getError();
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric     switch (Res.get()) {
1790b57cec5SDimitry Andric     case Cursor::Record:
1800b57cec5SDimitry Andric       break;
1810b57cec5SDimitry Andric     case Cursor::BlockBegin:
1820b57cec5SDimitry Andric       if (llvm::Error Err = Stream.SkipBlock()) {
1830b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
1840b57cec5SDimitry Andric         consumeError(std::move(Err));
1850b57cec5SDimitry Andric         return SDError::MalformedMetadataBlock;
1860b57cec5SDimitry Andric       }
187*bdd1243dSDimitry Andric       [[fallthrough]];
1880b57cec5SDimitry Andric     case Cursor::BlockEnd:
1890b57cec5SDimitry Andric       if (!VersionChecked)
1900b57cec5SDimitry Andric         return SDError::MissingVersion;
1910b57cec5SDimitry Andric       return {};
1920b57cec5SDimitry Andric     }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric     SmallVector<uint64_t, 1> Record;
1950b57cec5SDimitry Andric     Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record);
1960b57cec5SDimitry Andric     if (!MaybeRecordID)
1970b57cec5SDimitry Andric       return errorToErrorCode(MaybeRecordID.takeError());
1980b57cec5SDimitry Andric     unsigned RecordID = MaybeRecordID.get();
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric     if (RecordID == RECORD_VERSION) {
2010b57cec5SDimitry Andric       if (Record.size() < 1)
2020b57cec5SDimitry Andric         return SDError::MissingVersion;
2030b57cec5SDimitry Andric       if (Record[0] > VersionNumber)
2040b57cec5SDimitry Andric         return SDError::VersionMismatch;
2050b57cec5SDimitry Andric       VersionChecked = true;
2060b57cec5SDimitry Andric     }
2070b57cec5SDimitry Andric   }
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric std::error_code
readDiagnosticBlock(llvm::BitstreamCursor & Stream)2110b57cec5SDimitry Andric SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
2120b57cec5SDimitry Andric   if (llvm::Error Err =
2130b57cec5SDimitry Andric           Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
2140b57cec5SDimitry Andric     // FIXME this drops the error on the floor.
2150b57cec5SDimitry Andric     consumeError(std::move(Err));
2160b57cec5SDimitry Andric     return SDError::MalformedDiagnosticBlock;
2170b57cec5SDimitry Andric   }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric   std::error_code EC;
2200b57cec5SDimitry Andric   if ((EC = visitStartOfDiagnostic()))
2210b57cec5SDimitry Andric     return EC;
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   SmallVector<uint64_t, 16> Record;
2240b57cec5SDimitry Andric   while (true) {
2250b57cec5SDimitry Andric     unsigned BlockOrCode = 0;
2260b57cec5SDimitry Andric     llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
2270b57cec5SDimitry Andric     if (!Res)
2280b57cec5SDimitry Andric       Res.getError();
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric     switch (Res.get()) {
2310b57cec5SDimitry Andric     case Cursor::BlockBegin:
2320b57cec5SDimitry Andric       // The only blocks we care about are subdiagnostics.
2330b57cec5SDimitry Andric       if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
2340b57cec5SDimitry Andric         if ((EC = readDiagnosticBlock(Stream)))
2350b57cec5SDimitry Andric           return EC;
2360b57cec5SDimitry Andric       } else if (llvm::Error Err = Stream.SkipBlock()) {
2370b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
2380b57cec5SDimitry Andric         consumeError(std::move(Err));
2390b57cec5SDimitry Andric         return SDError::MalformedSubBlock;
2400b57cec5SDimitry Andric       }
2410b57cec5SDimitry Andric       continue;
2420b57cec5SDimitry Andric     case Cursor::BlockEnd:
2430b57cec5SDimitry Andric       if ((EC = visitEndOfDiagnostic()))
2440b57cec5SDimitry Andric         return EC;
2450b57cec5SDimitry Andric       return {};
2460b57cec5SDimitry Andric     case Cursor::Record:
2470b57cec5SDimitry Andric       break;
2480b57cec5SDimitry Andric     }
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric     // Read the record.
2510b57cec5SDimitry Andric     Record.clear();
2520b57cec5SDimitry Andric     StringRef Blob;
2530b57cec5SDimitry Andric     Expected<unsigned> MaybeRecID =
2540b57cec5SDimitry Andric         Stream.readRecord(BlockOrCode, Record, &Blob);
2550b57cec5SDimitry Andric     if (!MaybeRecID)
2560b57cec5SDimitry Andric       return errorToErrorCode(MaybeRecID.takeError());
2570b57cec5SDimitry Andric     unsigned RecID = MaybeRecID.get();
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric     if (RecID < serialized_diags::RECORD_FIRST ||
2600b57cec5SDimitry Andric         RecID > serialized_diags::RECORD_LAST)
2610b57cec5SDimitry Andric       continue;
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric     switch ((RecordIDs)RecID) {
2640b57cec5SDimitry Andric     case RECORD_CATEGORY:
2650b57cec5SDimitry Andric       // A category has ID and name size.
2660b57cec5SDimitry Andric       if (Record.size() != 2)
2670b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
2680b57cec5SDimitry Andric       if ((EC = visitCategoryRecord(Record[0], Blob)))
2690b57cec5SDimitry Andric         return EC;
2700b57cec5SDimitry Andric       continue;
2710b57cec5SDimitry Andric     case RECORD_DIAG:
2720b57cec5SDimitry Andric       // A diagnostic has severity, location (4), category, flag, and message
2730b57cec5SDimitry Andric       // size.
2740b57cec5SDimitry Andric       if (Record.size() != 8)
2750b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
2760b57cec5SDimitry Andric       if ((EC = visitDiagnosticRecord(
2770b57cec5SDimitry Andric                Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
2780b57cec5SDimitry Andric                Record[5], Record[6], Blob)))
2790b57cec5SDimitry Andric         return EC;
2800b57cec5SDimitry Andric       continue;
2810b57cec5SDimitry Andric     case RECORD_DIAG_FLAG:
2820b57cec5SDimitry Andric       // A diagnostic flag has ID and name size.
2830b57cec5SDimitry Andric       if (Record.size() != 2)
2840b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
2850b57cec5SDimitry Andric       if ((EC = visitDiagFlagRecord(Record[0], Blob)))
2860b57cec5SDimitry Andric         return EC;
2870b57cec5SDimitry Andric       continue;
2880b57cec5SDimitry Andric     case RECORD_FILENAME:
2890b57cec5SDimitry Andric       // A filename has ID, size, timestamp, and name size. The size and
2900b57cec5SDimitry Andric       // timestamp are legacy fields that are always zero these days.
2910b57cec5SDimitry Andric       if (Record.size() != 4)
2920b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
2930b57cec5SDimitry Andric       if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
2940b57cec5SDimitry Andric         return EC;
2950b57cec5SDimitry Andric       continue;
2960b57cec5SDimitry Andric     case RECORD_FIXIT:
2970b57cec5SDimitry Andric       // A fixit has two locations (4 each) and message size.
2980b57cec5SDimitry Andric       if (Record.size() != 9)
2990b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
3000b57cec5SDimitry Andric       if ((EC = visitFixitRecord(
3010b57cec5SDimitry Andric                Location(Record[0], Record[1], Record[2], Record[3]),
3020b57cec5SDimitry Andric                Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
3030b57cec5SDimitry Andric         return EC;
3040b57cec5SDimitry Andric       continue;
3050b57cec5SDimitry Andric     case RECORD_SOURCE_RANGE:
3060b57cec5SDimitry Andric       // A source range is two locations (4 each).
3070b57cec5SDimitry Andric       if (Record.size() != 8)
3080b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
3090b57cec5SDimitry Andric       if ((EC = visitSourceRangeRecord(
3100b57cec5SDimitry Andric                Location(Record[0], Record[1], Record[2], Record[3]),
3110b57cec5SDimitry Andric                Location(Record[4], Record[5], Record[6], Record[7]))))
3120b57cec5SDimitry Andric         return EC;
3130b57cec5SDimitry Andric       continue;
3140b57cec5SDimitry Andric     case RECORD_VERSION:
3150b57cec5SDimitry Andric       // A version is just a number.
3160b57cec5SDimitry Andric       if (Record.size() != 1)
3170b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
3180b57cec5SDimitry Andric       if ((EC = visitVersionRecord(Record[0])))
3190b57cec5SDimitry Andric         return EC;
3200b57cec5SDimitry Andric       continue;
3210b57cec5SDimitry Andric     }
3220b57cec5SDimitry Andric   }
3230b57cec5SDimitry Andric }
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric namespace {
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric class SDErrorCategoryType final : public std::error_category {
name() const3280b57cec5SDimitry Andric   const char *name() const noexcept override {
3290b57cec5SDimitry Andric     return "clang.serialized_diags";
3300b57cec5SDimitry Andric   }
3310b57cec5SDimitry Andric 
message(int IE) const3320b57cec5SDimitry Andric   std::string message(int IE) const override {
3330b57cec5SDimitry Andric     auto E = static_cast<SDError>(IE);
3340b57cec5SDimitry Andric     switch (E) {
3350b57cec5SDimitry Andric     case SDError::CouldNotLoad:
3360b57cec5SDimitry Andric       return "Failed to open diagnostics file";
3370b57cec5SDimitry Andric     case SDError::InvalidSignature:
3380b57cec5SDimitry Andric       return "Invalid diagnostics signature";
3390b57cec5SDimitry Andric     case SDError::InvalidDiagnostics:
3400b57cec5SDimitry Andric       return "Parse error reading diagnostics";
3410b57cec5SDimitry Andric     case SDError::MalformedTopLevelBlock:
3420b57cec5SDimitry Andric       return "Malformed block at top-level of diagnostics";
3430b57cec5SDimitry Andric     case SDError::MalformedSubBlock:
3440b57cec5SDimitry Andric       return "Malformed sub-block in a diagnostic";
3450b57cec5SDimitry Andric     case SDError::MalformedBlockInfoBlock:
3460b57cec5SDimitry Andric       return "Malformed BlockInfo block";
3470b57cec5SDimitry Andric     case SDError::MalformedMetadataBlock:
3480b57cec5SDimitry Andric       return "Malformed Metadata block";
3490b57cec5SDimitry Andric     case SDError::MalformedDiagnosticBlock:
3500b57cec5SDimitry Andric       return "Malformed Diagnostic block";
3510b57cec5SDimitry Andric     case SDError::MalformedDiagnosticRecord:
3520b57cec5SDimitry Andric       return "Malformed Diagnostic record";
3530b57cec5SDimitry Andric     case SDError::MissingVersion:
3540b57cec5SDimitry Andric       return "No version provided in diagnostics";
3550b57cec5SDimitry Andric     case SDError::VersionMismatch:
3560b57cec5SDimitry Andric       return "Unsupported diagnostics version";
3570b57cec5SDimitry Andric     case SDError::UnsupportedConstruct:
3580b57cec5SDimitry Andric       return "Bitcode constructs that are not supported in diagnostics appear";
3590b57cec5SDimitry Andric     case SDError::HandlerFailed:
3600b57cec5SDimitry Andric       return "Generic error occurred while handling a record";
3610b57cec5SDimitry Andric     }
3620b57cec5SDimitry Andric     llvm_unreachable("Unknown error type!");
3630b57cec5SDimitry Andric   }
3640b57cec5SDimitry Andric };
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric } // namespace
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
SDErrorCategory()3690b57cec5SDimitry Andric const std::error_category &clang::serialized_diags::SDErrorCategory() {
3700b57cec5SDimitry Andric   return *ErrorCategory;
3710b57cec5SDimitry Andric }
372