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 98 unsigned getOptionGroupIndex() const { 99 return OptionGroupIndex; 100 } 101 102 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 109 diag::Flavor getFlavor() const { 110 return Class == CLASS_REMARK ? diag::Flavor::Remark 111 : diag::Flavor::WarningOrError; 112 } 113 114 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. 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. 249 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 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 270 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 280 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 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. 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 330 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 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. 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 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 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 377 DiagnosticIDs::DiagnosticIDs() {} 378 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. 387 unsigned DiagnosticIDs::getCustomDiagID(CustomDiagDesc Diag) { 388 if (!CustomDiagInfo) 389 CustomDiagInfo.reset(new diag::CustomDiagInfo()); 390 return CustomDiagInfo->getOrCreateDiagID(Diag); 391 } 392 393 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. 401 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 /// 410 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 420 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. 426 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 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 453 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 467 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 578 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 598 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. 611 StringRef DiagnosticIDs::getWarningOptionDocumentation(diag::Group Group) { 612 return OptionTable[static_cast<int>(Group)].Documentation; 613 } 614 615 StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) { 616 return OptionTable[static_cast<int>(Group)].getName(); 617 } 618 619 std::optional<diag::Group> 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> 629 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. 642 StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { 643 if (auto G = getGroupForDiag(DiagID)) 644 return getWarningOptionForGroup(*G); 645 return StringRef(); 646 } 647 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. 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 698 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> 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> 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 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 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 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 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 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 826 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 849 bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) { 850 unsigned cat = getCategoryNumberForDiag(DiagID); 851 return DiagnosticIDs::getCategoryNameFromID(cat).starts_with("ARC "); 852 } 853 854 bool DiagnosticIDs::isCodegenABICheckDiagnostic(unsigned DiagID) { 855 unsigned cat = getCategoryNumberForDiag(DiagID); 856 return DiagnosticIDs::getCategoryNameFromID(cat) == "Codegen ABI Check"; 857 } 858