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"
33struct StaticDiagInfoRec;
35#define GET_DIAG_STABLE_ID_ARRAYS
36#include "clang/Basic/DiagnosticStableIDs.inc"
37#undef GET_DIAG_STABLE_ID_ARRAYS
42struct StaticDiagInfoDescriptionStringTable {
43#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
44 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
46 char ENUM##_desc[sizeof(DESC)];
51const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
52#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
53 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
60extern const StaticDiagInfoRec StaticDiagInfo[];
64const uint32_t StaticDiagInfoDescriptionOffsets[] = {
65#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
66 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
68 offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),
73const uint32_t StaticDiagInfoStableIDOffsets[] = {
74#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
75 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
82const uint32_t StaticDiagInfoLegacyStableIDStartOffsets[] = {
83#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
84 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
100struct StaticDiagInfoRec {
103 uint16_t DefaultSeverity : 3;
104 LLVM_PREFERRED_TYPE(DiagnosticClass)
109 uint16_t Category : 6;
110 LLVM_PREFERRED_TYPE(
bool)
111 uint16_t WarnNoWerror : 1;
112 LLVM_PREFERRED_TYPE(
bool)
113 uint16_t WarnShowInSystemHeader : 1;
114 LLVM_PREFERRED_TYPE(
bool)
115 uint16_t WarnShowInSystemMacro : 1;
118 uint16_t OptionGroupIndex : 15;
119 LLVM_PREFERRED_TYPE(
bool)
120 uint16_t Deferrable : 1;
122 uint16_t DescriptionLen;
124 unsigned getOptionGroupIndex()
const {
125 return OptionGroupIndex;
128 StringRef getDescription()
const {
129 size_t MyIndex =
this - &StaticDiagInfo[0];
130 uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];
131 const char* Table =
reinterpret_cast<const char*
>(&StaticDiagInfoDescriptions);
132 return StringRef(&Table[StringOffset], DescriptionLen);
135 StringRef getStableID()
const {
136 size_t MyIndex =
this - &StaticDiagInfo[0];
137 uint32_t StringOffset = StaticDiagInfoStableIDOffsets[MyIndex];
138 return DiagStableIDs[StringOffset];
141 llvm::SmallVector<StringRef, 4> getLegacyStableIDs()
const {
142 llvm::SmallVector<StringRef, 4>
Result;
143 size_t MyIndex =
this - &StaticDiagInfo[0];
144 uint32_t StartOffset = StaticDiagInfoLegacyStableIDStartOffsets[MyIndex];
145 for (uint32_t Offset = StartOffset; DiagLegacyStableIDs[Offset] != 0;
147 Result.push_back(DiagStableIDs[DiagLegacyStableIDs[Offset]]);
154 return Class == CLASS_REMARK ? diag::Flavor::Remark
155 : diag::Flavor::WarningOrError;
158 bool operator<(
const StaticDiagInfoRec &RHS)
const {
159 return DiagID < RHS.DiagID;
163#define STRINGIFY_NAME(NAME) #NAME
164#define VALIDATE_DIAG_SIZE(NAME) \
166 static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
167 static_cast<unsigned>(diag::DIAG_START_##NAME) + \
168 static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
170 DIAG_SIZE_##NAME) " is insufficient to contain all " \
171 "diagnostics, it may need to be made larger in " \
187#undef VALIDATE_DIAG_SIZE
190const StaticDiagInfoRec StaticDiagInfo[] = {
192#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
193 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
199 DiagnosticIDs::SFINAE, \
206 STR_SIZE(DESC, uint16_t)},
207#include "clang/Basic/DiagnosticCommonKinds.inc"
208#include "clang/Basic/DiagnosticDriverKinds.inc"
209#include "clang/Basic/DiagnosticFrontendKinds.inc"
210#include "clang/Basic/DiagnosticSerializationKinds.inc"
211#include "clang/Basic/DiagnosticLexKinds.inc"
212#include "clang/Basic/DiagnosticParseKinds.inc"
213#include "clang/Basic/DiagnosticASTKinds.inc"
214#include "clang/Basic/DiagnosticCommentKinds.inc"
215#include "clang/Basic/DiagnosticCrossTUKinds.inc"
216#include "clang/Basic/DiagnosticSemaKinds.inc"
217#include "clang/Basic/DiagnosticAnalysisKinds.inc"
218#include "clang/Basic/DiagnosticRefactoringKinds.inc"
219#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
220#include "clang/Basic/DiagnosticTrapKinds.inc"
233 using namespace diag;
234 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
246 unsigned ID = DiagID - DIAG_START_COMMON - 1;
247#define CATEGORY(NAME, PREV) \
248 if (DiagID > DIAG_START_##NAME) { \
249 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
250 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
273 const StaticDiagInfoRec *
Found = &StaticDiagInfo[ID + Offset];
277 if (
Found->DiagID != DiagID)
290 std::vector<CustomDiagDesc> DiagInfo;
291 std::map<CustomDiagDesc, unsigned> DiagIDs;
292 std::map<diag::Group, std::vector<unsigned>> GroupToDiags;
299 "Invalid diagnostic ID");
305 std::map<CustomDiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
306 if (I != DiagIDs.end() && I->first == D)
311 DiagIDs.insert(std::make_pair(D, ID));
312 DiagInfo.push_back(D);
314 GroupToDiags[*
Group].emplace_back(ID);
319 if (
auto Diags = GroupToDiags.find(G); Diags != GroupToDiags.end())
320 return Diags->second;
334 CustomDiagInfo->getDescription(DiagID).GetDefaultSeverity());
335 }
else if (
const StaticDiagInfoRec *StaticInfo =
GetDiagInfo(DiagID)) {
338 if (StaticInfo->WarnNoWerror) {
340 "Unexpected mapping with no-Werror bit!");
351 const auto &
Diag = CustomDiagInfo->getDescription(DiagID);
352 if (
auto Group =
Diag.GetGroup()) {
367 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
368 return Info->Category;
374 struct StaticDiagCategoryRec {
378 StringRef getName()
const {
379 return StringRef(NameStr, NameLen);
385#define GET_CATEGORY_TABLE
386#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
387#include "clang/Basic/DiagnosticGroups.inc"
388#undef GET_CATEGORY_TABLE
410 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
416 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
417 return Info->Deferrable;
438 return CustomDiagInfo->getOrCreateDiagID(
Diag);
444 : CustomDiagInfo->getDescription(DiagID).GetClass() !=
CLASS_ERROR;
459 bool &EnabledByDefault)
const {
475 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
476 return Info->getDescription();
477 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
478 return CustomDiagInfo->getDescription(DiagID).GetDescription();
483 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
484 return Info->getStableID().str();
485 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
489 return std::to_string(DiagID);
496 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
497 return Info->getLegacyStableIDs();
498 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
518 llvm_unreachable(
"unexpected severity");
525DiagnosticIDs::getDiagnosticLevel(
unsigned DiagID,
SourceLocation Loc,
527 unsigned DiagClass = getDiagClass(DiagID);
529 return toLevel(getDiagnosticSeverity(DiagID, Loc,
Diag));
539DiagnosticIDs::getDiagnosticSeverity(
unsigned DiagID,
SourceLocation Loc,
549 DiagnosticsEngine::DiagState *State =
Diag.GetDiagStateForLoc(Loc);
550 DiagnosticMapping Mapping = State->getOrAddMapping((
diag::kind)DiagID);
565 bool EnabledByDefault =
false;
567 if (
Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
573 if (IsExtensionDiag &&
592 if (State->IgnoreAllWarnings) {
593 if ((!
IsCustomDiag || CustomDiagInfo->getDescription(DiagID).GetGroup()) &&
615 DiagID != diag::fatal_too_many_errors &&
Diag.FatalsAsError)
620 if (!
Diag.hasSourceManager())
628 if (State->SuppressSystemWarnings && !
Diag.getForceSystemWarnings() &&
634 if (!Mapping.
isPragma() &&
Diag.isSuppressedViaMapping(DiagID, Loc))
646 const auto &
SM =
Diag.getSourceManager();
649 if (
SM.isInSystemHeader(
SM.getExpansionLoc(Loc))) {
650 bool ShowInSystemHeader =
true;
653 CustomDiagInfo->getDescription(DiagID).ShouldShowInSystemHeader();
654 else if (
const StaticDiagInfoRec *Rec =
GetDiagInfo(DiagID))
655 ShowInSystemHeader = Rec->WarnShowInSystemHeader;
657 if (!ShowInSystemHeader)
662 bool ShowInSystemMacro =
true;
667 if (
const StaticDiagInfoRec *Rec =
GetDiagInfo(DiagID))
668 ShowInSystemMacro = Rec->WarnShowInSystemMacro;
670 if (!ShowInSystemMacro &&
SM.isInSystemMacro(Loc))
678 return Class(CustomDiagInfo->getDescription(DiagID).GetClass());
680 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
681 return Class(Info->Class);
685#define GET_DIAG_ARRAYS
686#include "clang/Basic/DiagnosticGroups.inc"
687#undef GET_DIAG_ARRAYS
690 struct WarningOption {
694 StringRef Documentation;
696 StringRef getName()
const {
return DiagGroupNames[NameOffset]; }
702#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
703 {FlagNameOffset, Members, SubGroups, Docs},
704#include "clang/Basic/DiagnosticGroups.inc"
710 return OptionTable[
static_cast<int>(Group)].Documentation;
714 return OptionTable[
static_cast<int>(Group)].getName();
717std::optional<diag::Group>
719 const auto *
Found = llvm::partition_point(
720 OptionTable, [=](
const WarningOption &O) {
return O.getName() < Name; });
726std::optional<diag::Group>
729 assert(CustomDiagInfo);
730 return CustomDiagInfo->getDescription(DiagID).GetGroup();
732 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
733 return static_cast<diag::Group>(Info->getOptionGroupIndex());
747 std::vector<std::string> Res{
"-W",
"-Wno-"};
748 for (StringRef Name : DiagGroupNames) {
752 Res.push_back((Twine(
"-W") + Name).str());
753 Res.push_back((Twine(
"-Wno-") + Name).str());
762 const WarningOption *Group,
767 if (!Group->Members && !Group->SubGroups)
773 const int16_t *
Member = DiagArrays + Group->Members;
782 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
783 for (; *SubGroups != (int16_t)-1; ++SubGroups) {
787 std::back_inserter(Diags));
789 Diags, CustomDiagInfo);
800 llvm::copy(CustomDiagInfo->getDiagsInGroup(*G),
801 std::back_inserter(Diags));
802 return ::getDiagnosticsInGroup(Flavor,
804 Diags, CustomDiagInfo.get());
811 for (
const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
812 *SubGroups != -1; ++SubGroups) {
813 func(
static_cast<size_t>(*SubGroups));
820 const WarningOption *WarningOpt = &
OptionTable[
static_cast<size_t>(Group)];
821 func(
static_cast<size_t>(Group));
828 GroupInfos[SubGroup].Severity =
static_cast<unsigned>(Sev);
836 GroupInfos[
static_cast<size_t>(*G)].HasNoWarningAsError = Val;
842 std::vector<diag::kind> &Diags) {
844 if (StaticDiagInfo[i].getFlavor() == Flavor)
845 Diags.push_back(StaticDiagInfo[i].DiagID);
851 unsigned BestDistance = Group.size() + 1;
854 if (!O.Members && !O.SubGroups)
857 unsigned Distance = O.getName().edit_distance(Group,
true, BestDistance);
858 if (Distance > BestDistance)
866 if (Distance == BestDistance) {
869 }
else if (Distance < BestDistance) {
872 BestDistance = Distance;
880 unsigned CompatDiagId) {
891#define DIAG_COMPAT_IDS_BEGIN()
892#define DIAG_COMPAT_IDS_END()
893#define DIAG_COMPAT_ID(Value, Name, Std, Diag, DiagPre) \
894 {Std == 98 ? 1998 : 2000 + Std, diag::Diag, diag::DiagPre},
895 static constexpr CompatDiag Diags[]{
896#include "clang/Basic/DiagnosticAllCompatIDs.inc"
899#undef DIAG_COMPAT_IDS_BEGIN
900#undef DIAG_COMPAT_IDS_END
902 assert(CompatDiagId < std::size(Diags) &&
"Invalid compat diag id");
904 unsigned StdVer = [&] {
905 if (LangOpts.CPlusPlus26)
907 if (LangOpts.CPlusPlus23)
909 if (LangOpts.CPlusPlus20)
911 if (LangOpts.CPlusPlus17)
913 if (LangOpts.CPlusPlus14)
915 if (LangOpts.CPlusPlus11)
920 const CompatDiag &D = Diags[CompatDiagId];
921 return StdVer >= D.StdVer ? D.DiagId : D.PreDiagId;
924bool DiagnosticIDs::isUnrecoverable(
unsigned DiagID)
const {
929 if (DiagID == diag::err_unavailable ||
930 DiagID == diag::err_unavailable_message)
938 if (
isARCDiagnostic(DiagID) && DiagID != diag::err_arc_may_not_respond)
Defines the Diagnostic IDs in ID sorted order.
Includes all the separate Diagnostic headers & some related helpers.
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...
static DiagnosticIDs::Level toLevel(diag::Severity SV)
static void forEachSubGroupImpl(const WarningOption *Group, Func func)
#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.
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.
static unsigned getCXXCompatDiagId(const LangOptions &LangOpts, unsigned CompatDiagId)
Get the appropriate diagnostic Id to use for issuing a compatibility diagnostic.
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)
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.
bool hasNoErrorAsFatal() const
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.
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.
@ 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.
The JSON file list parser is used to communicate input to InstallAPI.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
@ Result
The result type of a method or function.
unsigned HasNoWarningAsError