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 {
104 LLVM_PREFERRED_TYPE(DiagnosticClass)
110 LLVM_PREFERRED_TYPE(
bool)
112 LLVM_PREFERRED_TYPE(
bool)
113 uint16_t WarnShowInSystemHeader : 1;
114 LLVM_PREFERRED_TYPE(
bool)
119 LLVM_PREFERRED_TYPE(
bool)
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 " \
188#undef VALIDATE_DIAG_SIZE
191const StaticDiagInfoRec StaticDiagInfo[] = {
193#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
194 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, STABLE_ID, \
200 DiagnosticIDs::SFINAE, \
207 STR_SIZE(DESC, uint16_t)},
208#include "clang/Basic/DiagnosticCommonKinds.inc"
209#include "clang/Basic/DiagnosticDriverKinds.inc"
210#include "clang/Basic/DiagnosticFrontendKinds.inc"
211#include "clang/Basic/DiagnosticCodeGenKinds.inc"
212#include "clang/Basic/DiagnosticSerializationKinds.inc"
213#include "clang/Basic/DiagnosticLexKinds.inc"
214#include "clang/Basic/DiagnosticParseKinds.inc"
215#include "clang/Basic/DiagnosticASTKinds.inc"
216#include "clang/Basic/DiagnosticCommentKinds.inc"
217#include "clang/Basic/DiagnosticCrossTUKinds.inc"
218#include "clang/Basic/DiagnosticSemaKinds.inc"
219#include "clang/Basic/DiagnosticAnalysisKinds.inc"
220#include "clang/Basic/DiagnosticRefactoringKinds.inc"
221#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
222#include "clang/Basic/DiagnosticTrapKinds.inc"
235 using namespace diag;
236 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
248 unsigned ID = DiagID - DIAG_START_COMMON - 1;
249#define CATEGORY(NAME, PREV) \
250 if (DiagID > DIAG_START_##NAME) { \
251 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
252 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
276 const StaticDiagInfoRec *
Found = &StaticDiagInfo[ID + Offset];
280 if (
Found->DiagID != DiagID)
293 std::vector<CustomDiagDesc> DiagInfo;
294 std::map<CustomDiagDesc, unsigned> DiagIDs;
295 std::map<diag::Group, std::vector<unsigned>> GroupToDiags;
302 "Invalid diagnostic ID");
308 std::map<CustomDiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
309 if (I != DiagIDs.end() && I->first == D)
314 DiagIDs.insert(std::make_pair(D, ID));
315 DiagInfo.push_back(D);
317 GroupToDiags[*
Group].emplace_back(ID);
322 if (
auto Diags = GroupToDiags.find(G); Diags != GroupToDiags.end())
323 return Diags->second;
337 CustomDiagInfo->getDescription(DiagID).GetDefaultSeverity());
338 }
else if (
const StaticDiagInfoRec *StaticInfo =
GetDiagInfo(DiagID)) {
341 if (StaticInfo->WarnNoWerror) {
343 "Unexpected mapping with no-Werror bit!");
354 const auto &
Diag = CustomDiagInfo->getDescription(DiagID);
355 if (
auto Group =
Diag.GetGroup()) {
370 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
371 return Info->Category;
377 struct StaticDiagCategoryRec {
381 StringRef getName()
const {
382 return StringRef(NameStr, NameLen);
388#define GET_CATEGORY_TABLE
389#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
390#include "clang/Basic/DiagnosticGroups.inc"
391#undef GET_CATEGORY_TABLE
413 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
419 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
420 return Info->Deferrable;
441 return CustomDiagInfo->getOrCreateDiagID(
Diag);
447 : CustomDiagInfo->getDescription(DiagID).GetClass() !=
CLASS_ERROR;
462 bool &EnabledByDefault)
const {
478 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
479 return Info->getDescription();
480 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
481 return CustomDiagInfo->getDescription(DiagID).GetDescription();
486 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
487 return Info->getStableID().str();
488 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
492 return std::to_string(DiagID);
499 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
500 return Info->getLegacyStableIDs();
501 assert(CustomDiagInfo &&
"Invalid CustomDiagInfo");
521 llvm_unreachable(
"unexpected severity");
528DiagnosticIDs::getDiagnosticLevel(
unsigned DiagID,
SourceLocation Loc,
530 unsigned DiagClass = getDiagClass(DiagID);
532 return toLevel(getDiagnosticSeverity(DiagID, Loc,
Diag));
542DiagnosticIDs::getDiagnosticSeverity(
unsigned DiagID,
SourceLocation Loc,
552 DiagnosticsEngine::DiagState *State =
Diag.GetDiagStateForLoc(Loc);
553 DiagnosticMapping Mapping = State->getOrAddMapping((
diag::kind)DiagID);
568 bool EnabledByDefault =
false;
570 if (
Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
576 if (IsExtensionDiag &&
595 if (State->IgnoreAllWarnings) {
596 if ((!
IsCustomDiag || CustomDiagInfo->getDescription(DiagID).GetGroup()) &&
618 DiagID != diag::fatal_too_many_errors &&
Diag.FatalsAsError)
623 if (!
Diag.hasSourceManager())
631 if (State->SuppressSystemWarnings && !
Diag.getForceSystemWarnings() &&
637 if (!Mapping.
isPragma() &&
Diag.isSuppressedViaMapping(DiagID, Loc))
649 const auto &SM =
Diag.getSourceManager();
652 if (SM.isInSystemHeader(SM.getExpansionLoc(Loc))) {
653 bool ShowInSystemHeader =
true;
656 CustomDiagInfo->getDescription(DiagID).ShouldShowInSystemHeader();
657 else if (
const StaticDiagInfoRec *Rec =
GetDiagInfo(DiagID))
658 ShowInSystemHeader = Rec->WarnShowInSystemHeader;
660 if (!ShowInSystemHeader)
665 bool ShowInSystemMacro =
true;
670 if (
const StaticDiagInfoRec *Rec =
GetDiagInfo(DiagID))
671 ShowInSystemMacro = Rec->WarnShowInSystemMacro;
673 if (!ShowInSystemMacro && SM.isInSystemMacro(Loc))
681 return Class(CustomDiagInfo->getDescription(DiagID).GetClass());
683 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
684 return Class(Info->Class);
688#define GET_DIAG_ARRAYS
689#include "clang/Basic/DiagnosticGroups.inc"
690#undef GET_DIAG_ARRAYS
693 struct WarningOption {
697 StringRef Documentation;
699 StringRef getName()
const {
return DiagGroupNames[NameOffset]; }
705#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
706 {FlagNameOffset, Members, SubGroups, Docs},
707#include "clang/Basic/DiagnosticGroups.inc"
713 return OptionTable[
static_cast<int>(Group)].Documentation;
717 return OptionTable[
static_cast<int>(Group)].getName();
720std::optional<diag::Group>
722 const auto *
Found = llvm::partition_point(
723 OptionTable, [=](
const WarningOption &O) {
return O.getName() < Name; });
729std::optional<diag::Group>
732 assert(CustomDiagInfo);
733 return CustomDiagInfo->getDescription(DiagID).GetGroup();
735 if (
const StaticDiagInfoRec *Info =
GetDiagInfo(DiagID))
736 return static_cast<diag::Group>(Info->getOptionGroupIndex());
750 std::vector<std::string> Res{
"-W",
"-Wno-"};
751 for (StringRef Name : DiagGroupNames) {
755 Res.push_back((Twine(
"-W") + Name).str());
756 Res.push_back((Twine(
"-Wno-") + Name).str());
765 const WarningOption *Group,
770 if (!Group->Members && !Group->SubGroups)
785 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
786 for (; *SubGroups != (
int16_t)-1; ++SubGroups) {
790 std::back_inserter(Diags));
792 Diags, CustomDiagInfo);
803 llvm::copy(CustomDiagInfo->getDiagsInGroup(*G),
804 std::back_inserter(Diags));
805 return ::getDiagnosticsInGroup(Flavor,
807 Diags, CustomDiagInfo.get());
814 for (
const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
815 *SubGroups != -1; ++SubGroups) {
816 func(
static_cast<size_t>(*SubGroups));
823 const WarningOption *WarningOpt = &
OptionTable[
static_cast<size_t>(Group)];
824 func(
static_cast<size_t>(Group));
831 GroupInfos[SubGroup].Severity =
static_cast<unsigned>(Sev);
839 GroupInfos[
static_cast<size_t>(*G)].HasNoWarningAsError = Val;
845 std::vector<diag::kind> &Diags) {
847 if (StaticDiagInfo[i].getFlavor() == Flavor)
848 Diags.push_back(StaticDiagInfo[i].DiagID);
854 unsigned BestDistance = Group.size() + 1;
857 if (!O.Members && !O.SubGroups)
860 unsigned Distance = O.getName().edit_distance(Group,
true, BestDistance);
861 if (Distance > BestDistance)
869 if (Distance == BestDistance) {
872 }
else if (Distance < BestDistance) {
875 BestDistance = Distance;
883 unsigned CompatDiagId) {
901#define DIAG_COMPAT_IDS_BEGIN()
902#define DIAG_COMPAT_IDS_END()
903#define DIAG_COMPAT_ID(Value, Name, Std, Diag, DiagPre) \
904 {Std >= 98 ? 1900 + Std : 2000 + Std, diag::Diag, diag::DiagPre},
905 static constexpr CompatDiag Diags[]{
906#include "clang/Basic/DiagnosticAllCompatIDs.inc"
909#undef DIAG_COMPAT_IDS_BEGIN
910#undef DIAG_COMPAT_IDS_END
912 assert(CompatDiagId < std::size(Diags) &&
"Invalid compat diag id");
914 unsigned StdVer = [&] {
915 if (!LangOpts.CPlusPlus) {
929 if (LangOpts.CPlusPlus29)
931 if (LangOpts.CPlusPlus26)
933 if (LangOpts.CPlusPlus23)
935 if (LangOpts.CPlusPlus20)
937 if (LangOpts.CPlusPlus17)
939 if (LangOpts.CPlusPlus14)
941 if (LangOpts.CPlusPlus11)
946 const CompatDiag &D = Diags[CompatDiagId];
947 return StdVer >= D.StdVer ? D.DiagId : D.PreDiagId;
950bool DiagnosticIDs::isUnrecoverable(
unsigned DiagID)
const {
955 if (DiagID == diag::err_unavailable ||
956 DiagID == diag::err_unavailable_message)
964 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.
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)
static unsigned getCompatDiagId(const LangOptions &LangOpts, unsigned CompatDiagId)
Get the appropriate diagnostic Id to use for issuing a compatibility diagnostic.
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.
Top level wrappers for InstallAPI frontend operations.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
@ Result
The result type of a method or function.
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 uint16_t
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t
unsigned HasNoWarningAsError