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)
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);
269 if (
auto Group =
D.GetGroup())
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");
459 unsigned DiagClass = getDiagClass(DiagID);
481 DiagnosticsEngine::DiagState *State =
Diag.GetDiagStateForLoc(
Loc);
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();
552 if (State->SuppressSystemWarnings &&
Loc.
isValid() &&
553 SM.isInSystemHeader(
SM.getExpansionLoc(
Loc))) {
554 bool ShowInSystemHeader =
true;
557 CustomDiagInfo->getDescription(DiagID).ShouldShowInSystemHeader();
558 else if (
const StaticDiagInfoRec *Rec =
GetDiagInfo(DiagID))
559 ShowInSystemHeader = Rec->WarnShowInSystemHeader;
561 if (!ShowInSystemHeader)
565 if (State->SuppressSystemWarnings &&
Loc.
isValid() &&
566 SM.isInSystemMacro(
Loc)) {
568 bool ShowInSystemMacro =
true;
569 if (
const StaticDiagInfoRec *Rec =
GetDiagInfo(DiagID))
570 ShowInSystemMacro = Rec->WarnShowInSystemMacro;
572 if (!ShowInSystemMacro)
584 return Class(CustomDiagInfo->getDescription(DiagID).GetClass());
586 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
587 return Class(Info->Class);
591#define GET_DIAG_ARRAYS
592#include "clang/Basic/DiagnosticGroups.inc"
593#undef GET_DIAG_ARRAYS
596 struct WarningOption {
600 StringRef Documentation;
602 StringRef getName()
const {
return DiagGroupNames[NameOffset]; }
608#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
609 {FlagNameOffset, Members, SubGroups, Docs},
610#include "clang/Basic/DiagnosticGroups.inc"
616 return OptionTable[
static_cast<int>(Group)].Documentation;
620 return OptionTable[
static_cast<int>(Group)].getName();
623std::optional<diag::Group>
625 const auto *
Found = llvm::partition_point(
626 OptionTable, [=](
const WarningOption &O) {
return O.getName() < Name; });
632std::optional<diag::Group>
635 assert(CustomDiagInfo);
636 return CustomDiagInfo->getDescription(DiagID).GetGroup();
638 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
639 return static_cast<diag::Group>(Info->getOptionGroupIndex());
653 std::vector<std::string> Res{
"-W",
"-Wno-"};
654 for (StringRef Name : DiagGroupNames) {
658 Res.push_back((Twine(
"-W") + Name).str());
659 Res.push_back((Twine(
"-Wno-") + Name).str());
668 const WarningOption *Group,
673 if (!Group->Members && !Group->SubGroups)
679 const int16_t *
Member = DiagArrays + Group->Members;
688 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
689 for (; *SubGroups != (int16_t)-1; ++SubGroups) {
693 std::back_inserter(Diags));
695 Diags, CustomDiagInfo);
706 llvm::copy(CustomDiagInfo->getDiagsInGroup(*G),
707 std::back_inserter(Diags));
708 return ::getDiagnosticsInGroup(Flavor,
710 Diags, CustomDiagInfo.get());
717 for (
const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
718 *SubGroups != -1; ++SubGroups) {
719 func(
static_cast<size_t>(*SubGroups));
726 const WarningOption *WarningOpt = &
OptionTable[
static_cast<size_t>(Group)];
727 func(
static_cast<size_t>(Group));
734 GroupInfos[SubGroup].Severity =
static_cast<unsigned>(Sev);
742 GroupInfos[
static_cast<size_t>(*G)].HasNoWarningAsError = Val;
748 std::vector<diag::kind> &Diags) {
750 if (StaticDiagInfo[i].getFlavor() == Flavor)
751 Diags.push_back(StaticDiagInfo[i].DiagID);
757 unsigned BestDistance = Group.size() + 1;
760 if (!O.Members && !O.SubGroups)
763 unsigned Distance = O.getName().edit_distance(Group,
true, BestDistance);
764 if (Distance > BestDistance)
772 if (Distance == BestDistance) {
775 }
else if (Distance < BestDistance) {
778 BestDistance = Distance;
786 unsigned CompatDiagId) {
797#define DIAG_COMPAT_IDS_BEGIN()
798#define DIAG_COMPAT_IDS_END()
799#define DIAG_COMPAT_ID(Value, Name, Std, Diag, DiagPre) \
800 {Std == 98 ? 1998 : 2000 + Std, diag::Diag, diag::DiagPre},
801 static constexpr CompatDiag Diags[]{
802#include "clang/Basic/DiagnosticAllCompatIDs.inc"
805#undef DIAG_COMPAT_IDS_BEGIN
806#undef DIAG_COMPAT_IDS_END
808 assert(CompatDiagId < std::size(Diags) &&
"Invalid compat diag id");
810 unsigned StdVer = [&] {
811 if (LangOpts.CPlusPlus26)
813 if (LangOpts.CPlusPlus23)
815 if (LangOpts.CPlusPlus20)
817 if (LangOpts.CPlusPlus17)
819 if (LangOpts.CPlusPlus14)
821 if (LangOpts.CPlusPlus11)
826 const CompatDiag &
D = Diags[CompatDiagId];
827 return StdVer >=
D.StdVer ?
D.DiagId :
D.PreDiagId;
830bool DiagnosticIDs::isUnrecoverable(
unsigned DiagID)
const {
835 if (DiagID == diag::err_unavailable ||
836 DiagID == diag::err_unavailable_message)
844 if (
isARCDiagnostic(DiagID) && DiagID != diag::err_arc_may_not_respond)
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.
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
Flavor
Flavors of diagnostics we can emit.
@ Remark
A diagnostic that indicates normal progress through compilation.
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.
@ Class
The "class" keyword introduces the elaborated-type-specifier.
unsigned HasNoWarningAsError