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;
38struct StaticDiagInfoDescriptionStringTable {
39#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
40 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
41 char ENUM##_desc[sizeof(DESC)];
46const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
47#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
48 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
54extern const StaticDiagInfoRec StaticDiagInfo[];
58const uint32_t StaticDiagInfoDescriptionOffsets[] = {
59#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
60 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
61 offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),
75struct StaticDiagInfoRec {
78 uint16_t DefaultSeverity : 3;
79 LLVM_PREFERRED_TYPE(DiagnosticClass)
84 uint16_t Category : 6;
85 LLVM_PREFERRED_TYPE(
bool)
86 uint16_t WarnNoWerror : 1;
87 LLVM_PREFERRED_TYPE(
bool)
88 uint16_t WarnShowInSystemHeader : 1;
89 LLVM_PREFERRED_TYPE(
bool)
90 uint16_t WarnShowInSystemMacro : 1;
93 uint16_t OptionGroupIndex : 15;
94 LLVM_PREFERRED_TYPE(
bool)
95 uint16_t Deferrable : 1;
97 uint16_t DescriptionLen;
99 unsigned getOptionGroupIndex()
const {
100 return OptionGroupIndex;
103 StringRef getDescription()
const {
104 size_t MyIndex =
this - &StaticDiagInfo[0];
105 uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];
106 const char* Table =
reinterpret_cast<const char*
>(&StaticDiagInfoDescriptions);
107 return StringRef(&Table[StringOffset], DescriptionLen);
111 return Class == CLASS_REMARK ? diag::Flavor::Remark
112 : diag::Flavor::WarningOrError;
115 bool operator<(
const StaticDiagInfoRec &RHS)
const {
116 return DiagID < RHS.DiagID;
120#define STRINGIFY_NAME(NAME) #NAME
121#define VALIDATE_DIAG_SIZE(NAME) \
123 static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
124 static_cast<unsigned>(diag::DIAG_START_##NAME) + \
125 static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
127 DIAG_SIZE_##NAME) " is insufficient to contain all " \
128 "diagnostics, it may need to be made larger in " \
144#undef VALIDATE_DIAG_SIZE
147const StaticDiagInfoRec StaticDiagInfo[] = {
149#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
150 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
155 DiagnosticIDs::SFINAE, \
162 STR_SIZE(DESC, uint16_t)},
163#include "clang/Basic/DiagnosticCommonKinds.inc"
164#include "clang/Basic/DiagnosticDriverKinds.inc"
165#include "clang/Basic/DiagnosticFrontendKinds.inc"
166#include "clang/Basic/DiagnosticSerializationKinds.inc"
167#include "clang/Basic/DiagnosticLexKinds.inc"
168#include "clang/Basic/DiagnosticParseKinds.inc"
169#include "clang/Basic/DiagnosticASTKinds.inc"
170#include "clang/Basic/DiagnosticCommentKinds.inc"
171#include "clang/Basic/DiagnosticCrossTUKinds.inc"
172#include "clang/Basic/DiagnosticSemaKinds.inc"
173#include "clang/Basic/DiagnosticAnalysisKinds.inc"
174#include "clang/Basic/DiagnosticRefactoringKinds.inc"
175#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
176#include "clang/Basic/DiagnosticTrapKinds.inc"
189 using namespace diag;
190 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
202 unsigned ID = DiagID - DIAG_START_COMMON - 1;
203#define CATEGORY(NAME, PREV) \
204 if (DiagID > DIAG_START_##NAME) { \
205 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
206 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
229 const StaticDiagInfoRec *
Found = &StaticDiagInfo[ID + Offset];
233 if (
Found->DiagID != DiagID)
246 std::vector<CustomDiagDesc> DiagInfo;
247 std::map<CustomDiagDesc, unsigned> DiagIDs;
248 std::map<diag::Group, std::vector<unsigned>> GroupToDiags;
255 "Invalid diagnostic ID");
261 std::map<CustomDiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
262 if (I != DiagIDs.end() && I->first == D)
267 DiagIDs.insert(std::make_pair(D, ID));
268 DiagInfo.push_back(D);
270 GroupToDiags[*
Group].emplace_back(ID);
275 if (
auto Diags = GroupToDiags.find(G); Diags != GroupToDiags.end())
276 return Diags->second;
290 CustomDiagInfo->getDescription(DiagID).GetDefaultSeverity());
291 }
else if (
const StaticDiagInfoRec *StaticInfo =
GetDiagInfo(DiagID)) {
294 if (StaticInfo->WarnNoWerror) {
296 "Unexpected mapping with no-Werror bit!");
307 const auto &
Diag = CustomDiagInfo->getDescription(DiagID);
308 if (
auto Group =
Diag.GetGroup()) {
323 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
324 return Info->Category;
330 struct StaticDiagCategoryRec {
334 StringRef getName()
const {
335 return StringRef(NameStr, NameLen);
341#define GET_CATEGORY_TABLE
342#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
343#include "clang/Basic/DiagnosticGroups.inc"
344#undef GET_CATEGORY_TABLE
366 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
372 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
373 return Info->Deferrable;
394 return CustomDiagInfo->getOrCreateDiagID(
Diag);
400 : CustomDiagInfo->getDescription(DiagID).GetClass() !=
CLASS_ERROR;
415 bool &EnabledByDefault)
const {
431 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
432 return Info->getDescription();
433 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
434 return CustomDiagInfo->getDescription(DiagID).GetDescription();
450 llvm_unreachable(
"unexpected severity");
457DiagnosticIDs::getDiagnosticLevel(
unsigned DiagID,
SourceLocation Loc,
459 unsigned DiagClass = getDiagClass(DiagID);
461 return toLevel(getDiagnosticSeverity(DiagID, Loc,
Diag));
471DiagnosticIDs::getDiagnosticSeverity(
unsigned DiagID,
SourceLocation Loc,
481 DiagnosticsEngine::DiagState *State =
Diag.GetDiagStateForLoc(Loc);
482 DiagnosticMapping Mapping = State->getOrAddMapping((
diag::kind)DiagID);
497 bool EnabledByDefault =
false;
499 if (
Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
504 if (IsExtensionDiag && !Mapping.
isUser())
517 if (State->IgnoreAllWarnings) {
518 if ((!
IsCustomDiag || CustomDiagInfo->getDescription(DiagID).GetGroup()) &&
540 DiagID != diag::fatal_too_many_errors &&
Diag.FatalsAsError)
545 if (!
Diag.hasSourceManager())
548 const auto &
SM =
Diag.getSourceManager();
558 if (State->SuppressSystemWarnings && !
Diag.getForceSystemWarnings() &&
559 Loc.
isValid() &&
SM.isInSystemHeader(
SM.getExpansionLoc(Loc))) {
560 bool ShowInSystemHeader =
true;
563 CustomDiagInfo->getDescription(DiagID).ShouldShowInSystemHeader();
564 else if (
const StaticDiagInfoRec *Rec =
GetDiagInfo(DiagID))
565 ShowInSystemHeader = Rec->WarnShowInSystemHeader;
567 if (!ShowInSystemHeader)
572 if (State->SuppressSystemWarnings && !
Diag.getForceSystemWarnings() &&
575 bool ShowInSystemMacro =
true;
576 if (
const StaticDiagInfoRec *Rec =
GetDiagInfo(DiagID))
577 ShowInSystemMacro = Rec->WarnShowInSystemMacro;
579 if (!ShowInSystemMacro &&
SM.isInSystemMacro(Loc))
583 if (!Mapping.
isPragma() &&
Diag.isSuppressedViaMapping(DiagID, Loc))
591 return Class(CustomDiagInfo->getDescription(DiagID).GetClass());
593 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
594 return Class(Info->Class);
598#define GET_DIAG_ARRAYS
599#include "clang/Basic/DiagnosticGroups.inc"
600#undef GET_DIAG_ARRAYS
603 struct WarningOption {
607 StringRef Documentation;
609 StringRef getName()
const {
return DiagGroupNames[NameOffset]; }
615#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
616 {FlagNameOffset, Members, SubGroups, Docs},
617#include "clang/Basic/DiagnosticGroups.inc"
623 return OptionTable[
static_cast<int>(Group)].Documentation;
627 return OptionTable[
static_cast<int>(Group)].getName();
630std::optional<diag::Group>
632 const auto *
Found = llvm::partition_point(
633 OptionTable, [=](
const WarningOption &O) {
return O.getName() < Name; });
639std::optional<diag::Group>
642 assert(CustomDiagInfo);
643 return CustomDiagInfo->getDescription(DiagID).GetGroup();
645 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
646 return static_cast<diag::Group>(Info->getOptionGroupIndex());
660 std::vector<std::string> Res{
"-W",
"-Wno-"};
661 for (StringRef Name : DiagGroupNames) {
665 Res.push_back((Twine(
"-W") + Name).str());
666 Res.push_back((Twine(
"-Wno-") + Name).str());
675 const WarningOption *Group,
680 if (!Group->Members && !Group->SubGroups)
686 const int16_t *
Member = DiagArrays + Group->Members;
695 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
696 for (; *SubGroups != (int16_t)-1; ++SubGroups) {
700 std::back_inserter(Diags));
702 Diags, CustomDiagInfo);
713 llvm::copy(CustomDiagInfo->getDiagsInGroup(*G),
714 std::back_inserter(Diags));
715 return ::getDiagnosticsInGroup(Flavor,
717 Diags, CustomDiagInfo.get());
724 for (
const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
725 *SubGroups != -1; ++SubGroups) {
726 func(
static_cast<size_t>(*SubGroups));
733 const WarningOption *WarningOpt = &
OptionTable[
static_cast<size_t>(Group)];
734 func(
static_cast<size_t>(Group));
741 GroupInfos[SubGroup].Severity =
static_cast<unsigned>(Sev);
749 GroupInfos[
static_cast<size_t>(*G)].HasNoWarningAsError = Val;
755 std::vector<diag::kind> &Diags) {
757 if (StaticDiagInfo[i].getFlavor() == Flavor)
758 Diags.push_back(StaticDiagInfo[i].DiagID);
764 unsigned BestDistance = Group.size() + 1;
767 if (!O.Members && !O.SubGroups)
770 unsigned Distance = O.getName().edit_distance(Group,
true, BestDistance);
771 if (Distance > BestDistance)
779 if (Distance == BestDistance) {
782 }
else if (Distance < BestDistance) {
785 BestDistance = Distance;
793 unsigned CompatDiagId) {
804#define DIAG_COMPAT_IDS_BEGIN()
805#define DIAG_COMPAT_IDS_END()
806#define DIAG_COMPAT_ID(Value, Name, Std, Diag, DiagPre) \
807 {Std == 98 ? 1998 : 2000 + Std, diag::Diag, diag::DiagPre},
808 static constexpr CompatDiag Diags[]{
809#include "clang/Basic/DiagnosticAllCompatIDs.inc"
812#undef DIAG_COMPAT_IDS_BEGIN
813#undef DIAG_COMPAT_IDS_END
815 assert(CompatDiagId < std::size(Diags) &&
"Invalid compat diag id");
817 unsigned StdVer = [&] {
818 if (LangOpts.CPlusPlus26)
820 if (LangOpts.CPlusPlus23)
822 if (LangOpts.CPlusPlus20)
824 if (LangOpts.CPlusPlus17)
826 if (LangOpts.CPlusPlus14)
828 if (LangOpts.CPlusPlus11)
833 const CompatDiag &D = Diags[CompatDiagId];
834 return StdVer >= D.StdVer ? D.DiagId : D.PreDiagId;
837bool DiagnosticIDs::isUnrecoverable(
unsigned DiagID)
const {
842 if (DiagID == diag::err_unavailable ||
843 DiagID == diag::err_unavailable_message)
851 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.
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 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.
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.
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