clang 24.0.0git
DiagnosticIDs.cpp
Go to the documentation of this file.
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
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/ADT/StringTable.h"
21#include "llvm/Support/Compiler.h"
22#include "llvm/Support/ErrorHandling.h"
23#include <map>
24#include <optional>
25using namespace clang;
26
27//===----------------------------------------------------------------------===//
28// Builtin Diagnostic information
29//===----------------------------------------------------------------------===//
30
31namespace {
32
33struct StaticDiagInfoRec;
34
35#define GET_DIAG_STABLE_ID_ARRAYS
36#include "clang/Basic/DiagnosticStableIDs.inc"
37#undef GET_DIAG_STABLE_ID_ARRAYS
38
39extern const StaticDiagInfoRec StaticDiagInfo[];
40
41const uint32_t StaticDiagInfoStableIDOffsets[] = {
42#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
43 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
44 LEGACY_STABLE_IDS) \
45 STABLE_ID,
47#undef DIAG
48};
49
50const uint32_t StaticDiagInfoLegacyStableIDStartOffsets[] = {
51#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
52 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
53 LEGACY_STABLE_IDS) \
54 LEGACY_STABLE_IDS,
56#undef DIAG
57};
58
59enum DiagnosticClass {
60 CLASS_NOTE = DiagnosticIDs::CLASS_NOTE,
61 CLASS_REMARK = DiagnosticIDs::CLASS_REMARK,
62 CLASS_WARNING = DiagnosticIDs::CLASS_WARNING,
63 CLASS_EXTENSION = DiagnosticIDs::CLASS_EXTENSION,
64 CLASS_ERROR = DiagnosticIDs::CLASS_ERROR,
65 CLASS_TRAP = DiagnosticIDs::CLASS_TRAP,
66};
67
68#if defined(_AIX) && (!defined(__GNUC__) || defined(__clang__))
69// Except for GCC; by default, AIX compilers store bit-fields in 4-byte words
70// and give the `pack` pragma push semantics.
71#define BEGIN_TWO_BYTE_PACK() _Pragma("pack(2)")
72#define END_TWO_BYTE_PACK() _Pragma("pack(pop)")
73#else
74#define BEGIN_TWO_BYTE_PACK()
75#define END_TWO_BYTE_PACK()
76#endif
77
79struct StaticDiagInfoRec {
80 uint16_t DiagID;
81 LLVM_PREFERRED_TYPE(diag::Severity)
82 uint16_t DefaultSeverity : 3;
83 LLVM_PREFERRED_TYPE(DiagnosticClass)
84 uint16_t Class : 3;
85 LLVM_PREFERRED_TYPE(DiagnosticIDs::SFINAEResponse)
86 uint16_t SFINAE : 2;
87 LLVM_PREFERRED_TYPE(diag::DiagCategory)
88 uint16_t Category : 6;
89 LLVM_PREFERRED_TYPE(bool)
90 uint16_t WarnNoWerror : 1;
91 LLVM_PREFERRED_TYPE(bool)
92 uint16_t WarnShowInSystemHeader : 1;
93 LLVM_PREFERRED_TYPE(bool)
94 uint16_t WarnShowInSystemMacro : 1;
95
96 LLVM_PREFERRED_TYPE(diag::Group)
97 uint16_t OptionGroupIndex : 14;
98 LLVM_PREFERRED_TYPE(bool)
99 uint16_t Deferrable : 1;
100
101 uint16_t DescriptionOffsetLow : 16;
102 uint16_t DescriptionOffsetHigh : 4;
103 uint16_t DescriptionLen : 12;
104
105 unsigned getOptionGroupIndex() const {
106 return OptionGroupIndex;
107 }
108
109 StringRef getDescription() const {
110 uint32_t Offset =
111 DescriptionOffsetLow | (uint32_t(DescriptionOffsetHigh) << 16);
112 return StringRef(StaticDiagInfoDescriptionsStorage + Offset,
113 DescriptionLen);
114 }
115
116 StringRef getStableID() const {
117 size_t MyIndex = this - &StaticDiagInfo[0];
118 uint32_t StringOffset = StaticDiagInfoStableIDOffsets[MyIndex];
119 return DiagStableIDs[StringOffset];
120 }
121
122 llvm::SmallVector<StringRef, 4> getLegacyStableIDs() const {
124 size_t MyIndex = this - &StaticDiagInfo[0];
125 uint32_t StartOffset = StaticDiagInfoLegacyStableIDStartOffsets[MyIndex];
126 for (uint32_t Offset = StartOffset; DiagLegacyStableIDs[Offset] != 0;
127 ++Offset) {
128 Result.push_back(DiagStableIDs[DiagLegacyStableIDs[Offset]]);
129 }
130
131 return Result;
132 }
133
134 diag::Flavor getFlavor() const {
135 return Class == CLASS_REMARK ? diag::Flavor::Remark
137 }
138
139 bool operator<(const StaticDiagInfoRec &RHS) const {
140 return DiagID < RHS.DiagID;
141 }
142};
144
145#undef BEGIN_TWO_BYTE_PACK
146#undef END_TWO_BYTE_PACK
147
148static_assert(sizeof(StaticDiagInfoRec) == 10);
149static_assert(static_cast<unsigned>(diag::Group::NUM_GROUPS) < (1U << 14),
150 "too many diagnostic groups for StaticDiagInfoRec");
151
152#define STRINGIFY_NAME(NAME) #NAME
153#define VALIDATE_DIAG_SIZE(NAME) \
154 static_assert( \
155 static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
156 static_cast<unsigned>(diag::DIAG_START_##NAME) + \
157 static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
158 STRINGIFY_NAME( \
159 DIAG_SIZE_##NAME) " is insufficient to contain all " \
160 "diagnostics, it may need to be made larger in " \
161 "DiagnosticIDs.h.");
162VALIDATE_DIAG_SIZE(COMMON)
163VALIDATE_DIAG_SIZE(DRIVER)
164VALIDATE_DIAG_SIZE(FRONTEND)
165VALIDATE_DIAG_SIZE(CODEGEN)
166VALIDATE_DIAG_SIZE(SERIALIZATION)
171VALIDATE_DIAG_SIZE(CROSSTU)
173VALIDATE_DIAG_SIZE(ANALYSIS)
174VALIDATE_DIAG_SIZE(REFACTORING)
175VALIDATE_DIAG_SIZE(INSTALLAPI)
177#undef VALIDATE_DIAG_SIZE
178#undef STRINGIFY_NAME
179
180const StaticDiagInfoRec StaticDiagInfo[] = {
181// clang-format off
182#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
183 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
184 LEGACY_STABLE_IDS) \
185 { \
186 diag::ENUM, \
187 DEFAULT_SEVERITY, \
188 CLASS, \
189 DiagnosticIDs::SFINAE, \
190 CATEGORY, \
191 NOWERROR, \
192 SHOWINSYSHEADER, \
193 SHOWINSYSMACRO, \
194 GROUP, \
195 DEFERRABLE, \
196 uint16_t(DIAG_DESC_OFFSET_##ENUM), \
197 uint16_t(DIAG_DESC_OFFSET_##ENUM >> 16), \
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/DiagnosticCodeGenKinds.inc"
203#include "clang/Basic/DiagnosticSerializationKinds.inc"
204#include "clang/Basic/DiagnosticLexKinds.inc"
205#include "clang/Basic/DiagnosticParseKinds.inc"
206#include "clang/Basic/DiagnosticASTKinds.inc"
207#include "clang/Basic/DiagnosticCommentKinds.inc"
208#include "clang/Basic/DiagnosticCrossTUKinds.inc"
209#include "clang/Basic/DiagnosticSemaKinds.inc"
210#include "clang/Basic/DiagnosticAnalysisKinds.inc"
211#include "clang/Basic/DiagnosticRefactoringKinds.inc"
212#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
213#include "clang/Basic/DiagnosticTrapKinds.inc"
214// clang-format on
215#undef DIAG
216};
217
218} // namespace
219
220static const unsigned StaticDiagInfoSize = std::size(StaticDiagInfo);
221
222/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
223/// or null if the ID is invalid.
224static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
225 // Out of bounds diag. Can't be in the table.
226 using namespace diag;
227 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
228 return nullptr;
229
230 // Compute the index of the requested diagnostic in the static table.
231 // 1. Add the number of diagnostics in each category preceding the
232 // diagnostic and of the category the diagnostic is in. This gives us
233 // the offset of the category in the table.
234 // 2. Subtract the number of IDs in each category from our ID. This gives us
235 // the offset of the diagnostic in the category.
236 // This is cheaper than a binary search on the table as it doesn't touch
237 // memory at all.
238 unsigned Offset = 0;
239 unsigned ID = DiagID - DIAG_START_COMMON - 1;
240#define CATEGORY(NAME, PREV) \
241 if (DiagID > DIAG_START_##NAME) { \
242 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
243 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
244 }
245CATEGORY(DRIVER, COMMON)
246CATEGORY(FRONTEND, DRIVER)
247CATEGORY(CODEGEN, FRONTEND)
248CATEGORY(SERIALIZATION, CODEGEN)
249CATEGORY(LEX, SERIALIZATION)
250CATEGORY(PARSE, LEX)
251CATEGORY(AST, PARSE)
252CATEGORY(COMMENT, AST)
253CATEGORY(CROSSTU, COMMENT)
254CATEGORY(SEMA, CROSSTU)
255CATEGORY(ANALYSIS, SEMA)
256CATEGORY(REFACTORING, ANALYSIS)
257CATEGORY(INSTALLAPI, REFACTORING)
258CATEGORY(TRAP, INSTALLAPI)
259#undef CATEGORY
260
261 // Avoid out of bounds reads.
262 if (ID + Offset >= StaticDiagInfoSize)
263 return nullptr;
264
265 assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
266
267 const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
268 // If the diag id doesn't match we found a different diag, abort. This can
269 // happen when this function is called with an ID that points into a hole in
270 // the diagID space.
271 if (Found->DiagID != DiagID)
272 return nullptr;
273 return Found;
274}
275
276//===----------------------------------------------------------------------===//
277// Custom Diagnostic information
278//===----------------------------------------------------------------------===//
279
280namespace clang {
281namespace diag {
284 std::vector<CustomDiagDesc> DiagInfo;
285 std::map<CustomDiagDesc, unsigned> DiagIDs;
286 std::map<diag::Group, std::vector<unsigned>> GroupToDiags;
287
288public:
289 /// getDescription - Return the description of the specified custom
290 /// diagnostic.
291 const CustomDiagDesc &getDescription(unsigned DiagID) const {
292 assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
293 "Invalid diagnostic ID");
294 return DiagInfo[DiagID - DIAG_UPPER_LIMIT];
295 }
296
298 // Check to see if it already exists.
299 std::map<CustomDiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
300 if (I != DiagIDs.end() && I->first == D)
301 return I->second;
302
303 // If not, assign a new ID.
304 unsigned ID = DiagInfo.size() + DIAG_UPPER_LIMIT;
305 DiagIDs.insert(std::make_pair(D, ID));
306 DiagInfo.push_back(D);
307 if (auto Group = D.GetGroup())
308 GroupToDiags[*Group].emplace_back(ID);
309 return ID;
310 }
311
313 if (auto Diags = GroupToDiags.find(G); Diags != GroupToDiags.end())
314 return Diags->second;
315 return {};
316 }
317};
318
319} // namespace diag
320} // namespace clang
321
324 diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
325
326 if (IsCustomDiag(DiagID)) {
327 Info.setSeverity(
328 CustomDiagInfo->getDescription(DiagID).GetDefaultSeverity());
329 } else if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
330 Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
331
332 if (StaticInfo->WarnNoWerror) {
333 assert(Info.getSeverity() == diag::Severity::Warning &&
334 "Unexpected mapping with no-Werror bit!");
335 Info.setNoWarningAsError(true);
336 }
337 }
338
339 return Info;
340}
341
343 unsigned DiagID) {
344 assert(IsCustomDiag(DiagID));
345 const auto &Diag = CustomDiagInfo->getDescription(DiagID);
346 if (auto Group = Diag.GetGroup()) {
347 GroupInfo GroupInfo = GroupInfos[static_cast<size_t>(*Group)];
348 if (static_cast<diag::Severity>(GroupInfo.Severity) != diag::Severity())
349 Mapping.setSeverity(static_cast<diag::Severity>(GroupInfo.Severity));
351 } else {
352 Mapping.setSeverity(Diag.GetDefaultSeverity());
353 Mapping.setNoWarningAsError(true);
354 Mapping.setNoErrorAsFatal(true);
355 }
356}
357
358/// getCategoryNumberForDiag - Return the category number that a specified
359/// DiagID belongs to, or 0 if no category.
361 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
362 return Info->Category;
363 return 0;
364}
365
366namespace {
367 // The diagnostic category names.
368 struct StaticDiagCategoryRec {
369 const char *NameStr;
370 uint8_t NameLen;
371
372 StringRef getName() const {
373 return StringRef(NameStr, NameLen);
374 }
375 };
376}
377
378static const StaticDiagCategoryRec CategoryNameTable[] = {
379#define GET_CATEGORY_TABLE
380#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
381#include "clang/Basic/DiagnosticGroups.inc"
382#undef GET_CATEGORY_TABLE
383 { nullptr, 0 }
384};
385
386/// getNumberOfCategories - Return the number of categories
388 return std::size(CategoryNameTable) - 1;
389}
390
391/// getCategoryNameFromID - Given a category ID, return the name of the
392/// category, an empty string if CategoryID is zero, or null if CategoryID is
393/// invalid.
394StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
395 if (CategoryID >= getNumberOfCategories())
396 return StringRef();
397 return CategoryNameTable[CategoryID].getName();
398}
399
400
401
404 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
405 return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
406 return SFINAE_Report;
407}
408
409bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
410 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
411 return Info->Deferrable;
412 return false;
413}
414
415//===----------------------------------------------------------------------===//
416// Common Diagnostic implementation
417//===----------------------------------------------------------------------===//
418
420
422
423/// getCustomDiagID - Return an ID for a diagnostic with the specified message
424/// and level. If this is the first request for this diagnostic, it is
425/// registered and created, otherwise the existing ID is returned.
426///
427/// \param FormatString A fixed diagnostic format string that will be hashed and
428/// mapped to a unique DiagID.
430 if (!CustomDiagInfo)
431 CustomDiagInfo.reset(new diag::CustomDiagInfo());
432 return CustomDiagInfo->getOrCreateDiagID(Diag);
433}
434
435bool DiagnosticIDs::isWarningOrExtension(unsigned DiagID) const {
436 return DiagID < diag::DIAG_UPPER_LIMIT
437 ? getDiagClass(DiagID) != CLASS_ERROR
438 : CustomDiagInfo->getDescription(DiagID).GetClass() != CLASS_ERROR;
439}
440
441/// Determine whether the given built-in diagnostic ID is a
442/// Note.
443bool DiagnosticIDs::isNote(unsigned DiagID) const {
444 return DiagID < diag::DIAG_UPPER_LIMIT && getDiagClass(DiagID) == CLASS_NOTE;
445}
446
447/// isExtensionDiag - Determine whether the given built-in diagnostic
448/// ID is for an extension of some sort. This also returns EnabledByDefault,
449/// which is set to indicate whether the diagnostic is ignored by default (in
450/// which case -pedantic enables it) or treated as a warning/error by default.
451///
453 bool &EnabledByDefault) const {
454 if (IsCustomDiag(DiagID) || getDiagClass(DiagID) != CLASS_EXTENSION)
455 return false;
456
457 EnabledByDefault =
459 return true;
460}
461
462bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) const {
464}
465
466/// getDescription - Given a diagnostic ID, return a description of the
467/// issue.
468StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
469 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
470 return Info->getDescription();
471 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
472 return CustomDiagInfo->getDescription(DiagID).GetDescription();
473}
474
475/// getStableID - Given a diagnostic ID, return the stable ID of the diagnostic.
476std::string DiagnosticIDs::getStableID(unsigned DiagID) const {
477 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
478 return Info->getStableID().str();
479 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
480 // TODO: Stable IDs for custom diagnostics?
481 // If we have to go through every custom diagnostic and add a stable ID, we
482 // should instead just go replace them all with declared diagnostics.
483 return std::to_string(DiagID);
484}
485
486/// getLegacyStableIDs - Given a diagnostic ID, return the previous stable IDs
487/// of the diagnostic.
489DiagnosticIDs::getLegacyStableIDs(unsigned DiagID) const {
490 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
491 return Info->getLegacyStableIDs();
492 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
493 // TODO: Stable IDs for custom diagnostics?
494 // If we have to go through every custom diagnostic and add a stable ID, we
495 // should instead just go replace them all with declared diagnostics.
496 return {};
497}
498
500 switch (SV) {
511 }
512 llvm_unreachable("unexpected severity");
513}
514
515/// getDiagnosticLevel - Based on the way the client configured the
516/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
517/// by consumable the DiagnosticClient.
519DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
520 const DiagnosticsEngine &Diag) const {
521 unsigned DiagClass = getDiagClass(DiagID);
522 if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
523 return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
524}
525
526/// Based on the way the client configured the Diagnostic
527/// object, classify the specified diagnostic ID into a Level, consumable by
528/// the DiagnosticClient.
529///
530/// \param Loc The source location we are interested in finding out the
531/// diagnostic state. Can be null in order to query the latest state.
533DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
534 const DiagnosticsEngine &Diag) const {
535 return getDiagnosticListHighestSeverity({DiagID}, Loc, Diag);
536}
537
538diag::Severity DiagnosticIDs::getDiagnosticListHighestSeverity(
540 const DiagnosticsEngine &Diag) const {
541 DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
542
543 auto checkSingleDiag = [&](diag::kind DiagID) -> diag::Severity {
545 assert(getDiagClass(DiagID) != CLASS_NOTE);
546
547 // Specific non-error diagnostics may be mapped to various levels from
548 // ignored to error. Errors can only be mapped to fatal.
550
551 // Get the mapping information, or compute it lazily.
552 DiagnosticMapping Mapping = State->getOrAddMapping((diag::kind)DiagID);
553
554 // TODO: Can a null severity really get here?
555 if (Mapping.getSeverity() != diag::Severity())
556 Result = Mapping.getSeverity();
557
558 // Upgrade ignored diagnostics if -Weverything is enabled.
559 if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
560 !Mapping.isUser() &&
561 (IsCustomDiag || getDiagClass(DiagID) != CLASS_REMARK))
563
564 // Ignore -pedantic diagnostics inside __extension__ blocks.
565 // (The diagnostics controlled by -pedantic are the extension diagnostics
566 // that are not enabled by default.)
567 bool EnabledByDefault = false;
568 bool IsExtensionDiag = isExtensionDiag(DiagID, EnabledByDefault);
569 if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
571
572 // For extension diagnostics that haven't been explicitly mapped, check if
573 // we should upgrade the diagnostic. Skip if the user explicitly
574 // suppressed it (e.g. -Wno-foo).
575 if (IsExtensionDiag &&
576 !(Mapping.isUser() && Result == diag::Severity::Ignored)) {
577 if (Mapping.hasNoWarningAsError())
578 Result = std::max(
579 Result, std::min(State->ExtBehavior, diag::Severity::Warning));
580 else
581 Result = std::max(Result, State->ExtBehavior);
582 }
583
584 // At this point, ignored errors can no longer be upgraded.
586 return Result;
587
588 // Honor -w: this disables all messages which are not Error/Fatal by
589 // default (disregarding attempts to upgrade severity from Warning to
590 // Error), as well as disabling all messages which are currently mapped to
591 // Warning (whether by default or downgraded from Error via e.g.
592 // -Wno-error or #pragma diagnostic.)
593 // FIXME: Should -w be ignored for custom warnings without a group?
594 if (State->IgnoreAllWarnings) {
595 if ((!IsCustomDiag ||
596 CustomDiagInfo->getDescription(DiagID).GetGroup()) &&
601 }
602
603 // If -Werror is enabled, map warnings to errors unless explicitly
604 // disabled.
606 if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
608 }
609
610 // If -Wfatal-errors is enabled, map errors to fatal unless explicitly
611 // disabled.
613 if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
615 }
616
617 // If explicitly requested, map fatal errors to errors.
619 DiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)
621
622 // Rest of the mappings are only applicable for diagnostics associated
623 // with a SourceLocation, bail out early for others.
624 if (!Diag.hasSourceManager())
625 return Result;
626
627 // We check both the location-specific state and the ForceSystemWarnings
628 // override. In some cases (like template instantiations from system
629 // modules), the location-specific state might have suppression enabled,
630 // but the engine might have an override (e.g.
631 // AllowWarningInSystemHeaders) to show the warning.
632 if (State->SuppressSystemWarnings && !Diag.getForceSystemWarnings() &&
633 shouldSuppressAsSystemWarning(DiagID, Loc, Diag)) {
635 }
636
637 // Clang-diagnostics pragmas always take precedence over suppression
638 // mapping.
639 if (!Mapping.isPragma() && Diag.isSuppressedViaMapping(DiagID, Loc))
641
642 return Result;
643 };
644
645 diag::Severity CompositeResult = diag::Severity::Ignored;
646 for (diag::kind DiagID : DiagIDs) {
647 CompositeResult = std::max(CompositeResult, checkSingleDiag(DiagID));
648
649 // If we already hit 'fatal', we can't get any higher! So just return that.
650 // We could potentially short-cut this by taking a parameter for "return
651 // first greater than", but since our uses of this are fairly small, and
652 // that only optimizes for the "we are about to do something expensive
653 // anyway" variant (that is, when everything is NOT ignored), it doesn't
654 // seem particularly valuable.
655 if (CompositeResult == diag::Severity::Fatal)
656 break;
657 }
658
659 return CompositeResult;
660}
661
663 unsigned DiagID, SourceLocation Loc, const DiagnosticsEngine &Diag) const {
664 if (!Loc.isValid())
665 return false;
666
668 const auto &SM = Diag.getSourceManager();
669
670 // If we are in a system header, we ignore it.
671 if (SM.isInSystemHeader(SM.getExpansionLoc(Loc))) {
672 bool ShowInSystemHeader = true;
673 if (IsCustomDiag)
674 ShowInSystemHeader =
675 CustomDiagInfo->getDescription(DiagID).ShouldShowInSystemHeader();
676 else if (const StaticDiagInfoRec *Rec = GetDiagInfo(DiagID))
677 ShowInSystemHeader = Rec->WarnShowInSystemHeader;
678
679 if (!ShowInSystemHeader)
680 return true;
681 }
682 // We also ignore warnings due to system macros.
683 if (Loc.isValid()) {
684 bool ShowInSystemMacro = true;
685
686 // FIXME: Respect the "show in system macro" information in the
687 // CustomDiagInfo (which is currently ignored).
688
689 if (const StaticDiagInfoRec *Rec = GetDiagInfo(DiagID))
690 ShowInSystemMacro = Rec->WarnShowInSystemMacro;
691
692 if (!ShowInSystemMacro && SM.isInSystemMacro(Loc))
693 return true;
694 }
695 return false;
696}
697
698DiagnosticIDs::Class DiagnosticIDs::getDiagClass(unsigned DiagID) const {
699 if (IsCustomDiag(DiagID))
700 return Class(CustomDiagInfo->getDescription(DiagID).GetClass());
701
702 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
703 return Class(Info->Class);
704 return CLASS_INVALID;
705}
706
707#define GET_DIAG_ARRAYS
708#include "clang/Basic/DiagnosticGroups.inc"
709#undef GET_DIAG_ARRAYS
710
711namespace {
712 struct WarningOption {
713 uint16_t NameOffset;
714 uint16_t Members;
715 uint16_t SubGroups;
716 StringRef Documentation;
717
718 StringRef getName() const { return DiagGroupNames[NameOffset]; }
719 };
720}
721
722// Second the table of options, sorted by name for fast binary lookup.
723static const WarningOption OptionTable[] = {
724#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
725 {FlagNameOffset, Members, SubGroups, Docs},
726#include "clang/Basic/DiagnosticGroups.inc"
727#undef DIAG_ENTRY
728};
729
730/// Given a diagnostic group ID, return its documentation.
732 return OptionTable[static_cast<int>(Group)].Documentation;
733}
734
736 return OptionTable[static_cast<int>(Group)].getName();
737}
738
739std::optional<diag::Group>
741 const auto *Found = llvm::partition_point(
742 OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });
743 if (Found == std::end(OptionTable) || Found->getName() != Name)
744 return std::nullopt;
745 return static_cast<diag::Group>(Found - OptionTable);
746}
747
748std::optional<diag::Group>
749DiagnosticIDs::getGroupForDiag(unsigned DiagID) const {
750 if (IsCustomDiag(DiagID)) {
751 assert(CustomDiagInfo);
752 return CustomDiagInfo->getDescription(DiagID).GetGroup();
753 }
754 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
755 return static_cast<diag::Group>(Info->getOptionGroupIndex());
756 return std::nullopt;
757}
758
759/// getWarningOptionForDiag - Return the lowest-level warning option that
760/// enables the specified diagnostic. If there is no -Wfoo flag that controls
761/// the diagnostic, this returns null.
762StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
763 if (auto G = getGroupForDiag(DiagID))
764 return getWarningOptionForGroup(*G);
765 return StringRef();
766}
767
768std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
769 std::vector<std::string> Res{"-W", "-Wno-"};
770 for (StringRef Name : DiagGroupNames) {
771 if (Name.empty())
772 continue;
773
774 Res.push_back((Twine("-W") + Name).str());
775 Res.push_back((Twine("-Wno-") + Name).str());
776 }
777
778 return Res;
779}
780
781/// Return \c true if any diagnostics were found in this group, even if they
782/// were filtered out due to having the wrong flavor.
784 const WarningOption *Group,
786 diag::CustomDiagInfo *CustomDiagInfo) {
787 // An empty group is considered to be a warning group: we have empty groups
788 // for GCC compatibility, and GCC does not have remarks.
789 if (!Group->Members && !Group->SubGroups)
790 return Flavor == diag::Flavor::Remark;
791
792 bool NotFound = true;
793
794 // Add the members of the option diagnostic set.
795 const int16_t *Member = DiagArrays + Group->Members;
796 for (; *Member != -1; ++Member) {
797 if (GetDiagInfo(*Member)->getFlavor() == Flavor) {
798 NotFound = false;
799 Diags.push_back(*Member);
800 }
801 }
802
803 // Add the members of the subgroups.
804 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
805 for (; *SubGroups != (int16_t)-1; ++SubGroups) {
806 if (CustomDiagInfo)
807 llvm::copy(
808 CustomDiagInfo->getDiagsInGroup(static_cast<diag::Group>(*SubGroups)),
809 std::back_inserter(Diags));
810 NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
811 Diags, CustomDiagInfo);
812 }
813
814 return NotFound;
815}
816
817bool
819 SmallVectorImpl<diag::kind> &Diags) const {
820 if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
821 if (CustomDiagInfo)
822 llvm::copy(CustomDiagInfo->getDiagsInGroup(*G),
823 std::back_inserter(Diags));
824 return ::getDiagnosticsInGroup(Flavor,
825 &OptionTable[static_cast<unsigned>(*G)],
826 Diags, CustomDiagInfo.get());
827 }
828 return true;
829}
830
831template <class Func>
832static void forEachSubGroupImpl(const WarningOption *Group, Func func) {
833 for (const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
834 *SubGroups != -1; ++SubGroups) {
835 func(static_cast<size_t>(*SubGroups));
836 forEachSubGroupImpl(&OptionTable[*SubGroups], func);
837 }
838}
839
840template <class Func>
841static void forEachSubGroup(diag::Group Group, Func func) {
842 const WarningOption *WarningOpt = &OptionTable[static_cast<size_t>(Group)];
843 func(static_cast<size_t>(Group));
844 ::forEachSubGroupImpl(WarningOpt, std::move(func));
845}
846
848 if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
849 ::forEachSubGroup(*G, [&](size_t SubGroup) {
850 GroupInfos[SubGroup].Severity = static_cast<unsigned>(Sev);
851 });
852 }
853}
854
855void DiagnosticIDs::setGroupNoWarningsAsError(StringRef Group, bool Val) {
856 if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
857 ::forEachSubGroup(*G, [&](size_t SubGroup) {
858 GroupInfos[static_cast<size_t>(*G)].HasNoWarningAsError = Val;
859 });
860 }
861}
862
864 std::vector<diag::kind> &Diags) {
865 for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
866 if (StaticDiagInfo[i].getFlavor() == Flavor)
867 Diags.push_back(StaticDiagInfo[i].DiagID);
868}
869
871 StringRef Group) {
872 StringRef Best;
873 unsigned BestDistance = Group.size() + 1; // Maximum threshold.
874 for (const WarningOption &O : OptionTable) {
875 // Don't suggest ignored warning flags.
876 if (!O.Members && !O.SubGroups)
877 continue;
878
879 unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
880 if (Distance > BestDistance)
881 continue;
882
883 // Don't suggest groups that are not of this kind.
885 if (::getDiagnosticsInGroup(Flavor, &O, Diags, nullptr) || Diags.empty())
886 continue;
887
888 if (Distance == BestDistance) {
889 // Two matches with the same distance, don't prefer one over the other.
890 Best = "";
891 } else if (Distance < BestDistance) {
892 // This is a better match.
893 Best = O.getName();
894 BestDistance = Distance;
895 }
896 }
897
898 return Best;
899}
900
902 unsigned CompatDiagId) {
903 struct CompatDiag {
904 unsigned StdVer;
905 unsigned DiagId;
906 unsigned PreDiagId;
907 };
908
909 // We encode the standard version such that C++98 < C++11 < C++14 etc. The
910 // actual numbers don't really matter for this, but the definitions of the
911 // compat diags in the Tablegen file use the standard version number (i.e.
912 // 98, 11, 14, etc.), so we base the encoding here on that.
913 //
914 // Likewise, for C, we have C99 < C11 < C17 < C23 < C29.
915 //
916 // We do end up with some overlap between C and C++ here, e.g. 2011 is used
917 // for both C11 and C++11, but this doesn't matter since we're never in e.g.
918 // C11 and C++11 mode at the same time (additionally, we should only ever
919 // be issuing C compatibility diagnostics in C mode and likewise for C++).
920#define DIAG_COMPAT_IDS_BEGIN()
921#define DIAG_COMPAT_IDS_END()
922#define DIAG_COMPAT_ID(Value, Name, Std, Diag, DiagPre) \
923 {Std >= 98 ? 1900 + Std : 2000 + Std, diag::Diag, diag::DiagPre},
924 static constexpr CompatDiag Diags[]{
925#include "clang/Basic/DiagnosticAllCompatIDs.inc"
926 };
927#undef DIAG_COMPAT_ID
928#undef DIAG_COMPAT_IDS_BEGIN
929#undef DIAG_COMPAT_IDS_END
930
931 assert(CompatDiagId < std::size(Diags) && "Invalid compat diag id");
932
933 unsigned StdVer = [&] {
934 if (!LangOpts.CPlusPlus) {
935 if (LangOpts.C2y)
936 return 2029;
937 if (LangOpts.C23)
938 return 2023;
939 if (LangOpts.C17)
940 return 2017;
941 if (LangOpts.C11)
942 return 2011;
943 if (LangOpts.C99)
944 return 1999;
945 return 1989;
946 }
947
948 if (LangOpts.CPlusPlus29)
949 return 2029;
950 if (LangOpts.CPlusPlus26)
951 return 2026;
952 if (LangOpts.CPlusPlus23)
953 return 2023;
954 if (LangOpts.CPlusPlus20)
955 return 2020;
956 if (LangOpts.CPlusPlus17)
957 return 2017;
958 if (LangOpts.CPlusPlus14)
959 return 2014;
960 if (LangOpts.CPlusPlus11)
961 return 2011;
962 return 1998;
963 }();
964
965 const CompatDiag &D = Diags[CompatDiagId];
966 return StdVer >= D.StdVer ? D.DiagId : D.PreDiagId;
967}
968
969bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
970 // Only errors may be unrecoverable.
971 if (getDiagClass(DiagID) < CLASS_ERROR)
972 return false;
973
974 if (DiagID == diag::err_unavailable ||
975 DiagID == diag::err_unavailable_message)
976 return false;
977
978 // All ARC errors are currently considered recoverable, with the exception of
979 // the following errors:
980 // - err_arc_may_not_respond: sending a message with an unknown selector could
981 // lead to crashes within CodeGen if the resulting expression is used to
982 // initialize a C++ auto variable, where type deduction is required.
983 // - err_arc_atomic_ownership: CodeGen hits llvm_unreachable on the invalid
984 // atomic builtin call.
985 // - err_arc_bridge_cast_incompatible: the failed cast leaves a
986 // value-dependent RecoveryExpr that crashes CodeGen when it is used in a
987 // condition or comparison.
988 if (isARCDiagnostic(DiagID) && DiagID != diag::err_arc_may_not_respond &&
989 DiagID != diag::err_arc_atomic_ownership &&
990 DiagID != diag::err_arc_bridge_cast_incompatible)
991 return false;
992
993 if (isCodegenABICheckDiagnostic(DiagID))
994 return false;
995
996 return true;
997}
998
999bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
1000 unsigned cat = getCategoryNumberForDiag(DiagID);
1001 return DiagnosticIDs::getCategoryNameFromID(cat).starts_with("ARC ");
1002}
1003
1005 unsigned cat = getCategoryNumberForDiag(DiagID);
1006 return DiagnosticIDs::getCategoryNameFromID(cat) == "Codegen ABI Check";
1007}
Includes all the separate Diagnostic headers & some related helpers.
#define COMMENT(CLASS, PARENT)
Definition Comment.h:55
static const StaticDiagInfoRec * GetDiagInfo(unsigned DiagID)
GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, or null if the ID is inval...
static bool getDiagnosticsInGroup(diag::Flavor Flavor, const WarningOption *Group, SmallVectorImpl< diag::kind > &Diags, diag::CustomDiagInfo *CustomDiagInfo)
Return true if any diagnostics were found in this group, even if they were filtered out due to having...
#define END_TWO_BYTE_PACK()
static DiagnosticIDs::Level toLevel(diag::Severity SV)
static void forEachSubGroupImpl(const WarningOption *Group, Func func)
#define BEGIN_TWO_BYTE_PACK()
#define VALIDATE_DIAG_SIZE(NAME)
#define CATEGORY(NAME, PREV)
static const unsigned StaticDiagInfoSize
static const WarningOption OptionTable[]
static const StaticDiagCategoryRec CategoryNameTable[]
static void forEachSubGroup(diag::Group Group, Func func)
Defines the Diagnostic IDs-related interfaces.
Result
Implement __builtin_bit_cast and related operations.
Defines the clang::LangOptions interface.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Defines the SourceManager interface.
std::optional< diag::Group > GetGroup() const
void initCustomDiagMapping(DiagnosticMapping &, unsigned DiagID)
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
static unsigned getNumberOfCategories()
Return the number of diagnostic categories.
static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group)
Get the diagnostic option with the closest edit distance to the given group name.
bool getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, SmallVectorImpl< diag::kind > &Diags) const
Get the set of all diagnostic IDs in the group with the given name.
static std::vector< std::string > getDiagnosticFlags()
Get the string of all diagnostic flags.
bool isWarningOrExtension(unsigned DiagID) const
Return true if the unmapped diagnostic levelof the specified diagnostic ID is a Warning or Extension.
void setGroupSeverity(StringRef Group, diag::Severity)
bool isExtensionDiag(unsigned DiagID) const
Determine whether the given diagnostic ID is for an extension of some sort.
DiagnosticMapping getDefaultMapping(unsigned DiagID) const
Get the default mapping for this diagnostic.
std::string getStableID(unsigned DiagID) const
Given a diagnostic ID, return the stable ID of the diagnostic.
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID)
Determines whether the given built-in diagnostic ID is for an error that is suppressed if it occurs d...
bool shouldSuppressAsSystemWarning(unsigned DiagID, SourceLocation Loc, const DiagnosticsEngine &Diag) const
Return true if either of the following two conditions hold:
bool isDefaultMappingAsError(unsigned DiagID) const
Return true if the specified diagnostic is mapped to errors by default.
void setGroupNoWarningsAsError(StringRef Group, bool)
static bool isCodegenABICheckDiagnostic(unsigned DiagID)
Return true if a given diagnostic is a codegen-time ABI check.
StringRef getDescription(unsigned DiagID) const
Given a diagnostic ID, return a description of the issue.
SFINAEResponse
Enumeration describing how the emission of a diagnostic should be treated when it occurs during C++ t...
@ SFINAE_Report
The diagnostic should be reported.
bool isNote(unsigned DiagID) const
Determine whether the given diagnostic ID is a Note.
StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
static StringRef getWarningOptionDocumentation(diag::Group GroupID)
Given a diagnostic group ID, return its documentation.
static std::optional< diag::Group > getGroupForWarningOption(StringRef)
Given a group ID, returns the flag that toggles the group.
friend class DiagnosticsEngine
static bool IsCustomDiag(diag::kind Diag)
static unsigned getCompatDiagId(const LangOptions &LangOpts, unsigned CompatDiagId)
Get the appropriate diagnostic Id to use for issuing a compatibility diagnostic.
unsigned getCustomDiagID(CustomDiagDesc Diag)
Return an ID for a diagnostic with the specified format string and level.
Level
The level of the diagnostic, after it has been through mapping.
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
static StringRef getWarningOptionForGroup(diag::Group)
Given a group ID, returns the flag that toggles the group.
static bool isARCDiagnostic(unsigned DiagID)
Return true if a given diagnostic falls into an ARC diagnostic category.
static void getAllDiagnostics(diag::Flavor Flavor, std::vector< diag::kind > &Diags)
Get the set of all diagnostic IDs.
std::optional< diag::Group > getGroupForDiag(unsigned DiagID) const
Return the lowest-level group that contains the specified diagnostic.
static bool isDeferrable(unsigned DiagID)
Whether the diagnostic message can be deferred.
llvm::SmallVector< StringRef, 4 > getLegacyStableIDs(unsigned DiagID) const
Given a diagnostic ID, return the previous stable IDs of the diagnostic.
void setNoWarningAsError(bool Value)
void setSeverity(diag::Severity Value)
diag::Severity getSeverity() const
static DiagnosticMapping Make(diag::Severity Severity, bool IsUser, bool IsPragma)
void setNoErrorAsFatal(bool Value)
bool hasNoWarningAsError() const
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:241
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
unsigned getOrCreateDiagID(DiagnosticIDs::CustomDiagDesc D)
const CustomDiagDesc & getDescription(unsigned DiagID) const
getDescription - Return the description of the specified custom diagnostic.
ArrayRef< unsigned > getDiagsInGroup(diag::Group G) const
DiagnosticIDs::CustomDiagDesc CustomDiagDesc
Flavor
Flavors of diagnostics we can emit.
@ WarningOrError
A diagnostic that indicates a problem or potential problem.
@ Remark
A diagnostic that indicates normal progress through compilation.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...
@ Warning
Present this diagnostic as a warning.
@ Fatal
Present this diagnostic as a fatal error.
@ Error
Present this diagnostic as an error.
@ Remark
Present this diagnostic as a remark.
@ Ignored
Do not present this diagnostic, ignore it.
Top level wrappers for InstallAPI frontend operations.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
@ Result
The result type of a method or function.
Definition TypeBase.h:906
__builtin_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 __builtin_riscv_mqwacc_i64 __packed_splat4 uint16_t
__builtin_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 __builtin_riscv_mqwacc_i64 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 int16_t