Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Basic/DiagnosticIDs.cpp
35233 views
1
//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements the Diagnostic IDs-related interfaces.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Basic/DiagnosticIDs.h"
14
#include "clang/Basic/AllDiagnostics.h"
15
#include "clang/Basic/DiagnosticCategories.h"
16
#include "clang/Basic/SourceManager.h"
17
#include "llvm/ADT/STLExtras.h"
18
#include "llvm/ADT/SmallVector.h"
19
#include "llvm/Support/ErrorHandling.h"
20
#include <map>
21
#include <optional>
22
using namespace clang;
23
24
//===----------------------------------------------------------------------===//
25
// Builtin Diagnostic information
26
//===----------------------------------------------------------------------===//
27
28
namespace {
29
30
struct StaticDiagInfoRec;
31
32
// Store the descriptions in a separate table to avoid pointers that need to
33
// be relocated, and also decrease the amount of data needed on 64-bit
34
// platforms. See "How To Write Shared Libraries" by Ulrich Drepper.
35
struct StaticDiagInfoDescriptionStringTable {
36
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
37
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
38
char ENUM##_desc[sizeof(DESC)];
39
// clang-format off
40
#include "clang/Basic/DiagnosticCommonKinds.inc"
41
#include "clang/Basic/DiagnosticDriverKinds.inc"
42
#include "clang/Basic/DiagnosticFrontendKinds.inc"
43
#include "clang/Basic/DiagnosticSerializationKinds.inc"
44
#include "clang/Basic/DiagnosticLexKinds.inc"
45
#include "clang/Basic/DiagnosticParseKinds.inc"
46
#include "clang/Basic/DiagnosticASTKinds.inc"
47
#include "clang/Basic/DiagnosticCommentKinds.inc"
48
#include "clang/Basic/DiagnosticCrossTUKinds.inc"
49
#include "clang/Basic/DiagnosticSemaKinds.inc"
50
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
51
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
52
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
53
// clang-format on
54
#undef DIAG
55
};
56
57
const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
58
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
59
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
60
DESC,
61
// clang-format off
62
#include "clang/Basic/DiagnosticCommonKinds.inc"
63
#include "clang/Basic/DiagnosticDriverKinds.inc"
64
#include "clang/Basic/DiagnosticFrontendKinds.inc"
65
#include "clang/Basic/DiagnosticSerializationKinds.inc"
66
#include "clang/Basic/DiagnosticLexKinds.inc"
67
#include "clang/Basic/DiagnosticParseKinds.inc"
68
#include "clang/Basic/DiagnosticASTKinds.inc"
69
#include "clang/Basic/DiagnosticCommentKinds.inc"
70
#include "clang/Basic/DiagnosticCrossTUKinds.inc"
71
#include "clang/Basic/DiagnosticSemaKinds.inc"
72
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
73
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
74
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
75
// clang-format on
76
#undef DIAG
77
};
78
79
extern const StaticDiagInfoRec StaticDiagInfo[];
80
81
// Stored separately from StaticDiagInfoRec to pack better. Otherwise,
82
// StaticDiagInfoRec would have extra padding on 64-bit platforms.
83
const uint32_t StaticDiagInfoDescriptionOffsets[] = {
84
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
85
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
86
offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),
87
// clang-format off
88
#include "clang/Basic/DiagnosticCommonKinds.inc"
89
#include "clang/Basic/DiagnosticDriverKinds.inc"
90
#include "clang/Basic/DiagnosticFrontendKinds.inc"
91
#include "clang/Basic/DiagnosticSerializationKinds.inc"
92
#include "clang/Basic/DiagnosticLexKinds.inc"
93
#include "clang/Basic/DiagnosticParseKinds.inc"
94
#include "clang/Basic/DiagnosticASTKinds.inc"
95
#include "clang/Basic/DiagnosticCommentKinds.inc"
96
#include "clang/Basic/DiagnosticCrossTUKinds.inc"
97
#include "clang/Basic/DiagnosticSemaKinds.inc"
98
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
99
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
100
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
101
// clang-format on
102
#undef DIAG
103
};
104
105
// Diagnostic classes.
106
enum DiagnosticClass {
107
CLASS_NOTE = 0x01,
108
CLASS_REMARK = 0x02,
109
CLASS_WARNING = 0x03,
110
CLASS_EXTENSION = 0x04,
111
CLASS_ERROR = 0x05
112
};
113
114
struct StaticDiagInfoRec {
115
uint16_t DiagID;
116
LLVM_PREFERRED_TYPE(diag::Severity)
117
uint8_t DefaultSeverity : 3;
118
LLVM_PREFERRED_TYPE(DiagnosticClass)
119
uint8_t Class : 3;
120
LLVM_PREFERRED_TYPE(DiagnosticIDs::SFINAEResponse)
121
uint8_t SFINAE : 2;
122
uint8_t Category : 6;
123
LLVM_PREFERRED_TYPE(bool)
124
uint8_t WarnNoWerror : 1;
125
LLVM_PREFERRED_TYPE(bool)
126
uint8_t WarnShowInSystemHeader : 1;
127
LLVM_PREFERRED_TYPE(bool)
128
uint8_t WarnShowInSystemMacro : 1;
129
130
uint16_t OptionGroupIndex : 15;
131
LLVM_PREFERRED_TYPE(bool)
132
uint16_t Deferrable : 1;
133
134
uint16_t DescriptionLen;
135
136
unsigned getOptionGroupIndex() const {
137
return OptionGroupIndex;
138
}
139
140
StringRef getDescription() const {
141
size_t MyIndex = this - &StaticDiagInfo[0];
142
uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];
143
const char* Table = reinterpret_cast<const char*>(&StaticDiagInfoDescriptions);
144
return StringRef(&Table[StringOffset], DescriptionLen);
145
}
146
147
diag::Flavor getFlavor() const {
148
return Class == CLASS_REMARK ? diag::Flavor::Remark
149
: diag::Flavor::WarningOrError;
150
}
151
152
bool operator<(const StaticDiagInfoRec &RHS) const {
153
return DiagID < RHS.DiagID;
154
}
155
};
156
157
#define STRINGIFY_NAME(NAME) #NAME
158
#define VALIDATE_DIAG_SIZE(NAME) \
159
static_assert( \
160
static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
161
static_cast<unsigned>(diag::DIAG_START_##NAME) + \
162
static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
163
STRINGIFY_NAME( \
164
DIAG_SIZE_##NAME) " is insufficient to contain all " \
165
"diagnostics, it may need to be made larger in " \
166
"DiagnosticIDs.h.");
167
VALIDATE_DIAG_SIZE(COMMON)
168
VALIDATE_DIAG_SIZE(DRIVER)
169
VALIDATE_DIAG_SIZE(FRONTEND)
170
VALIDATE_DIAG_SIZE(SERIALIZATION)
171
VALIDATE_DIAG_SIZE(LEX)
172
VALIDATE_DIAG_SIZE(PARSE)
173
VALIDATE_DIAG_SIZE(AST)
174
VALIDATE_DIAG_SIZE(COMMENT)
175
VALIDATE_DIAG_SIZE(CROSSTU)
176
VALIDATE_DIAG_SIZE(SEMA)
177
VALIDATE_DIAG_SIZE(ANALYSIS)
178
VALIDATE_DIAG_SIZE(REFACTORING)
179
VALIDATE_DIAG_SIZE(INSTALLAPI)
180
#undef VALIDATE_DIAG_SIZE
181
#undef STRINGIFY_NAME
182
183
const StaticDiagInfoRec StaticDiagInfo[] = {
184
// clang-format off
185
#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
186
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
187
{ \
188
diag::ENUM, \
189
DEFAULT_SEVERITY, \
190
CLASS, \
191
DiagnosticIDs::SFINAE, \
192
CATEGORY, \
193
NOWERROR, \
194
SHOWINSYSHEADER, \
195
SHOWINSYSMACRO, \
196
GROUP, \
197
DEFERRABLE, \
198
STR_SIZE(DESC, uint16_t)},
199
#include "clang/Basic/DiagnosticCommonKinds.inc"
200
#include "clang/Basic/DiagnosticDriverKinds.inc"
201
#include "clang/Basic/DiagnosticFrontendKinds.inc"
202
#include "clang/Basic/DiagnosticSerializationKinds.inc"
203
#include "clang/Basic/DiagnosticLexKinds.inc"
204
#include "clang/Basic/DiagnosticParseKinds.inc"
205
#include "clang/Basic/DiagnosticASTKinds.inc"
206
#include "clang/Basic/DiagnosticCommentKinds.inc"
207
#include "clang/Basic/DiagnosticCrossTUKinds.inc"
208
#include "clang/Basic/DiagnosticSemaKinds.inc"
209
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
210
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
211
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
212
// clang-format on
213
#undef DIAG
214
};
215
216
} // namespace
217
218
static const unsigned StaticDiagInfoSize = std::size(StaticDiagInfo);
219
220
/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
221
/// or null if the ID is invalid.
222
static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
223
// Out of bounds diag. Can't be in the table.
224
using namespace diag;
225
if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
226
return nullptr;
227
228
// Compute the index of the requested diagnostic in the static table.
229
// 1. Add the number of diagnostics in each category preceding the
230
// diagnostic and of the category the diagnostic is in. This gives us
231
// the offset of the category in the table.
232
// 2. Subtract the number of IDs in each category from our ID. This gives us
233
// the offset of the diagnostic in the category.
234
// This is cheaper than a binary search on the table as it doesn't touch
235
// memory at all.
236
unsigned Offset = 0;
237
unsigned ID = DiagID - DIAG_START_COMMON - 1;
238
#define CATEGORY(NAME, PREV) \
239
if (DiagID > DIAG_START_##NAME) { \
240
Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
241
ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
242
}
243
CATEGORY(DRIVER, COMMON)
244
CATEGORY(FRONTEND, DRIVER)
245
CATEGORY(SERIALIZATION, FRONTEND)
246
CATEGORY(LEX, SERIALIZATION)
247
CATEGORY(PARSE, LEX)
248
CATEGORY(AST, PARSE)
249
CATEGORY(COMMENT, AST)
250
CATEGORY(CROSSTU, COMMENT)
251
CATEGORY(SEMA, CROSSTU)
252
CATEGORY(ANALYSIS, SEMA)
253
CATEGORY(REFACTORING, ANALYSIS)
254
CATEGORY(INSTALLAPI, REFACTORING)
255
#undef CATEGORY
256
257
// Avoid out of bounds reads.
258
if (ID + Offset >= StaticDiagInfoSize)
259
return nullptr;
260
261
assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
262
263
const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
264
// If the diag id doesn't match we found a different diag, abort. This can
265
// happen when this function is called with an ID that points into a hole in
266
// the diagID space.
267
if (Found->DiagID != DiagID)
268
return nullptr;
269
return Found;
270
}
271
272
DiagnosticMapping DiagnosticIDs::getDefaultMapping(unsigned DiagID) {
273
DiagnosticMapping Info = DiagnosticMapping::Make(
274
diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
275
276
if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
277
Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
278
279
if (StaticInfo->WarnNoWerror) {
280
assert(Info.getSeverity() == diag::Severity::Warning &&
281
"Unexpected mapping with no-Werror bit!");
282
Info.setNoWarningAsError(true);
283
}
284
}
285
286
return Info;
287
}
288
289
/// getCategoryNumberForDiag - Return the category number that a specified
290
/// DiagID belongs to, or 0 if no category.
291
unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
292
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
293
return Info->Category;
294
return 0;
295
}
296
297
namespace {
298
// The diagnostic category names.
299
struct StaticDiagCategoryRec {
300
const char *NameStr;
301
uint8_t NameLen;
302
303
StringRef getName() const {
304
return StringRef(NameStr, NameLen);
305
}
306
};
307
}
308
309
static const StaticDiagCategoryRec CategoryNameTable[] = {
310
#define GET_CATEGORY_TABLE
311
#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
312
#include "clang/Basic/DiagnosticGroups.inc"
313
#undef GET_CATEGORY_TABLE
314
{ nullptr, 0 }
315
};
316
317
/// getNumberOfCategories - Return the number of categories
318
unsigned DiagnosticIDs::getNumberOfCategories() {
319
return std::size(CategoryNameTable) - 1;
320
}
321
322
/// getCategoryNameFromID - Given a category ID, return the name of the
323
/// category, an empty string if CategoryID is zero, or null if CategoryID is
324
/// invalid.
325
StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
326
if (CategoryID >= getNumberOfCategories())
327
return StringRef();
328
return CategoryNameTable[CategoryID].getName();
329
}
330
331
332
333
DiagnosticIDs::SFINAEResponse
334
DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
335
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
336
return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
337
return SFINAE_Report;
338
}
339
340
bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
341
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
342
return Info->Deferrable;
343
return false;
344
}
345
346
/// getBuiltinDiagClass - Return the class field of the diagnostic.
347
///
348
static unsigned getBuiltinDiagClass(unsigned DiagID) {
349
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
350
return Info->Class;
351
return ~0U;
352
}
353
354
//===----------------------------------------------------------------------===//
355
// Custom Diagnostic information
356
//===----------------------------------------------------------------------===//
357
358
namespace clang {
359
namespace diag {
360
class CustomDiagInfo {
361
typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
362
std::vector<DiagDesc> DiagInfo;
363
std::map<DiagDesc, unsigned> DiagIDs;
364
public:
365
366
/// getDescription - Return the description of the specified custom
367
/// diagnostic.
368
StringRef getDescription(unsigned DiagID) const {
369
assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
370
"Invalid diagnostic ID");
371
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
372
}
373
374
/// getLevel - Return the level of the specified custom diagnostic.
375
DiagnosticIDs::Level getLevel(unsigned DiagID) const {
376
assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
377
"Invalid diagnostic ID");
378
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
379
}
380
381
unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
382
DiagnosticIDs &Diags) {
383
DiagDesc D(L, std::string(Message));
384
// Check to see if it already exists.
385
std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
386
if (I != DiagIDs.end() && I->first == D)
387
return I->second;
388
389
// If not, assign a new ID.
390
unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
391
DiagIDs.insert(std::make_pair(D, ID));
392
DiagInfo.push_back(D);
393
return ID;
394
}
395
};
396
397
} // end diag namespace
398
} // end clang namespace
399
400
401
//===----------------------------------------------------------------------===//
402
// Common Diagnostic implementation
403
//===----------------------------------------------------------------------===//
404
405
DiagnosticIDs::DiagnosticIDs() {}
406
407
DiagnosticIDs::~DiagnosticIDs() {}
408
409
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
410
/// and level. If this is the first request for this diagnostic, it is
411
/// registered and created, otherwise the existing ID is returned.
412
///
413
/// \param FormatString A fixed diagnostic format string that will be hashed and
414
/// mapped to a unique DiagID.
415
unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
416
if (!CustomDiagInfo)
417
CustomDiagInfo.reset(new diag::CustomDiagInfo());
418
return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
419
}
420
421
422
/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
423
/// level of the specified diagnostic ID is a Warning or Extension.
424
/// This only works on builtin diagnostics, not custom ones, and is not legal to
425
/// call on NOTEs.
426
bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
427
return DiagID < diag::DIAG_UPPER_LIMIT &&
428
getBuiltinDiagClass(DiagID) != CLASS_ERROR;
429
}
430
431
/// Determine whether the given built-in diagnostic ID is a
432
/// Note.
433
bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
434
return DiagID < diag::DIAG_UPPER_LIMIT &&
435
getBuiltinDiagClass(DiagID) == CLASS_NOTE;
436
}
437
438
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
439
/// ID is for an extension of some sort. This also returns EnabledByDefault,
440
/// which is set to indicate whether the diagnostic is ignored by default (in
441
/// which case -pedantic enables it) or treated as a warning/error by default.
442
///
443
bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
444
bool &EnabledByDefault) {
445
if (DiagID >= diag::DIAG_UPPER_LIMIT ||
446
getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
447
return false;
448
449
EnabledByDefault =
450
getDefaultMapping(DiagID).getSeverity() != diag::Severity::Ignored;
451
return true;
452
}
453
454
bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
455
if (DiagID >= diag::DIAG_UPPER_LIMIT)
456
return false;
457
458
return getDefaultMapping(DiagID).getSeverity() >= diag::Severity::Error;
459
}
460
461
/// getDescription - Given a diagnostic ID, return a description of the
462
/// issue.
463
StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
464
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
465
return Info->getDescription();
466
assert(CustomDiagInfo && "Invalid CustomDiagInfo");
467
return CustomDiagInfo->getDescription(DiagID);
468
}
469
470
static DiagnosticIDs::Level toLevel(diag::Severity SV) {
471
switch (SV) {
472
case diag::Severity::Ignored:
473
return DiagnosticIDs::Ignored;
474
case diag::Severity::Remark:
475
return DiagnosticIDs::Remark;
476
case diag::Severity::Warning:
477
return DiagnosticIDs::Warning;
478
case diag::Severity::Error:
479
return DiagnosticIDs::Error;
480
case diag::Severity::Fatal:
481
return DiagnosticIDs::Fatal;
482
}
483
llvm_unreachable("unexpected severity");
484
}
485
486
/// getDiagnosticLevel - Based on the way the client configured the
487
/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
488
/// by consumable the DiagnosticClient.
489
DiagnosticIDs::Level
490
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
491
const DiagnosticsEngine &Diag) const {
492
// Handle custom diagnostics, which cannot be mapped.
493
if (DiagID >= diag::DIAG_UPPER_LIMIT) {
494
assert(CustomDiagInfo && "Invalid CustomDiagInfo");
495
return CustomDiagInfo->getLevel(DiagID);
496
}
497
498
unsigned DiagClass = getBuiltinDiagClass(DiagID);
499
if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
500
return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
501
}
502
503
/// Based on the way the client configured the Diagnostic
504
/// object, classify the specified diagnostic ID into a Level, consumable by
505
/// the DiagnosticClient.
506
///
507
/// \param Loc The source location we are interested in finding out the
508
/// diagnostic state. Can be null in order to query the latest state.
509
diag::Severity
510
DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
511
const DiagnosticsEngine &Diag) const {
512
assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
513
514
// Specific non-error diagnostics may be mapped to various levels from ignored
515
// to error. Errors can only be mapped to fatal.
516
diag::Severity Result = diag::Severity::Fatal;
517
518
// Get the mapping information, or compute it lazily.
519
DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
520
DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
521
522
// TODO: Can a null severity really get here?
523
if (Mapping.getSeverity() != diag::Severity())
524
Result = Mapping.getSeverity();
525
526
// Upgrade ignored diagnostics if -Weverything is enabled.
527
if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
528
!Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
529
Result = diag::Severity::Warning;
530
531
// Ignore -pedantic diagnostics inside __extension__ blocks.
532
// (The diagnostics controlled by -pedantic are the extension diagnostics
533
// that are not enabled by default.)
534
bool EnabledByDefault = false;
535
bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
536
if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
537
return diag::Severity::Ignored;
538
539
// For extension diagnostics that haven't been explicitly mapped, check if we
540
// should upgrade the diagnostic.
541
if (IsExtensionDiag && !Mapping.isUser())
542
Result = std::max(Result, State->ExtBehavior);
543
544
// At this point, ignored errors can no longer be upgraded.
545
if (Result == diag::Severity::Ignored)
546
return Result;
547
548
// Honor -w: this disables all messages which are not Error/Fatal by
549
// default (disregarding attempts to upgrade severity from Warning to Error),
550
// as well as disabling all messages which are currently mapped to Warning
551
// (whether by default or downgraded from Error via e.g. -Wno-error or #pragma
552
// diagnostic.)
553
if (State->IgnoreAllWarnings) {
554
if (Result == diag::Severity::Warning ||
555
(Result >= diag::Severity::Error &&
556
!isDefaultMappingAsError((diag::kind)DiagID)))
557
return diag::Severity::Ignored;
558
}
559
560
// If -Werror is enabled, map warnings to errors unless explicitly disabled.
561
if (Result == diag::Severity::Warning) {
562
if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
563
Result = diag::Severity::Error;
564
}
565
566
// If -Wfatal-errors is enabled, map errors to fatal unless explicitly
567
// disabled.
568
if (Result == diag::Severity::Error) {
569
if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
570
Result = diag::Severity::Fatal;
571
}
572
573
// If explicitly requested, map fatal errors to errors.
574
if (Result == diag::Severity::Fatal &&
575
Diag.CurDiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)
576
Result = diag::Severity::Error;
577
578
// Custom diagnostics always are emitted in system headers.
579
bool ShowInSystemHeader =
580
!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
581
582
// If we are in a system header, we ignore it. We look at the diagnostic class
583
// because we also want to ignore extensions and warnings in -Werror and
584
// -pedantic-errors modes, which *map* warnings/extensions to errors.
585
if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
586
Diag.getSourceManager().isInSystemHeader(
587
Diag.getSourceManager().getExpansionLoc(Loc)))
588
return diag::Severity::Ignored;
589
590
// We also ignore warnings due to system macros
591
bool ShowInSystemMacro =
592
!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro;
593
if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&
594
Diag.getSourceManager().isInSystemMacro(Loc))
595
return diag::Severity::Ignored;
596
597
return Result;
598
}
599
600
#define GET_DIAG_ARRAYS
601
#include "clang/Basic/DiagnosticGroups.inc"
602
#undef GET_DIAG_ARRAYS
603
604
namespace {
605
struct WarningOption {
606
uint16_t NameOffset;
607
uint16_t Members;
608
uint16_t SubGroups;
609
StringRef Documentation;
610
611
// String is stored with a pascal-style length byte.
612
StringRef getName() const {
613
return StringRef(DiagGroupNames + NameOffset + 1,
614
DiagGroupNames[NameOffset]);
615
}
616
};
617
}
618
619
// Second the table of options, sorted by name for fast binary lookup.
620
static const WarningOption OptionTable[] = {
621
#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
622
{FlagNameOffset, Members, SubGroups, Docs},
623
#include "clang/Basic/DiagnosticGroups.inc"
624
#undef DIAG_ENTRY
625
};
626
627
/// Given a diagnostic group ID, return its documentation.
628
StringRef DiagnosticIDs::getWarningOptionDocumentation(diag::Group Group) {
629
return OptionTable[static_cast<int>(Group)].Documentation;
630
}
631
632
StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) {
633
return OptionTable[static_cast<int>(Group)].getName();
634
}
635
636
std::optional<diag::Group>
637
DiagnosticIDs::getGroupForWarningOption(StringRef Name) {
638
const auto *Found = llvm::partition_point(
639
OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });
640
if (Found == std::end(OptionTable) || Found->getName() != Name)
641
return std::nullopt;
642
return static_cast<diag::Group>(Found - OptionTable);
643
}
644
645
std::optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {
646
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
647
return static_cast<diag::Group>(Info->getOptionGroupIndex());
648
return std::nullopt;
649
}
650
651
/// getWarningOptionForDiag - Return the lowest-level warning option that
652
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
653
/// the diagnostic, this returns null.
654
StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
655
if (auto G = getGroupForDiag(DiagID))
656
return getWarningOptionForGroup(*G);
657
return StringRef();
658
}
659
660
std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
661
std::vector<std::string> Res{"-W", "-Wno-"};
662
for (size_t I = 1; DiagGroupNames[I] != '\0';) {
663
std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);
664
I += DiagGroupNames[I] + 1;
665
Res.push_back("-W" + Diag);
666
Res.push_back("-Wno-" + Diag);
667
}
668
669
return Res;
670
}
671
672
/// Return \c true if any diagnostics were found in this group, even if they
673
/// were filtered out due to having the wrong flavor.
674
static bool getDiagnosticsInGroup(diag::Flavor Flavor,
675
const WarningOption *Group,
676
SmallVectorImpl<diag::kind> &Diags) {
677
// An empty group is considered to be a warning group: we have empty groups
678
// for GCC compatibility, and GCC does not have remarks.
679
if (!Group->Members && !Group->SubGroups)
680
return Flavor == diag::Flavor::Remark;
681
682
bool NotFound = true;
683
684
// Add the members of the option diagnostic set.
685
const int16_t *Member = DiagArrays + Group->Members;
686
for (; *Member != -1; ++Member) {
687
if (GetDiagInfo(*Member)->getFlavor() == Flavor) {
688
NotFound = false;
689
Diags.push_back(*Member);
690
}
691
}
692
693
// Add the members of the subgroups.
694
const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
695
for (; *SubGroups != (int16_t)-1; ++SubGroups)
696
NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
697
Diags);
698
699
return NotFound;
700
}
701
702
bool
703
DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
704
SmallVectorImpl<diag::kind> &Diags) const {
705
if (std::optional<diag::Group> G = getGroupForWarningOption(Group))
706
return ::getDiagnosticsInGroup(
707
Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);
708
return true;
709
}
710
711
void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,
712
std::vector<diag::kind> &Diags) {
713
for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
714
if (StaticDiagInfo[i].getFlavor() == Flavor)
715
Diags.push_back(StaticDiagInfo[i].DiagID);
716
}
717
718
StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
719
StringRef Group) {
720
StringRef Best;
721
unsigned BestDistance = Group.size() + 1; // Maximum threshold.
722
for (const WarningOption &O : OptionTable) {
723
// Don't suggest ignored warning flags.
724
if (!O.Members && !O.SubGroups)
725
continue;
726
727
unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
728
if (Distance > BestDistance)
729
continue;
730
731
// Don't suggest groups that are not of this kind.
732
llvm::SmallVector<diag::kind, 8> Diags;
733
if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())
734
continue;
735
736
if (Distance == BestDistance) {
737
// Two matches with the same distance, don't prefer one over the other.
738
Best = "";
739
} else if (Distance < BestDistance) {
740
// This is a better match.
741
Best = O.getName();
742
BestDistance = Distance;
743
}
744
}
745
746
return Best;
747
}
748
749
/// ProcessDiag - This is the method used to report a diagnostic that is
750
/// finally fully formed.
751
bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
752
Diagnostic Info(&Diag);
753
754
assert(Diag.getClient() && "DiagnosticClient not set!");
755
756
// Figure out the diagnostic level of this message.
757
unsigned DiagID = Info.getID();
758
DiagnosticIDs::Level DiagLevel
759
= getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
760
761
// Update counts for DiagnosticErrorTrap even if a fatal error occurred
762
// or diagnostics are suppressed.
763
if (DiagLevel >= DiagnosticIDs::Error) {
764
++Diag.TrapNumErrorsOccurred;
765
if (isUnrecoverable(DiagID))
766
++Diag.TrapNumUnrecoverableErrorsOccurred;
767
}
768
769
if (Diag.SuppressAllDiagnostics)
770
return false;
771
772
if (DiagLevel != DiagnosticIDs::Note) {
773
// Record that a fatal error occurred only when we see a second
774
// non-note diagnostic. This allows notes to be attached to the
775
// fatal error, but suppresses any diagnostics that follow those
776
// notes.
777
if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
778
Diag.FatalErrorOccurred = true;
779
780
Diag.LastDiagLevel = DiagLevel;
781
}
782
783
// If a fatal error has already been emitted, silence all subsequent
784
// diagnostics.
785
if (Diag.FatalErrorOccurred) {
786
if (DiagLevel >= DiagnosticIDs::Error &&
787
Diag.Client->IncludeInDiagnosticCounts()) {
788
++Diag.NumErrors;
789
}
790
791
return false;
792
}
793
794
// If the client doesn't care about this message, don't issue it. If this is
795
// a note and the last real diagnostic was ignored, ignore it too.
796
if (DiagLevel == DiagnosticIDs::Ignored ||
797
(DiagLevel == DiagnosticIDs::Note &&
798
Diag.LastDiagLevel == DiagnosticIDs::Ignored))
799
return false;
800
801
if (DiagLevel >= DiagnosticIDs::Error) {
802
if (isUnrecoverable(DiagID))
803
Diag.UnrecoverableErrorOccurred = true;
804
805
// Warnings which have been upgraded to errors do not prevent compilation.
806
if (isDefaultMappingAsError(DiagID))
807
Diag.UncompilableErrorOccurred = true;
808
809
Diag.ErrorOccurred = true;
810
if (Diag.Client->IncludeInDiagnosticCounts()) {
811
++Diag.NumErrors;
812
}
813
814
// If we've emitted a lot of errors, emit a fatal error instead of it to
815
// stop a flood of bogus errors.
816
if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&
817
DiagLevel == DiagnosticIDs::Error) {
818
Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
819
return false;
820
}
821
}
822
823
// Make sure we set FatalErrorOccurred to ensure that the notes from the
824
// diagnostic that caused `fatal_too_many_errors` won't be emitted.
825
if (Diag.CurDiagID == diag::fatal_too_many_errors)
826
Diag.FatalErrorOccurred = true;
827
// Finally, report it.
828
EmitDiag(Diag, DiagLevel);
829
return true;
830
}
831
832
void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
833
Diagnostic Info(&Diag);
834
assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
835
836
Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
837
if (Diag.Client->IncludeInDiagnosticCounts()) {
838
if (DiagLevel == DiagnosticIDs::Warning)
839
++Diag.NumWarnings;
840
}
841
842
Diag.CurDiagID = ~0U;
843
}
844
845
bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
846
if (DiagID >= diag::DIAG_UPPER_LIMIT) {
847
assert(CustomDiagInfo && "Invalid CustomDiagInfo");
848
// Custom diagnostics.
849
return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
850
}
851
852
// Only errors may be unrecoverable.
853
if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
854
return false;
855
856
if (DiagID == diag::err_unavailable ||
857
DiagID == diag::err_unavailable_message)
858
return false;
859
860
// Currently we consider all ARC errors as recoverable.
861
if (isARCDiagnostic(DiagID))
862
return false;
863
864
if (isCodegenABICheckDiagnostic(DiagID))
865
return false;
866
867
return true;
868
}
869
870
bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
871
unsigned cat = getCategoryNumberForDiag(DiagID);
872
return DiagnosticIDs::getCategoryNameFromID(cat).starts_with("ARC ");
873
}
874
875
bool DiagnosticIDs::isCodegenABICheckDiagnostic(unsigned DiagID) {
876
unsigned cat = getCategoryNumberForDiag(DiagID);
877
return DiagnosticIDs::getCategoryNameFromID(cat) == "Codegen ABI Check";
878
}
879
880