xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/SerializedDiagnosticReader.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "clang/Frontend/SerializedDiagnosticReader.h"
10*0b57cec5SDimitry Andric #include "clang/Basic/FileManager.h"
11*0b57cec5SDimitry Andric #include "clang/Basic/FileSystemOptions.h"
12*0b57cec5SDimitry Andric #include "clang/Frontend/SerializedDiagnostics.h"
13*0b57cec5SDimitry Andric #include "llvm/ADT/Optional.h"
14*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
15*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
16*0b57cec5SDimitry Andric #include "llvm/Bitstream/BitCodes.h"
17*0b57cec5SDimitry Andric #include "llvm/Bitstream/BitstreamReader.h"
18*0b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
21*0b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h"
22*0b57cec5SDimitry Andric #include <cstdint>
23*0b57cec5SDimitry Andric #include <system_error>
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric using namespace clang;
26*0b57cec5SDimitry Andric using namespace serialized_diags;
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
29*0b57cec5SDimitry Andric   // Open the diagnostics file.
30*0b57cec5SDimitry Andric   FileSystemOptions FO;
31*0b57cec5SDimitry Andric   FileManager FileMgr(FO);
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric   auto Buffer = FileMgr.getBufferForFile(File);
34*0b57cec5SDimitry Andric   if (!Buffer)
35*0b57cec5SDimitry Andric     return SDError::CouldNotLoad;
36*0b57cec5SDimitry Andric 
37*0b57cec5SDimitry Andric   llvm::BitstreamCursor Stream(**Buffer);
38*0b57cec5SDimitry Andric   Optional<llvm::BitstreamBlockInfo> BlockInfo;
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric   if (Stream.AtEndOfStream())
41*0b57cec5SDimitry Andric     return SDError::InvalidSignature;
42*0b57cec5SDimitry Andric 
43*0b57cec5SDimitry Andric   // Sniff for the signature.
44*0b57cec5SDimitry Andric   for (unsigned char C : {'D', 'I', 'A', 'G'}) {
45*0b57cec5SDimitry Andric     if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) {
46*0b57cec5SDimitry Andric       if (Res.get() == C)
47*0b57cec5SDimitry Andric         continue;
48*0b57cec5SDimitry Andric     } else {
49*0b57cec5SDimitry Andric       // FIXME this drops the error on the floor.
50*0b57cec5SDimitry Andric       consumeError(Res.takeError());
51*0b57cec5SDimitry Andric     }
52*0b57cec5SDimitry Andric     return SDError::InvalidSignature;
53*0b57cec5SDimitry Andric   }
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric   // Read the top level blocks.
56*0b57cec5SDimitry Andric   while (!Stream.AtEndOfStream()) {
57*0b57cec5SDimitry Andric     if (Expected<unsigned> Res = Stream.ReadCode()) {
58*0b57cec5SDimitry Andric       if (Res.get() != llvm::bitc::ENTER_SUBBLOCK)
59*0b57cec5SDimitry Andric         return SDError::InvalidDiagnostics;
60*0b57cec5SDimitry Andric     } else {
61*0b57cec5SDimitry Andric       // FIXME this drops the error on the floor.
62*0b57cec5SDimitry Andric       consumeError(Res.takeError());
63*0b57cec5SDimitry Andric       return SDError::InvalidDiagnostics;
64*0b57cec5SDimitry Andric     }
65*0b57cec5SDimitry Andric 
66*0b57cec5SDimitry Andric     std::error_code EC;
67*0b57cec5SDimitry Andric     Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID();
68*0b57cec5SDimitry Andric     if (!MaybeSubBlockID) {
69*0b57cec5SDimitry Andric       // FIXME this drops the error on the floor.
70*0b57cec5SDimitry Andric       consumeError(MaybeSubBlockID.takeError());
71*0b57cec5SDimitry Andric       return SDError::InvalidDiagnostics;
72*0b57cec5SDimitry Andric     }
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric     switch (MaybeSubBlockID.get()) {
75*0b57cec5SDimitry Andric     case llvm::bitc::BLOCKINFO_BLOCK_ID: {
76*0b57cec5SDimitry Andric       Expected<Optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =
77*0b57cec5SDimitry Andric           Stream.ReadBlockInfoBlock();
78*0b57cec5SDimitry Andric       if (!MaybeBlockInfo) {
79*0b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
80*0b57cec5SDimitry Andric         consumeError(MaybeBlockInfo.takeError());
81*0b57cec5SDimitry Andric         return SDError::InvalidDiagnostics;
82*0b57cec5SDimitry Andric       }
83*0b57cec5SDimitry Andric       BlockInfo = std::move(MaybeBlockInfo.get());
84*0b57cec5SDimitry Andric     }
85*0b57cec5SDimitry Andric       if (!BlockInfo)
86*0b57cec5SDimitry Andric         return SDError::MalformedBlockInfoBlock;
87*0b57cec5SDimitry Andric       Stream.setBlockInfo(&*BlockInfo);
88*0b57cec5SDimitry Andric       continue;
89*0b57cec5SDimitry Andric     case BLOCK_META:
90*0b57cec5SDimitry Andric       if ((EC = readMetaBlock(Stream)))
91*0b57cec5SDimitry Andric         return EC;
92*0b57cec5SDimitry Andric       continue;
93*0b57cec5SDimitry Andric     case BLOCK_DIAG:
94*0b57cec5SDimitry Andric       if ((EC = readDiagnosticBlock(Stream)))
95*0b57cec5SDimitry Andric         return EC;
96*0b57cec5SDimitry Andric       continue;
97*0b57cec5SDimitry Andric     default:
98*0b57cec5SDimitry Andric       if (llvm::Error Err = Stream.SkipBlock()) {
99*0b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
100*0b57cec5SDimitry Andric         consumeError(std::move(Err));
101*0b57cec5SDimitry Andric         return SDError::MalformedTopLevelBlock;
102*0b57cec5SDimitry Andric       }
103*0b57cec5SDimitry Andric       continue;
104*0b57cec5SDimitry Andric     }
105*0b57cec5SDimitry Andric   }
106*0b57cec5SDimitry Andric   return {};
107*0b57cec5SDimitry Andric }
108*0b57cec5SDimitry Andric 
109*0b57cec5SDimitry Andric enum class SerializedDiagnosticReader::Cursor {
110*0b57cec5SDimitry Andric   Record = 1,
111*0b57cec5SDimitry Andric   BlockEnd,
112*0b57cec5SDimitry Andric   BlockBegin
113*0b57cec5SDimitry Andric };
114*0b57cec5SDimitry Andric 
115*0b57cec5SDimitry Andric llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
116*0b57cec5SDimitry Andric SerializedDiagnosticReader::skipUntilRecordOrBlock(
117*0b57cec5SDimitry Andric     llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
118*0b57cec5SDimitry Andric   BlockOrRecordID = 0;
119*0b57cec5SDimitry Andric 
120*0b57cec5SDimitry Andric   while (!Stream.AtEndOfStream()) {
121*0b57cec5SDimitry Andric     unsigned Code;
122*0b57cec5SDimitry Andric     if (Expected<unsigned> Res = Stream.ReadCode())
123*0b57cec5SDimitry Andric       Code = Res.get();
124*0b57cec5SDimitry Andric     else
125*0b57cec5SDimitry Andric       return llvm::errorToErrorCode(Res.takeError());
126*0b57cec5SDimitry Andric 
127*0b57cec5SDimitry Andric     if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) {
128*0b57cec5SDimitry Andric       // We found a record.
129*0b57cec5SDimitry Andric       BlockOrRecordID = Code;
130*0b57cec5SDimitry Andric       return Cursor::Record;
131*0b57cec5SDimitry Andric     }
132*0b57cec5SDimitry Andric     switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) {
133*0b57cec5SDimitry Andric     case llvm::bitc::ENTER_SUBBLOCK:
134*0b57cec5SDimitry Andric       if (Expected<unsigned> Res = Stream.ReadSubBlockID())
135*0b57cec5SDimitry Andric         BlockOrRecordID = Res.get();
136*0b57cec5SDimitry Andric       else
137*0b57cec5SDimitry Andric         return llvm::errorToErrorCode(Res.takeError());
138*0b57cec5SDimitry Andric       return Cursor::BlockBegin;
139*0b57cec5SDimitry Andric 
140*0b57cec5SDimitry Andric     case llvm::bitc::END_BLOCK:
141*0b57cec5SDimitry Andric       if (Stream.ReadBlockEnd())
142*0b57cec5SDimitry Andric         return SDError::InvalidDiagnostics;
143*0b57cec5SDimitry Andric       return Cursor::BlockEnd;
144*0b57cec5SDimitry Andric 
145*0b57cec5SDimitry Andric     case llvm::bitc::DEFINE_ABBREV:
146*0b57cec5SDimitry Andric       if (llvm::Error Err = Stream.ReadAbbrevRecord())
147*0b57cec5SDimitry Andric         return llvm::errorToErrorCode(std::move(Err));
148*0b57cec5SDimitry Andric       continue;
149*0b57cec5SDimitry Andric 
150*0b57cec5SDimitry Andric     case llvm::bitc::UNABBREV_RECORD:
151*0b57cec5SDimitry Andric       return SDError::UnsupportedConstruct;
152*0b57cec5SDimitry Andric 
153*0b57cec5SDimitry Andric     case llvm::bitc::FIRST_APPLICATION_ABBREV:
154*0b57cec5SDimitry Andric       llvm_unreachable("Unexpected abbrev id.");
155*0b57cec5SDimitry Andric     }
156*0b57cec5SDimitry Andric   }
157*0b57cec5SDimitry Andric 
158*0b57cec5SDimitry Andric   return SDError::InvalidDiagnostics;
159*0b57cec5SDimitry Andric }
160*0b57cec5SDimitry Andric 
161*0b57cec5SDimitry Andric std::error_code
162*0b57cec5SDimitry Andric SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
163*0b57cec5SDimitry Andric   if (llvm::Error Err =
164*0b57cec5SDimitry Andric           Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
165*0b57cec5SDimitry Andric     // FIXME this drops the error on the floor.
166*0b57cec5SDimitry Andric     consumeError(std::move(Err));
167*0b57cec5SDimitry Andric     return SDError::MalformedMetadataBlock;
168*0b57cec5SDimitry Andric   }
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric   bool VersionChecked = false;
171*0b57cec5SDimitry Andric 
172*0b57cec5SDimitry Andric   while (true) {
173*0b57cec5SDimitry Andric     unsigned BlockOrCode = 0;
174*0b57cec5SDimitry Andric     llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
175*0b57cec5SDimitry Andric     if (!Res)
176*0b57cec5SDimitry Andric       Res.getError();
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric     switch (Res.get()) {
179*0b57cec5SDimitry Andric     case Cursor::Record:
180*0b57cec5SDimitry Andric       break;
181*0b57cec5SDimitry Andric     case Cursor::BlockBegin:
182*0b57cec5SDimitry Andric       if (llvm::Error Err = Stream.SkipBlock()) {
183*0b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
184*0b57cec5SDimitry Andric         consumeError(std::move(Err));
185*0b57cec5SDimitry Andric         return SDError::MalformedMetadataBlock;
186*0b57cec5SDimitry Andric       }
187*0b57cec5SDimitry Andric       LLVM_FALLTHROUGH;
188*0b57cec5SDimitry Andric     case Cursor::BlockEnd:
189*0b57cec5SDimitry Andric       if (!VersionChecked)
190*0b57cec5SDimitry Andric         return SDError::MissingVersion;
191*0b57cec5SDimitry Andric       return {};
192*0b57cec5SDimitry Andric     }
193*0b57cec5SDimitry Andric 
194*0b57cec5SDimitry Andric     SmallVector<uint64_t, 1> Record;
195*0b57cec5SDimitry Andric     Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record);
196*0b57cec5SDimitry Andric     if (!MaybeRecordID)
197*0b57cec5SDimitry Andric       return errorToErrorCode(MaybeRecordID.takeError());
198*0b57cec5SDimitry Andric     unsigned RecordID = MaybeRecordID.get();
199*0b57cec5SDimitry Andric 
200*0b57cec5SDimitry Andric     if (RecordID == RECORD_VERSION) {
201*0b57cec5SDimitry Andric       if (Record.size() < 1)
202*0b57cec5SDimitry Andric         return SDError::MissingVersion;
203*0b57cec5SDimitry Andric       if (Record[0] > VersionNumber)
204*0b57cec5SDimitry Andric         return SDError::VersionMismatch;
205*0b57cec5SDimitry Andric       VersionChecked = true;
206*0b57cec5SDimitry Andric     }
207*0b57cec5SDimitry Andric   }
208*0b57cec5SDimitry Andric }
209*0b57cec5SDimitry Andric 
210*0b57cec5SDimitry Andric std::error_code
211*0b57cec5SDimitry Andric SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
212*0b57cec5SDimitry Andric   if (llvm::Error Err =
213*0b57cec5SDimitry Andric           Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
214*0b57cec5SDimitry Andric     // FIXME this drops the error on the floor.
215*0b57cec5SDimitry Andric     consumeError(std::move(Err));
216*0b57cec5SDimitry Andric     return SDError::MalformedDiagnosticBlock;
217*0b57cec5SDimitry Andric   }
218*0b57cec5SDimitry Andric 
219*0b57cec5SDimitry Andric   std::error_code EC;
220*0b57cec5SDimitry Andric   if ((EC = visitStartOfDiagnostic()))
221*0b57cec5SDimitry Andric     return EC;
222*0b57cec5SDimitry Andric 
223*0b57cec5SDimitry Andric   SmallVector<uint64_t, 16> Record;
224*0b57cec5SDimitry Andric   while (true) {
225*0b57cec5SDimitry Andric     unsigned BlockOrCode = 0;
226*0b57cec5SDimitry Andric     llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
227*0b57cec5SDimitry Andric     if (!Res)
228*0b57cec5SDimitry Andric       Res.getError();
229*0b57cec5SDimitry Andric 
230*0b57cec5SDimitry Andric     switch (Res.get()) {
231*0b57cec5SDimitry Andric     case Cursor::BlockBegin:
232*0b57cec5SDimitry Andric       // The only blocks we care about are subdiagnostics.
233*0b57cec5SDimitry Andric       if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
234*0b57cec5SDimitry Andric         if ((EC = readDiagnosticBlock(Stream)))
235*0b57cec5SDimitry Andric           return EC;
236*0b57cec5SDimitry Andric       } else if (llvm::Error Err = Stream.SkipBlock()) {
237*0b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
238*0b57cec5SDimitry Andric         consumeError(std::move(Err));
239*0b57cec5SDimitry Andric         return SDError::MalformedSubBlock;
240*0b57cec5SDimitry Andric       }
241*0b57cec5SDimitry Andric       continue;
242*0b57cec5SDimitry Andric     case Cursor::BlockEnd:
243*0b57cec5SDimitry Andric       if ((EC = visitEndOfDiagnostic()))
244*0b57cec5SDimitry Andric         return EC;
245*0b57cec5SDimitry Andric       return {};
246*0b57cec5SDimitry Andric     case Cursor::Record:
247*0b57cec5SDimitry Andric       break;
248*0b57cec5SDimitry Andric     }
249*0b57cec5SDimitry Andric 
250*0b57cec5SDimitry Andric     // Read the record.
251*0b57cec5SDimitry Andric     Record.clear();
252*0b57cec5SDimitry Andric     StringRef Blob;
253*0b57cec5SDimitry Andric     Expected<unsigned> MaybeRecID =
254*0b57cec5SDimitry Andric         Stream.readRecord(BlockOrCode, Record, &Blob);
255*0b57cec5SDimitry Andric     if (!MaybeRecID)
256*0b57cec5SDimitry Andric       return errorToErrorCode(MaybeRecID.takeError());
257*0b57cec5SDimitry Andric     unsigned RecID = MaybeRecID.get();
258*0b57cec5SDimitry Andric 
259*0b57cec5SDimitry Andric     if (RecID < serialized_diags::RECORD_FIRST ||
260*0b57cec5SDimitry Andric         RecID > serialized_diags::RECORD_LAST)
261*0b57cec5SDimitry Andric       continue;
262*0b57cec5SDimitry Andric 
263*0b57cec5SDimitry Andric     switch ((RecordIDs)RecID) {
264*0b57cec5SDimitry Andric     case RECORD_CATEGORY:
265*0b57cec5SDimitry Andric       // A category has ID and name size.
266*0b57cec5SDimitry Andric       if (Record.size() != 2)
267*0b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
268*0b57cec5SDimitry Andric       if ((EC = visitCategoryRecord(Record[0], Blob)))
269*0b57cec5SDimitry Andric         return EC;
270*0b57cec5SDimitry Andric       continue;
271*0b57cec5SDimitry Andric     case RECORD_DIAG:
272*0b57cec5SDimitry Andric       // A diagnostic has severity, location (4), category, flag, and message
273*0b57cec5SDimitry Andric       // size.
274*0b57cec5SDimitry Andric       if (Record.size() != 8)
275*0b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
276*0b57cec5SDimitry Andric       if ((EC = visitDiagnosticRecord(
277*0b57cec5SDimitry Andric                Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
278*0b57cec5SDimitry Andric                Record[5], Record[6], Blob)))
279*0b57cec5SDimitry Andric         return EC;
280*0b57cec5SDimitry Andric       continue;
281*0b57cec5SDimitry Andric     case RECORD_DIAG_FLAG:
282*0b57cec5SDimitry Andric       // A diagnostic flag has ID and name size.
283*0b57cec5SDimitry Andric       if (Record.size() != 2)
284*0b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
285*0b57cec5SDimitry Andric       if ((EC = visitDiagFlagRecord(Record[0], Blob)))
286*0b57cec5SDimitry Andric         return EC;
287*0b57cec5SDimitry Andric       continue;
288*0b57cec5SDimitry Andric     case RECORD_FILENAME:
289*0b57cec5SDimitry Andric       // A filename has ID, size, timestamp, and name size. The size and
290*0b57cec5SDimitry Andric       // timestamp are legacy fields that are always zero these days.
291*0b57cec5SDimitry Andric       if (Record.size() != 4)
292*0b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
293*0b57cec5SDimitry Andric       if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
294*0b57cec5SDimitry Andric         return EC;
295*0b57cec5SDimitry Andric       continue;
296*0b57cec5SDimitry Andric     case RECORD_FIXIT:
297*0b57cec5SDimitry Andric       // A fixit has two locations (4 each) and message size.
298*0b57cec5SDimitry Andric       if (Record.size() != 9)
299*0b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
300*0b57cec5SDimitry Andric       if ((EC = visitFixitRecord(
301*0b57cec5SDimitry Andric                Location(Record[0], Record[1], Record[2], Record[3]),
302*0b57cec5SDimitry Andric                Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
303*0b57cec5SDimitry Andric         return EC;
304*0b57cec5SDimitry Andric       continue;
305*0b57cec5SDimitry Andric     case RECORD_SOURCE_RANGE:
306*0b57cec5SDimitry Andric       // A source range is two locations (4 each).
307*0b57cec5SDimitry Andric       if (Record.size() != 8)
308*0b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
309*0b57cec5SDimitry Andric       if ((EC = visitSourceRangeRecord(
310*0b57cec5SDimitry Andric                Location(Record[0], Record[1], Record[2], Record[3]),
311*0b57cec5SDimitry Andric                Location(Record[4], Record[5], Record[6], Record[7]))))
312*0b57cec5SDimitry Andric         return EC;
313*0b57cec5SDimitry Andric       continue;
314*0b57cec5SDimitry Andric     case RECORD_VERSION:
315*0b57cec5SDimitry Andric       // A version is just a number.
316*0b57cec5SDimitry Andric       if (Record.size() != 1)
317*0b57cec5SDimitry Andric         return SDError::MalformedDiagnosticRecord;
318*0b57cec5SDimitry Andric       if ((EC = visitVersionRecord(Record[0])))
319*0b57cec5SDimitry Andric         return EC;
320*0b57cec5SDimitry Andric       continue;
321*0b57cec5SDimitry Andric     }
322*0b57cec5SDimitry Andric   }
323*0b57cec5SDimitry Andric }
324*0b57cec5SDimitry Andric 
325*0b57cec5SDimitry Andric namespace {
326*0b57cec5SDimitry Andric 
327*0b57cec5SDimitry Andric class SDErrorCategoryType final : public std::error_category {
328*0b57cec5SDimitry Andric   const char *name() const noexcept override {
329*0b57cec5SDimitry Andric     return "clang.serialized_diags";
330*0b57cec5SDimitry Andric   }
331*0b57cec5SDimitry Andric 
332*0b57cec5SDimitry Andric   std::string message(int IE) const override {
333*0b57cec5SDimitry Andric     auto E = static_cast<SDError>(IE);
334*0b57cec5SDimitry Andric     switch (E) {
335*0b57cec5SDimitry Andric     case SDError::CouldNotLoad:
336*0b57cec5SDimitry Andric       return "Failed to open diagnostics file";
337*0b57cec5SDimitry Andric     case SDError::InvalidSignature:
338*0b57cec5SDimitry Andric       return "Invalid diagnostics signature";
339*0b57cec5SDimitry Andric     case SDError::InvalidDiagnostics:
340*0b57cec5SDimitry Andric       return "Parse error reading diagnostics";
341*0b57cec5SDimitry Andric     case SDError::MalformedTopLevelBlock:
342*0b57cec5SDimitry Andric       return "Malformed block at top-level of diagnostics";
343*0b57cec5SDimitry Andric     case SDError::MalformedSubBlock:
344*0b57cec5SDimitry Andric       return "Malformed sub-block in a diagnostic";
345*0b57cec5SDimitry Andric     case SDError::MalformedBlockInfoBlock:
346*0b57cec5SDimitry Andric       return "Malformed BlockInfo block";
347*0b57cec5SDimitry Andric     case SDError::MalformedMetadataBlock:
348*0b57cec5SDimitry Andric       return "Malformed Metadata block";
349*0b57cec5SDimitry Andric     case SDError::MalformedDiagnosticBlock:
350*0b57cec5SDimitry Andric       return "Malformed Diagnostic block";
351*0b57cec5SDimitry Andric     case SDError::MalformedDiagnosticRecord:
352*0b57cec5SDimitry Andric       return "Malformed Diagnostic record";
353*0b57cec5SDimitry Andric     case SDError::MissingVersion:
354*0b57cec5SDimitry Andric       return "No version provided in diagnostics";
355*0b57cec5SDimitry Andric     case SDError::VersionMismatch:
356*0b57cec5SDimitry Andric       return "Unsupported diagnostics version";
357*0b57cec5SDimitry Andric     case SDError::UnsupportedConstruct:
358*0b57cec5SDimitry Andric       return "Bitcode constructs that are not supported in diagnostics appear";
359*0b57cec5SDimitry Andric     case SDError::HandlerFailed:
360*0b57cec5SDimitry Andric       return "Generic error occurred while handling a record";
361*0b57cec5SDimitry Andric     }
362*0b57cec5SDimitry Andric     llvm_unreachable("Unknown error type!");
363*0b57cec5SDimitry Andric   }
364*0b57cec5SDimitry Andric };
365*0b57cec5SDimitry Andric 
366*0b57cec5SDimitry Andric } // namespace
367*0b57cec5SDimitry Andric 
368*0b57cec5SDimitry Andric static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
369*0b57cec5SDimitry Andric const std::error_category &clang::serialized_diags::SDErrorCategory() {
370*0b57cec5SDimitry Andric   return *ErrorCategory;
371*0b57cec5SDimitry Andric }
372