aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorNikolas Klauser <nikolasklauser@berlin.de>2025-01-28 08:41:31 +0100
committerGitHub <noreply@github.com>2025-01-28 08:41:31 +0100
commit0865ecc5150b9a55ba1f9e30b6d463a66ac362a6 (patch)
treeb129c3b00fd3ad7c5f353ccdf4731cc6d9b9b219 /clang/lib
parentaab25f20f6c06bab7aac6fb83d54705ec4cdfadd (diff)
downloadllvm-0865ecc5150b9a55ba1f9e30b6d463a66ac362a6.zip
llvm-0865ecc5150b9a55ba1f9e30b6d463a66ac362a6.tar.gz
llvm-0865ecc5150b9a55ba1f9e30b6d463a66ac362a6.tar.bz2
[clang] Extend diagnose_if to accept more detailed warning information, take 2 (#119712)
This is take two of #70976. This iteration of the patch makes sure that custom diagnostics without any warning group don't get promoted by `-Werror` or `-Wfatal-errors`. This implements parts of the extension proposed in https://discourse.llvm.org/t/exposing-the-diagnostic-engine-to-c/73092/7. Specifically, this makes it possible to specify a diagnostic group in an optional third argument.
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Basic/Diagnostic.cpp22
-rw-r--r--clang/lib/Basic/DiagnosticIDs.cpp285
-rw-r--r--clang/lib/Frontend/LogDiagnosticPrinter.cpp4
-rw-r--r--clang/lib/Frontend/SerializedDiagnosticPrinter.cpp12
-rw-r--r--clang/lib/Frontend/TextDiagnosticPrinter.cpp10
-rw-r--r--clang/lib/Sema/Sema.cpp5
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp4
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp26
-rw-r--r--clang/lib/Sema/SemaOverload.cpp33
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp3
-rw-r--r--clang/lib/Serialization/ASTReader.cpp2
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp1
13 files changed, 256 insertions, 153 deletions
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index ae71758..9e2f134 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -145,7 +145,7 @@ void DiagnosticsEngine::Reset(bool soft /*=false*/) {
// Create a DiagState and DiagStatePoint representing diagnostic changes
// through command-line.
- DiagStates.emplace_back();
+ DiagStates.emplace_back(*Diags);
DiagStatesByLoc.appendFirst(&DiagStates.back());
}
}
@@ -156,8 +156,11 @@ DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {
DiagMap.insert(std::make_pair(Diag, DiagnosticMapping()));
// Initialize the entry if we added it.
- if (Result.second)
- Result.first->second = DiagnosticIDs::getDefaultMapping(Diag);
+ if (Result.second) {
+ Result.first->second = DiagIDs.getDefaultMapping(Diag);
+ if (DiagnosticIDs::IsCustomDiag(Diag))
+ DiagIDs.initCustomDiagMapping(Result.first->second, Diag);
+ }
return Result.first->second;
}
@@ -299,7 +302,8 @@ void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr,
for (auto &Mapping : *Transition.State) {
StringRef Option =
- DiagnosticIDs::getWarningOptionForDiag(Mapping.first);
+ SrcMgr.getDiagnostics().Diags->getWarningOptionForDiag(
+ Mapping.first);
if (!DiagName.empty() && DiagName != Option)
continue;
@@ -343,9 +347,7 @@ void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
SourceLocation L) {
- assert(Diag < diag::DIAG_UPPER_LIMIT &&
- "Can only map builtin diagnostics");
- assert((Diags->isBuiltinWarningOrExtension(Diag) ||
+ assert((Diags->isWarningOrExtension(Diag) ||
(Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
"Cannot map errors into warnings!");
assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
@@ -397,6 +399,8 @@ bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
return true;
+ Diags->setGroupSeverity(Group, Map);
+
// Set the mapping.
for (diag::kind Diag : GroupDiags)
setSeverity(Diag, Map, Loc);
@@ -419,6 +423,7 @@ bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
if (Enabled)
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
diag::Severity::Error);
+ Diags->setGroupSeverity(Group, diag::Severity::Warning);
// Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
// potentially downgrade anything already mapped to be a warning.
@@ -450,6 +455,7 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
if (Enabled)
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
diag::Severity::Fatal);
+ Diags->setGroupSeverity(Group, diag::Severity::Error);
// Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
// and potentially downgrade anything already mapped to be a fatal error.
@@ -482,7 +488,7 @@ void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
// Set the mapping.
for (diag::kind Diag : AllDiags)
- if (Diags->isBuiltinWarningOrExtension(Diag))
+ if (Diags->isWarningOrExtension(Diag))
setSeverity(Diag, Map, Loc);
}
diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp
index de1de6f..ca5b8d2 100644
--- a/clang/lib/Basic/DiagnosticIDs.cpp
+++ b/clang/lib/Basic/DiagnosticIDs.cpp
@@ -62,13 +62,12 @@ const uint32_t StaticDiagInfoDescriptionOffsets[] = {
#undef DIAG
};
-// Diagnostic classes.
enum DiagnosticClass {
- CLASS_NOTE = 0x01,
- CLASS_REMARK = 0x02,
- CLASS_WARNING = 0x03,
- CLASS_EXTENSION = 0x04,
- CLASS_ERROR = 0x05
+ CLASS_NOTE = DiagnosticIDs::CLASS_NOTE,
+ CLASS_REMARK = DiagnosticIDs::CLASS_REMARK,
+ CLASS_WARNING = DiagnosticIDs::CLASS_WARNING,
+ CLASS_EXTENSION = DiagnosticIDs::CLASS_EXTENSION,
+ CLASS_ERROR = DiagnosticIDs::CLASS_ERROR,
};
struct StaticDiagInfoRec {
@@ -229,11 +228,60 @@ CATEGORY(INSTALLAPI, REFACTORING)
return Found;
}
-DiagnosticMapping DiagnosticIDs::getDefaultMapping(unsigned DiagID) {
+//===----------------------------------------------------------------------===//
+// Custom Diagnostic information
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+namespace diag {
+using CustomDiagDesc = DiagnosticIDs::CustomDiagDesc;
+class CustomDiagInfo {
+ std::vector<CustomDiagDesc> DiagInfo;
+ std::map<CustomDiagDesc, unsigned> DiagIDs;
+ std::map<diag::Group, std::vector<unsigned>> GroupToDiags;
+
+public:
+ /// getDescription - Return the description of the specified custom
+ /// diagnostic.
+ const CustomDiagDesc &getDescription(unsigned DiagID) const {
+ assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
+ "Invalid diagnostic ID");
+ return DiagInfo[DiagID - DIAG_UPPER_LIMIT];
+ }
+
+ unsigned getOrCreateDiagID(DiagnosticIDs::CustomDiagDesc D) {
+ // Check to see if it already exists.
+ std::map<CustomDiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
+ if (I != DiagIDs.end() && I->first == D)
+ return I->second;
+
+ // If not, assign a new ID.
+ unsigned ID = DiagInfo.size() + DIAG_UPPER_LIMIT;
+ DiagIDs.insert(std::make_pair(D, ID));
+ DiagInfo.push_back(D);
+ if (auto Group = D.GetGroup())
+ GroupToDiags[*Group].emplace_back(ID);
+ return ID;
+ }
+
+ ArrayRef<unsigned> getDiagsInGroup(diag::Group G) const {
+ if (auto Diags = GroupToDiags.find(G); Diags != GroupToDiags.end())
+ return Diags->second;
+ return {};
+ }
+};
+
+} // namespace diag
+} // namespace clang
+
+DiagnosticMapping DiagnosticIDs::getDefaultMapping(unsigned DiagID) const {
DiagnosticMapping Info = DiagnosticMapping::Make(
diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
- if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
+ if (IsCustomDiag(DiagID)) {
+ Info.setSeverity(
+ CustomDiagInfo->getDescription(DiagID).GetDefaultSeverity());
+ } else if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
if (StaticInfo->WarnNoWerror) {
@@ -246,6 +294,22 @@ DiagnosticMapping DiagnosticIDs::getDefaultMapping(unsigned DiagID) {
return Info;
}
+void DiagnosticIDs::initCustomDiagMapping(DiagnosticMapping &Mapping,
+ unsigned DiagID) {
+ assert(IsCustomDiag(DiagID));
+ const auto &Diag = CustomDiagInfo->getDescription(DiagID);
+ if (auto Group = Diag.GetGroup()) {
+ GroupInfo GroupInfo = GroupInfos[static_cast<size_t>(*Group)];
+ if (static_cast<diag::Severity>(GroupInfo.Severity) != diag::Severity())
+ Mapping.setSeverity(static_cast<diag::Severity>(GroupInfo.Severity));
+ Mapping.setNoWarningAsError(GroupInfo.HasNoWarningAsError);
+ } else {
+ Mapping.setSeverity(Diag.GetDefaultSeverity());
+ Mapping.setNoWarningAsError(true);
+ Mapping.setNoErrorAsFatal(true);
+ }
+}
+
/// getCategoryNumberForDiag - Return the category number that a specified
/// DiagID belongs to, or 0 if no category.
unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
@@ -303,61 +367,6 @@ bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
return false;
}
-/// getBuiltinDiagClass - Return the class field of the diagnostic.
-///
-static unsigned getBuiltinDiagClass(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Class;
- return ~0U;
-}
-
-//===----------------------------------------------------------------------===//
-// Custom Diagnostic information
-//===----------------------------------------------------------------------===//
-
-namespace clang {
- namespace diag {
- class CustomDiagInfo {
- typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
- std::vector<DiagDesc> DiagInfo;
- std::map<DiagDesc, unsigned> DiagIDs;
- public:
-
- /// getDescription - Return the description of the specified custom
- /// diagnostic.
- StringRef getDescription(unsigned DiagID) const {
- assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnostic ID");
- return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
- }
-
- /// getLevel - Return the level of the specified custom diagnostic.
- DiagnosticIDs::Level getLevel(unsigned DiagID) const {
- assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnostic ID");
- return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
- }
-
- unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
- DiagnosticIDs &Diags) {
- DiagDesc D(L, std::string(Message));
- // Check to see if it already exists.
- std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
- if (I != DiagIDs.end() && I->first == D)
- return I->second;
-
- // If not, assign a new ID.
- unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
- DiagIDs.insert(std::make_pair(D, ID));
- DiagInfo.push_back(D);
- return ID;
- }
- };
-
- } // end diag namespace
-} // end clang namespace
-
-
//===----------------------------------------------------------------------===//
// Common Diagnostic implementation
//===----------------------------------------------------------------------===//
@@ -372,38 +381,32 @@ DiagnosticIDs::~DiagnosticIDs() {}
///
/// \param FormatString A fixed diagnostic format string that will be hashed and
/// mapped to a unique DiagID.
-unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
+unsigned DiagnosticIDs::getCustomDiagID(CustomDiagDesc Diag) {
if (!CustomDiagInfo)
CustomDiagInfo.reset(new diag::CustomDiagInfo());
- return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
+ return CustomDiagInfo->getOrCreateDiagID(Diag);
}
-
-/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
-/// level of the specified diagnostic ID is a Warning or Extension.
-/// This only works on builtin diagnostics, not custom ones, and is not legal to
-/// call on NOTEs.
-bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
- return DiagID < diag::DIAG_UPPER_LIMIT &&
- getBuiltinDiagClass(DiagID) != CLASS_ERROR;
+bool DiagnosticIDs::isWarningOrExtension(unsigned DiagID) const {
+ return DiagID < diag::DIAG_UPPER_LIMIT
+ ? getDiagClass(DiagID) != CLASS_ERROR
+ : CustomDiagInfo->getDescription(DiagID).GetClass() != CLASS_ERROR;
}
/// Determine whether the given built-in diagnostic ID is a
/// Note.
-bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
- return DiagID < diag::DIAG_UPPER_LIMIT &&
- getBuiltinDiagClass(DiagID) == CLASS_NOTE;
+bool DiagnosticIDs::isNote(unsigned DiagID) const {
+ return DiagID < diag::DIAG_UPPER_LIMIT && getDiagClass(DiagID) == CLASS_NOTE;
}
-/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
+/// isExtensionDiag - Determine whether the given built-in diagnostic
/// ID is for an extension of some sort. This also returns EnabledByDefault,
/// which is set to indicate whether the diagnostic is ignored by default (in
/// which case -pedantic enables it) or treated as a warning/error by default.
///
-bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
- bool &EnabledByDefault) {
- if (DiagID >= diag::DIAG_UPPER_LIMIT ||
- getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
+bool DiagnosticIDs::isExtensionDiag(unsigned DiagID,
+ bool &EnabledByDefault) const {
+ if (IsCustomDiag(DiagID) || getDiagClass(DiagID) != CLASS_EXTENSION)
return false;
EnabledByDefault =
@@ -411,10 +414,7 @@ bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
return true;
}
-bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
- if (DiagID >= diag::DIAG_UPPER_LIMIT)
- return false;
-
+bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) const {
return getDefaultMapping(DiagID).getSeverity() >= diag::Severity::Error;
}
@@ -424,7 +424,7 @@ StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return Info->getDescription();
assert(CustomDiagInfo && "Invalid CustomDiagInfo");
- return CustomDiagInfo->getDescription(DiagID);
+ return CustomDiagInfo->getDescription(DiagID).GetDescription();
}
static DiagnosticIDs::Level toLevel(diag::Severity SV) {
@@ -449,13 +449,7 @@ static DiagnosticIDs::Level toLevel(diag::Severity SV) {
DiagnosticIDs::Level
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
const DiagnosticsEngine &Diag) const {
- // Handle custom diagnostics, which cannot be mapped.
- if (DiagID >= diag::DIAG_UPPER_LIMIT) {
- assert(CustomDiagInfo && "Invalid CustomDiagInfo");
- return CustomDiagInfo->getLevel(DiagID);
- }
-
- unsigned DiagClass = getBuiltinDiagClass(DiagID);
+ unsigned DiagClass = getDiagClass(DiagID);
if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
}
@@ -469,7 +463,8 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
diag::Severity
DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
const DiagnosticsEngine &Diag) const {
- assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
+ bool IsCustomDiag = DiagnosticIDs::IsCustomDiag(DiagID);
+ assert(getDiagClass(DiagID) != CLASS_NOTE);
// Specific non-error diagnostics may be mapped to various levels from ignored
// to error. Errors can only be mapped to fatal.
@@ -477,7 +472,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// Get the mapping information, or compute it lazily.
DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
- DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
+ DiagnosticMapping Mapping = State->getOrAddMapping((diag::kind)DiagID);
// TODO: Can a null severity really get here?
if (Mapping.getSeverity() != diag::Severity())
@@ -485,14 +480,15 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// Upgrade ignored diagnostics if -Weverything is enabled.
if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
- !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
+ !Mapping.isUser() &&
+ (IsCustomDiag || getDiagClass(DiagID) != CLASS_REMARK))
Result = diag::Severity::Warning;
// Ignore -pedantic diagnostics inside __extension__ blocks.
// (The diagnostics controlled by -pedantic are the extension diagnostics
// that are not enabled by default.)
bool EnabledByDefault = false;
- bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
+ bool IsExtensionDiag = isExtensionDiag(DiagID, EnabledByDefault);
if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
return diag::Severity::Ignored;
@@ -510,10 +506,12 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// as well as disabling all messages which are currently mapped to Warning
// (whether by default or downgraded from Error via e.g. -Wno-error or #pragma
// diagnostic.)
+ // FIXME: Should -w be ignored for custom warnings without a group?
if (State->IgnoreAllWarnings) {
- if (Result == diag::Severity::Warning ||
- (Result >= diag::Severity::Error &&
- !isDefaultMappingAsError((diag::kind)DiagID)))
+ if ((!IsCustomDiag || CustomDiagInfo->getDescription(DiagID).GetGroup()) &&
+ (Result == diag::Severity::Warning ||
+ (Result >= diag::Severity::Error &&
+ !isDefaultMappingAsError((diag::kind)DiagID))))
return diag::Severity::Ignored;
}
@@ -541,9 +539,11 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
return Result;
const auto &SM = Diag.getSourceManager();
- // Custom diagnostics always are emitted in system headers.
+
bool ShowInSystemHeader =
- !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
+ IsCustomDiag
+ ? CustomDiagInfo->getDescription(DiagID).ShouldShowInSystemHeader()
+ : !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
// If we are in a system header, we ignore it. We look at the diagnostic class
// because we also want to ignore extensions and warnings in -Werror and
@@ -566,6 +566,15 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
return Result;
}
+DiagnosticIDs::Class DiagnosticIDs::getDiagClass(unsigned DiagID) const {
+ if (IsCustomDiag(DiagID))
+ return Class(CustomDiagInfo->getDescription(DiagID).GetClass());
+
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+ return Class(Info->Class);
+ return CLASS_INVALID;
+}
+
#define GET_DIAG_ARRAYS
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_DIAG_ARRAYS
@@ -607,7 +616,12 @@ DiagnosticIDs::getGroupForWarningOption(StringRef Name) {
return static_cast<diag::Group>(Found - OptionTable);
}
-std::optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {
+std::optional<diag::Group>
+DiagnosticIDs::getGroupForDiag(unsigned DiagID) const {
+ if (IsCustomDiag(DiagID)) {
+ assert(CustomDiagInfo);
+ return CustomDiagInfo->getDescription(DiagID).GetGroup();
+ }
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return static_cast<diag::Group>(Info->getOptionGroupIndex());
return std::nullopt;
@@ -639,7 +653,8 @@ std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
/// were filtered out due to having the wrong flavor.
static bool getDiagnosticsInGroup(diag::Flavor Flavor,
const WarningOption *Group,
- SmallVectorImpl<diag::kind> &Diags) {
+ SmallVectorImpl<diag::kind> &Diags,
+ diag::CustomDiagInfo *CustomDiagInfo) {
// An empty group is considered to be a warning group: we have empty groups
// for GCC compatibility, and GCC does not have remarks.
if (!Group->Members && !Group->SubGroups)
@@ -658,9 +673,14 @@ static bool getDiagnosticsInGroup(diag::Flavor Flavor,
// Add the members of the subgroups.
const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
- for (; *SubGroups != (int16_t)-1; ++SubGroups)
+ for (; *SubGroups != (int16_t)-1; ++SubGroups) {
+ if (CustomDiagInfo)
+ llvm::copy(
+ CustomDiagInfo->getDiagsInGroup(static_cast<diag::Group>(*SubGroups)),
+ std::back_inserter(Diags));
NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
- Diags);
+ Diags, CustomDiagInfo);
+ }
return NotFound;
}
@@ -668,12 +688,49 @@ static bool getDiagnosticsInGroup(diag::Flavor Flavor,
bool
DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
SmallVectorImpl<diag::kind> &Diags) const {
- if (std::optional<diag::Group> G = getGroupForWarningOption(Group))
- return ::getDiagnosticsInGroup(
- Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);
+ if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
+ if (CustomDiagInfo)
+ llvm::copy(CustomDiagInfo->getDiagsInGroup(*G),
+ std::back_inserter(Diags));
+ return ::getDiagnosticsInGroup(Flavor,
+ &OptionTable[static_cast<unsigned>(*G)],
+ Diags, CustomDiagInfo.get());
+ }
return true;
}
+template <class Func>
+static void forEachSubGroupImpl(const WarningOption *Group, Func func) {
+ for (const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
+ *SubGroups != -1; ++SubGroups) {
+ func(static_cast<size_t>(*SubGroups));
+ forEachSubGroupImpl(&OptionTable[*SubGroups], std::move(func));
+ }
+}
+
+template <class Func>
+static void forEachSubGroup(diag::Group Group, Func func) {
+ const WarningOption *WarningOpt = &OptionTable[static_cast<size_t>(Group)];
+ func(static_cast<size_t>(Group));
+ ::forEachSubGroupImpl(WarningOpt, std::move(func));
+}
+
+void DiagnosticIDs::setGroupSeverity(StringRef Group, diag::Severity Sev) {
+ if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
+ ::forEachSubGroup(*G, [&](size_t SubGroup) {
+ GroupInfos[SubGroup].Severity = static_cast<unsigned>(Sev);
+ });
+ }
+}
+
+void DiagnosticIDs::setGroupNoWarningsAsError(StringRef Group, bool Val) {
+ if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
+ ::forEachSubGroup(*G, [&](size_t SubGroup) {
+ GroupInfos[static_cast<size_t>(*G)].HasNoWarningAsError = Val;
+ });
+ }
+}
+
void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,
std::vector<diag::kind> &Diags) {
for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
@@ -696,7 +753,7 @@ StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
// Don't suggest groups that are not of this kind.
llvm::SmallVector<diag::kind, 8> Diags;
- if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())
+ if (::getDiagnosticsInGroup(Flavor, &O, Diags, nullptr) || Diags.empty())
continue;
if (Distance == BestDistance) {
@@ -810,14 +867,8 @@ void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag,
}
bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
- if (DiagID >= diag::DIAG_UPPER_LIMIT) {
- assert(CustomDiagInfo && "Invalid CustomDiagInfo");
- // Custom diagnostics.
- return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
- }
-
// Only errors may be unrecoverable.
- if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
+ if (getDiagClass(DiagID) < CLASS_ERROR)
return false;
if (DiagID == diag::err_unavailable ||
diff --git a/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
index 469d1c2..4e963af 100644
--- a/clang/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -129,7 +129,8 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
DE.DiagnosticLevel = Level;
DE.WarningOption =
- std::string(DiagnosticIDs::getWarningOptionForDiag(DE.DiagnosticID));
+ std::string(Info.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
+ DE.DiagnosticID));
// Format the message.
SmallString<100> MessageStr;
@@ -160,4 +161,3 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
// Record the diagnostic entry.
Entries.push_back(DE);
}
-
diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 1313342..02aa3e8 100644
--- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -202,7 +202,7 @@ private:
/// Emit the string information for diagnostic flags.
unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
- unsigned DiagID = 0);
+ const Diagnostic *Diag = nullptr);
unsigned getEmitDiagnosticFlag(StringRef DiagName);
@@ -536,11 +536,13 @@ unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
}
unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
- unsigned DiagID) {
- if (DiagLevel == DiagnosticsEngine::Note)
+ const Diagnostic *Diag) {
+ if (!Diag || DiagLevel == DiagnosticsEngine::Note)
return 0; // No flag for notes.
- StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
+ StringRef FlagName =
+ Diag->getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
+ Diag->getID());
return getEmitDiagnosticFlag(FlagName);
}
@@ -655,7 +657,7 @@ void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
Record.push_back(getEmitCategory(DiagID));
// Emit the diagnostic flag string lazily and get the mapped ID.
- Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
+ Record.push_back(getEmitDiagnosticFlag(Level, Info));
} else {
Record.push_back(getEmitCategory());
Record.push_back(getEmitDiagnosticFlag(Level));
diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index dac5c44..28f7218 100644
--- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -70,13 +70,17 @@ static void printDiagnosticOptions(raw_ostream &OS,
// flag it as such. Note that diagnostics could also have been mapped by a
// pragma, but we don't currently have a way to distinguish this.
if (Level == DiagnosticsEngine::Error &&
- DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) &&
- !DiagnosticIDs::isDefaultMappingAsError(Info.getID())) {
+ Info.getDiags()->getDiagnosticIDs()->isWarningOrExtension(
+ Info.getID()) &&
+ !Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
+ Info.getID())) {
OS << " [-Werror";
Started = true;
}
- StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
+ StringRef Opt =
+ Info.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
+ Info.getID());
if (!Opt.empty()) {
OS << (Started ? "," : " [")
<< (Level == DiagnosticsEngine::Remark ? "-R" : "-W") << Opt;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index abb46d3..9507d76 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1679,7 +1679,7 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) {
// that is different from the last template instantiation where
// we emitted an error, print a template instantiation
// backtrace.
- if (!DiagnosticIDs::isBuiltinNote(DiagID))
+ if (!Diags.getDiagnosticIDs()->isNote(DiagID))
PrintContextStack();
}
@@ -1693,7 +1693,8 @@ bool Sema::hasUncompilableErrorOccurred() const {
if (Loc == DeviceDeferredDiags.end())
return false;
for (auto PDAt : Loc->second) {
- if (DiagnosticIDs::isDefaultMappingAsError(PDAt.second.getDiagID()))
+ if (Diags.getDiagnosticIDs()->isDefaultMappingAsError(
+ PDAt.second.getDiagID()))
return true;
}
return false;
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 35f28bf..0e1bf72 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -833,7 +833,7 @@ SemaBase::SemaDiagnosticBuilder SemaCUDA::DiagIfDeviceCode(SourceLocation Loc,
if (!getLangOpts().CUDAIsDevice)
return SemaDiagnosticBuilder::K_Nop;
if (SemaRef.IsLastErrorImmediate &&
- getDiagnostics().getDiagnosticIDs()->isBuiltinNote(DiagID))
+ getDiagnostics().getDiagnosticIDs()->isNote(DiagID))
return SemaDiagnosticBuilder::K_Immediate;
return (SemaRef.getEmissionStatus(CurFunContext) ==
Sema::FunctionEmissionStatus::Emitted)
@@ -864,7 +864,7 @@ Sema::SemaDiagnosticBuilder SemaCUDA::DiagIfHostCode(SourceLocation Loc,
if (getLangOpts().CUDAIsDevice)
return SemaDiagnosticBuilder::K_Nop;
if (SemaRef.IsLastErrorImmediate &&
- getDiagnostics().getDiagnosticIDs()->isBuiltinNote(DiagID))
+ getDiagnostics().getDiagnosticIDs()->isNote(DiagID))
return SemaDiagnosticBuilder::K_Immediate;
return (SemaRef.getEmissionStatus(CurFunContext) ==
Sema::FunctionEmissionStatus::Emitted)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c2d82b9..9d7d225 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -879,22 +879,38 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkFunctionConditionAttr(S, D, AL, Cond, Msg))
return;
- StringRef DiagTypeStr;
- if (!S.checkStringLiteralArgumentAttr(AL, 2, DiagTypeStr))
+ StringRef DefaultSevStr;
+ if (!S.checkStringLiteralArgumentAttr(AL, 2, DefaultSevStr))
return;
- DiagnoseIfAttr::DiagnosticType DiagType;
- if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) {
+ DiagnoseIfAttr::DefaultSeverity DefaultSev;
+ if (!DiagnoseIfAttr::ConvertStrToDefaultSeverity(DefaultSevStr, DefaultSev)) {
S.Diag(AL.getArgAsExpr(2)->getBeginLoc(),
diag::err_diagnose_if_invalid_diagnostic_type);
return;
}
+ StringRef WarningGroup;
+ SmallVector<StringRef, 2> Options;
+ if (AL.getNumArgs() > 3) {
+ if (!S.checkStringLiteralArgumentAttr(AL, 3, WarningGroup))
+ return;
+ if (WarningGroup.empty() ||
+ !S.getDiagnostics().getDiagnosticIDs()->getGroupForWarningOption(
+ WarningGroup)) {
+ S.Diag(AL.getArgAsExpr(3)->getBeginLoc(),
+ diag::err_diagnose_if_unknown_warning)
+ << WarningGroup;
+ return;
+ }
+ }
+
bool ArgDependent = false;
if (const auto *FD = dyn_cast<FunctionDecl>(D))
ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
D->addAttr(::new (S.Context) DiagnoseIfAttr(
- S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
+ S.Context, AL, Cond, Msg, DefaultSev, WarningGroup, ArgDependent,
+ cast<NamedDecl>(D)));
}
static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6ae9c51..776dba8 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -7377,8 +7377,10 @@ static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND,
return false;
auto WarningBegin = std::stable_partition(
- Attrs.begin(), Attrs.end(),
- [](const DiagnoseIfAttr *DIA) { return DIA->isError(); });
+ Attrs.begin(), Attrs.end(), [](const DiagnoseIfAttr *DIA) {
+ return DIA->getDefaultSeverity() == DiagnoseIfAttr::DS_error &&
+ DIA->getWarningGroup().empty();
+ });
// Note that diagnose_if attributes are late-parsed, so they appear in the
// correct order (unlike enable_if attributes).
@@ -7392,11 +7394,32 @@ static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND,
return true;
}
+ auto ToSeverity = [](DiagnoseIfAttr::DefaultSeverity Sev) {
+ switch (Sev) {
+ case DiagnoseIfAttr::DS_warning:
+ return diag::Severity::Warning;
+ case DiagnoseIfAttr::DS_error:
+ return diag::Severity::Error;
+ }
+ llvm_unreachable("Fully covered switch above!");
+ };
+
for (const auto *DIA : llvm::make_range(WarningBegin, Attrs.end()))
if (IsSuccessful(DIA)) {
- S.Diag(Loc, diag::warn_diagnose_if_succeeded) << DIA->getMessage();
- S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
- << DIA->getParent() << DIA->getCond()->getSourceRange();
+ if (DIA->getWarningGroup().empty() &&
+ DIA->getDefaultSeverity() == DiagnoseIfAttr::DS_warning) {
+ S.Diag(Loc, diag::warn_diagnose_if_succeeded) << DIA->getMessage();
+ S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
+ << DIA->getParent() << DIA->getCond()->getSourceRange();
+ } else {
+ auto DiagGroup = S.Diags.getDiagnosticIDs()->getGroupForWarningOption(
+ DIA->getWarningGroup());
+ assert(DiagGroup);
+ auto DiagID = S.Diags.getDiagnosticIDs()->getCustomDiagID(
+ {ToSeverity(DIA->getDefaultSeverity()), "%0",
+ DiagnosticIDs::CLASS_WARNING, false, false, *DiagGroup});
+ S.Diag(Loc, DiagID) << DIA->getMessage();
+ }
}
return false;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ebe2dd9..16a7049 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -284,7 +284,8 @@ static void instantiateDependentDiagnoseIfAttr(
if (Cond)
New->addAttr(new (S.getASTContext()) DiagnoseIfAttr(
S.getASTContext(), *DIA, Cond, DIA->getMessage(),
- DIA->getDiagnosticType(), DIA->getArgDependent(), New));
+ DIA->getDefaultSeverity(), DIA->getWarningGroup(),
+ DIA->getArgDependent(), New));
}
// Constructs and adds to New a new instance of CUDALaunchBoundsAttr using
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 08801d2..f524251 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -6864,7 +6864,7 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
// command line (-w, -Weverything, -Werror, ...) along with any explicit
// -Wblah flags.
unsigned Flags = Record[Idx++];
- DiagState Initial;
+ DiagState Initial(*Diag.getDiagnosticIDs());
Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1;
Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1;
Initial.WarningsAsErrors = Flags & 1; Flags >>= 1;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index a580f37..2d0fae8 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -3264,7 +3264,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
// Skip default mappings. We have a mapping for every diagnostic ever
// emitted, regardless of whether it was customized.
if (!I.second.isPragma() &&
- I.second == DiagnosticIDs::getDefaultMapping(I.first))
+ I.second == Diag.getDiagnosticIDs()->getDefaultMapping(I.first))
continue;
Mappings.push_back(I);
}
diff --git a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
index e8cf367..79ee430 100644
--- a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
@@ -91,7 +91,6 @@ public:
? " [" + PD->getCheckerName() + "]"
: "")
.str();
-
reportPiece(WarnID, PD->getLocation().asLocation(),
(PD->getShortDescription() + WarningMsg).str(),
PD->path.back()->getRanges(), PD->path.back()->getFixits());