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