-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang] Extend diagnose_if to accept more detailed warning information, take 2 #119712
Conversation
@llvm/pr-subscribers-clang-tools-extra @llvm/pr-subscribers-clang Author: Nikolas Klauser (philnik777) ChangesThis is take two of #70976. This iteration of the patch makes sure that custom 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. Patch is 66.35 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/119712.diff 30 Files Affected:
diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp
index a59d1e7ac84096..a8214acc50558d 100644
--- a/clang-tools-extra/clangd/Diagnostics.cpp
+++ b/clang-tools-extra/clangd/Diagnostics.cpp
@@ -577,7 +577,17 @@ std::vector<Diag> StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) {
for (auto &Diag : Output) {
if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) {
// Warnings controlled by -Wfoo are better recognized by that name.
- StringRef Warning = DiagnosticIDs::getWarningOptionForDiag(Diag.ID);
+ const StringRef Warning = [&] {
+ if (OrigSrcMgr) {
+ return OrigSrcMgr->getDiagnostics()
+ .getDiagnosticIDs()
+ ->getWarningOptionForDiag(Diag.ID);
+ }
+ if (!DiagnosticIDs::IsCustomDiag(Diag.ID))
+ return DiagnosticIDs{}.getWarningOptionForDiag(Diag.ID);
+ return StringRef{};
+ }();
+
if (!Warning.empty()) {
Diag.Name = ("-W" + Warning).str();
} else {
@@ -894,20 +904,23 @@ void StoreDiags::flushLastDiag() {
Output.push_back(std::move(*LastDiag));
}
-bool isBuiltinDiagnosticSuppressed(unsigned ID,
- const llvm::StringSet<> &Suppress,
- const LangOptions &LangOpts) {
+bool isDiagnosticSuppressed(const clang::Diagnostic &Diag,
+ const llvm::StringSet<> &Suppress,
+ const LangOptions &LangOpts) {
// Don't complain about header-only stuff in mainfiles if it's a header.
// FIXME: would be cleaner to suppress in clang, once we decide whether the
// behavior should be to silently-ignore or respect the pragma.
- if (ID == diag::pp_pragma_sysheader_in_main_file && LangOpts.IsHeaderFile)
+ if (Diag.getID() == diag::pp_pragma_sysheader_in_main_file &&
+ LangOpts.IsHeaderFile)
return true;
- if (const char *CodePtr = getDiagnosticCode(ID)) {
+ if (const char *CodePtr = getDiagnosticCode(Diag.getID())) {
if (Suppress.contains(normalizeSuppressedCode(CodePtr)))
return true;
}
- StringRef Warning = DiagnosticIDs::getWarningOptionForDiag(ID);
+ StringRef Warning =
+ Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
+ Diag.getID());
if (!Warning.empty() && Suppress.contains(Warning))
return true;
return false;
diff --git a/clang-tools-extra/clangd/Diagnostics.h b/clang-tools-extra/clangd/Diagnostics.h
index d4c0478c63a5cf..c45d8dc3aa6ce6 100644
--- a/clang-tools-extra/clangd/Diagnostics.h
+++ b/clang-tools-extra/clangd/Diagnostics.h
@@ -181,11 +181,11 @@ class StoreDiags : public DiagnosticConsumer {
};
/// Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
-bool isBuiltinDiagnosticSuppressed(unsigned ID,
- const llvm::StringSet<> &Suppressed,
- const LangOptions &);
+bool isDiagnosticSuppressed(const clang::Diagnostic &Diag,
+ const llvm::StringSet<> &Suppressed,
+ const LangOptions &);
/// Take a user-specified diagnostic code, and convert it to a normalized form
-/// stored in the config and consumed by isBuiltinDiagnosticsSuppressed.
+/// stored in the config and consumed by isDiagnosticsSuppressed.
///
/// (This strips err_ and -W prefix so we can match with or without them.)
llvm::StringRef normalizeSuppressedCode(llvm::StringRef);
diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
index 045d32afbc938a..5cf1691ce39617 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -342,7 +342,7 @@ void applyWarningOptions(llvm::ArrayRef<std::string> ExtraArgs,
if (Enable) {
if (Diags.getDiagnosticLevel(ID, SourceLocation()) <
DiagnosticsEngine::Warning) {
- auto Group = DiagnosticIDs::getGroupForDiag(ID);
+ auto Group = Diags.getDiagnosticIDs()->getGroupForDiag(ID);
if (!Group || !EnabledGroups(*Group))
continue;
Diags.setSeverity(ID, diag::Severity::Warning, SourceLocation());
@@ -585,8 +585,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
const clang::Diagnostic &Info) {
if (Cfg.Diagnostics.SuppressAll ||
- isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress,
- Clang->getLangOpts()))
+ isDiagnosticSuppressed(Info, Cfg.Diagnostics.Suppress,
+ Clang->getLangOpts()))
return DiagnosticsEngine::Ignored;
auto It = OverriddenSeverity.find(Info.getID());
diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index ce88ec0eb88c1b..b247e608eece34 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -622,8 +622,8 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
PreambleDiagnostics.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
const clang::Diagnostic &Info) {
if (Cfg.Diagnostics.SuppressAll ||
- isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress,
- CI.getLangOpts()))
+ isDiagnosticSuppressed(Info, Cfg.Diagnostics.Suppress,
+ CI.getLangOpts()))
return DiagnosticsEngine::Ignored;
switch (Info.getID()) {
case diag::warn_no_newline_eof:
diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
index 4ecfdf0184ab40..cf9b42828568da 100644
--- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
@@ -298,20 +298,41 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) {
"unreachable-code", "unused-variable",
"typecheck_bool_condition",
"unexpected_friend", "warn_alloca"));
- EXPECT_TRUE(isBuiltinDiagnosticSuppressed(
- diag::warn_unreachable, Conf.Diagnostics.Suppress, LangOptions()));
+ clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr,
+ new clang::IgnoringDiagConsumer);
+
+ using Diag = clang::Diagnostic;
+ {
+ auto D = DiagEngine.Report(diag::warn_unreachable);
+ EXPECT_TRUE(isDiagnosticSuppressed(
+ Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
+ }
// Subcategory not respected/suppressed.
- EXPECT_FALSE(isBuiltinDiagnosticSuppressed(
- diag::warn_unreachable_break, Conf.Diagnostics.Suppress, LangOptions()));
- EXPECT_TRUE(isBuiltinDiagnosticSuppressed(
- diag::warn_unused_variable, Conf.Diagnostics.Suppress, LangOptions()));
- EXPECT_TRUE(isBuiltinDiagnosticSuppressed(diag::err_typecheck_bool_condition,
- Conf.Diagnostics.Suppress,
- LangOptions()));
- EXPECT_TRUE(isBuiltinDiagnosticSuppressed(
- diag::err_unexpected_friend, Conf.Diagnostics.Suppress, LangOptions()));
- EXPECT_TRUE(isBuiltinDiagnosticSuppressed(
- diag::warn_alloca, Conf.Diagnostics.Suppress, LangOptions()));
+ {
+ auto D = DiagEngine.Report(diag::warn_unreachable_break);
+ EXPECT_FALSE(isDiagnosticSuppressed(
+ Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
+ }
+ {
+ auto D = DiagEngine.Report(diag::warn_unused_variable);
+ EXPECT_TRUE(isDiagnosticSuppressed(
+ Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
+ }
+ {
+ auto D = DiagEngine.Report(diag::err_typecheck_bool_condition);
+ EXPECT_TRUE(isDiagnosticSuppressed(
+ Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
+ }
+ {
+ auto D = DiagEngine.Report(diag::err_unexpected_friend);
+ EXPECT_TRUE(isDiagnosticSuppressed(
+ Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
+ }
+ {
+ auto D = DiagEngine.Report(diag::warn_alloca);
+ EXPECT_TRUE(isDiagnosticSuppressed(
+ Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
+ }
Frag.Diagnostics.Suppress.emplace_back("*");
EXPECT_TRUE(compileAndApply());
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 6db36a015acfd7..1f98748314250a 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3412,18 +3412,16 @@ def DiagnoseIf : InheritableAttr {
let Spellings = [GNU<"diagnose_if">];
let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>;
let Args = [ExprArgument<"Cond">, StringArgument<"Message">,
- EnumArgument<"DiagnosticType", "DiagnosticType",
+ EnumArgument<"DefaultSeverity",
+ "DefaultSeverity",
/*is_string=*/true,
- ["error", "warning"],
- ["DT_Error", "DT_Warning"]>,
+ ["error", "warning"],
+ ["DS_error", "DS_warning"]>,
+ StringArgument<"WarningGroup", /*optional*/ 1>,
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
DeclArgument<Named, "Parent", 0, /*fake*/ 1>];
let InheritEvenIfAlreadyPresent = 1;
let LateParsed = LateAttrParseStandard;
- let AdditionalMembers = [{
- bool isError() const { return diagnosticType == DT_Error; }
- bool isWarning() const { return diagnosticType == DT_Warning; }
- }];
let TemplateDependent = 1;
let Documentation = [DiagnoseIfDocs];
}
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index d271accca3d3b7..0f673302cb30b8 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -375,10 +375,12 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
// Map extensions to warnings or errors?
diag::Severity ExtBehavior = diag::Severity::Ignored;
- DiagState()
+ DiagnosticIDs &DiagIDs;
+
+ DiagState(DiagnosticIDs &DiagIDs)
: IgnoreAllWarnings(false), EnableAllWarnings(false),
WarningsAsErrors(false), ErrorsAsFatal(false),
- SuppressSystemWarnings(false) {}
+ SuppressSystemWarnings(false), DiagIDs(DiagIDs) {}
using iterator = llvm::DenseMap<unsigned, DiagnosticMapping>::iterator;
using const_iterator =
@@ -892,6 +894,8 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
/// \param FormatString A fixed diagnostic format string that will be hashed
/// and mapped to a unique DiagID.
template <unsigned N>
+ // TODO: Deprecate this once all uses are removed from LLVM
+ // [[deprecated("Use a CustomDiagDesc instead of a Level")]]
unsigned getCustomDiagID(Level L, const char (&FormatString)[N]) {
return Diags->getCustomDiagID((DiagnosticIDs::Level)L,
StringRef(FormatString, N - 1));
diff --git a/clang/include/clang/Basic/DiagnosticCategories.h b/clang/include/clang/Basic/DiagnosticCategories.h
index 14be326f7515f8..839f8dee3ca89f 100644
--- a/clang/include/clang/Basic/DiagnosticCategories.h
+++ b/clang/include/clang/Basic/DiagnosticCategories.h
@@ -21,11 +21,12 @@ namespace clang {
};
enum class Group {
-#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
- GroupName,
+#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
+ GroupName,
#include "clang/Basic/DiagnosticGroups.inc"
#undef CATEGORY
#undef DIAG_ENTRY
+ NUM_GROUPS
};
} // end namespace diag
} // end namespace clang
diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h
index a051af327de28f..1fa38ed6066e26 100644
--- a/clang/include/clang/Basic/DiagnosticIDs.h
+++ b/clang/include/clang/Basic/DiagnosticIDs.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
#define LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
+#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
@@ -84,7 +85,7 @@ namespace clang {
/// to either Ignore (nothing), Remark (emit a remark), Warning
/// (emit a warning) or Error (emit as an error). It allows clients to
/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
- enum class Severity {
+ enum class Severity : uint8_t {
// NOTE: 0 means "uncomputed".
Ignored = 1, ///< Do not present this diagnostic, ignore it.
Remark = 2, ///< Present this diagnostic as a remark.
@@ -181,13 +182,96 @@ class DiagnosticMapping {
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
public:
/// The level of the diagnostic, after it has been through mapping.
- enum Level {
- Ignored, Note, Remark, Warning, Error, Fatal
+ enum Level : uint8_t { Ignored, Note, Remark, Warning, Error, Fatal };
+
+ // Diagnostic classes.
+ enum Class {
+ CLASS_INVALID = 0x00,
+ CLASS_NOTE = 0x01,
+ CLASS_REMARK = 0x02,
+ CLASS_WARNING = 0x03,
+ CLASS_EXTENSION = 0x04,
+ CLASS_ERROR = 0x05
+ };
+
+ static bool IsCustomDiag(diag::kind Diag) {
+ return Diag >= diag::DIAG_UPPER_LIMIT;
+ }
+
+ class CustomDiagDesc {
+ LLVM_PREFERRED_TYPE(diag::Severity)
+ unsigned DefaultSeverity : 3;
+ LLVM_PREFERRED_TYPE(Class)
+ unsigned DiagClass : 3;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned ShowInSystemHeader : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned ShowInSystemMacro : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasGroup : 1;
+ diag::Group Group;
+ std::string Description;
+
+ auto get_as_tuple() const {
+ return std::tuple(DefaultSeverity, DiagClass, ShowInSystemHeader,
+ ShowInSystemMacro, HasGroup, Group,
+ std::string_view{Description});
+ }
+
+ public:
+ CustomDiagDesc(diag::Severity DefaultSeverity, std::string Description,
+ unsigned Class = CLASS_WARNING,
+ bool ShowInSystemHeader = false,
+ bool ShowInSystemMacro = false,
+ std::optional<diag::Group> Group = std::nullopt)
+ : DefaultSeverity(static_cast<unsigned>(DefaultSeverity)),
+ DiagClass(Class), ShowInSystemHeader(ShowInSystemHeader),
+ ShowInSystemMacro(ShowInSystemMacro), HasGroup(Group != std::nullopt),
+ Group(Group.value_or(diag::Group{})),
+ Description(std::move(Description)) {}
+
+ std::optional<diag::Group> GetGroup() const {
+ if (HasGroup)
+ return Group;
+ return std::nullopt;
+ }
+
+ diag::Severity GetDefaultSeverity() const {
+ return static_cast<diag::Severity>(DefaultSeverity);
+ }
+
+ Class GetClass() const { return static_cast<Class>(DiagClass); }
+ std::string_view GetDescription() const { return Description; }
+ bool ShouldShowInSystemHeader() const { return ShowInSystemHeader; }
+
+ friend bool operator==(const CustomDiagDesc &lhs,
+ const CustomDiagDesc &rhs) {
+ return lhs.get_as_tuple() == rhs.get_as_tuple();
+ }
+
+ friend bool operator<(const CustomDiagDesc &lhs,
+ const CustomDiagDesc &rhs) {
+ return lhs.get_as_tuple() < rhs.get_as_tuple();
+ }
+ };
+
+ struct GroupInfo {
+ LLVM_PREFERRED_TYPE(diag::Severity)
+ unsigned Severity : 3;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasNoWarningAsError : 1;
};
private:
/// Information for uniquing and looking up custom diags.
std::unique_ptr<diag::CustomDiagInfo> CustomDiagInfo;
+ std::unique_ptr<GroupInfo[]> GroupInfos = []() {
+ auto GIs = std::make_unique<GroupInfo[]>(
+ static_cast<size_t>(diag::Group::NUM_GROUPS));
+ for (size_t i = 0; i != static_cast<size_t>(diag::Group::NUM_GROUPS); ++i)
+ GIs[i] = {{}, false};
+ return GIs;
+ }();
public:
DiagnosticIDs();
@@ -202,7 +286,35 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
// FIXME: Replace this function with a create-only facilty like
// createCustomDiagIDFromFormatString() to enforce safe usage. At the time of
// writing, nearly all callers of this function were invalid.
- unsigned getCustomDiagID(Level L, StringRef FormatString);
+ unsigned getCustomDiagID(CustomDiagDesc Diag);
+
+ // TODO: Deprecate this once all uses are removed from LLVM
+ // [[deprecated("Use a CustomDiagDesc instead of a Level")]]
+ unsigned getCustomDiagID(Level Level, StringRef Message) {
+ return getCustomDiagID([&]() -> CustomDiagDesc {
+ switch (Level) {
+ case DiagnosticIDs::Level::Ignored:
+ return {diag::Severity::Ignored, std::string(Message), CLASS_WARNING,
+ /*ShowInSystemHeader*/ true};
+ case DiagnosticIDs::Level::Note:
+ return {diag::Severity::Fatal, std::string(Message), CLASS_NOTE,
+ /*ShowInSystemHeader*/ true};
+ case DiagnosticIDs::Level::Remark:
+ return {diag::Severity::Remark, std::string(Message), CLASS_REMARK,
+ /*ShowInSystemHeader*/ true};
+ case DiagnosticIDs::Level::Warning:
+ return {diag::Severity::Warning, std::string(Message), CLASS_WARNING,
+ /*ShowInSystemHeader*/ true};
+ case DiagnosticIDs::Level::Error:
+ return {diag::Severity::Error, std::string(Message), CLASS_ERROR,
+ /*ShowInSystemHeader*/ true};
+ case DiagnosticIDs::Level::Fatal:
+ return {diag::Severity::Fatal, std::string(Message), CLASS_ERROR,
+ /*ShowInSystemHeader*/ true};
+ }
+ llvm_unreachable("Fully covered switch above!");
+ }());
+ }
//===--------------------------------------------------------------------===//
// Diagnostic classification and reporting interfaces.
@@ -214,35 +326,36 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
/// Return true if the unmapped diagnostic levelof 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.
- static bool isBuiltinWarningOrExtension(unsigned DiagID);
+ /// This is not legal to call on NOTEs.
+ bool isWarningOrExtension(unsigned DiagID) const;
/// Return true if the specified diagnostic is mapped to errors by
/// default.
- static bool isDefaultMappingAsError(unsigned DiagID);
+ bool isDefaultMappingAsError(unsigned DiagID) const;
/// Get the default mapping for this diagnostic.
- static DiagnosticMapping getDefaultMapping(unsigned DiagID);
+ DiagnosticMapping getDefaultMapping(unsigned DiagID) const;
+
+ void initCustomDiagMapping(DiagnosticMapping &, unsigned DiagID);
- /// Determine whether the given built-in diagnostic ID is a Note.
- static bool isBuiltinNote(unsigned DiagID);
+ /// Determine whether the given diagnostic ID is a Note.
+ bool isNote(unsigned DiagID) const;
- /// Determine whether the given built-in diagnostic ID is for an
+ /// Determine whether the given diagnostic ID is for an
/// extension of some sort.
- static bool isBuiltinExtensionDiag(unsigned DiagID) {
+ bool isExtensionDiag(unsigned DiagID) const {
bool ignored;
- return isBuiltinExtensionDiag(DiagID, ignored);
+ return isExtensionDiag(DiagID, ignored);
}
- /// Determine whether the given built-in diagnostic ID is for an
+ /// Determine whether the given diagnostic ID is for an
/// extension of some sort, and whether it is enabled by default.
///
/// 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.
///
- static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault);
+ bool isExtensionDiag(unsigned DiagID, bool &EnabledByDefault) const;
/// Given a group ID, returns the flag that toggles the group.
/// For example,...
[truncated]
|
@AaronBallman Your reproducer doesn't seem to work anymore in trunk (there's probably been another change?), so I couldn't test early diagnostics anymore. If you have another reproducer I'd be happy to add it. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ends up being shockingly invasive, and I'm pretty uncomfortable about that. I realize I'm code owner of attributes here, but this touches so much of diagnostics that I don't feel comfortable being the primary reviewer, so I think we have to wait until January when Aaron comes back to get an answer here.
From the commit message, it sounds like this might introduce warnings that We found in chromium (and other large projects) that non-fatal warnings get ignored and over time just lead to a ton of warning spam in build output, which in turn leads to people tuning out warnings even more. We have the principle that diagnostics are either important, in which case they should be fatal and non-ignorable, or they aren't, in which case they should be silent. https://www.linfo.org/rule_of_silence.html is along the same lines. So it'd be nice if (assuming I read the PR description correctly) there was a way to force all warnings into errors. (I think |
FWIW, that's already the case today (which we found out in the previous iteration of this): https://godbolt.org/z/nG4oWvv3s I think the commit message is talking specifically about warnings which have no warning group whatsoever, which is something we've been slowly working to get rid of:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes generally LGTM but I'd really love to hear from @kadircet as to whether this PR fully addresses the issues found before: #70976 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but I'd really love to hear from @kadircet as to whether this PR fully addresses the issues found before: #70976 (comment)
I think it mostly does (left some comments in places that it might break).
it'd be nice to also document this new behavioral change in https://clang.llvm.org/docs/AttributeReference.html#diagnose-if.
TBH I find it somewhat confusing to have a severity in diagnose_if
and an existing diagnostic group, which already has its own severity. It isn't obvious to me how the severity for such a diagnotic should be configured. Does the command line options take precedence, or the annotation in code? IME mostly the latter takes over in clang, but, IIUC, we're doing the opposite here. Since I was late the RFC, I am not pushing back on the change, but just wanted to share my thoughts. So feel free to ignore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I find it somewhat confusing to have a severity in
diagnose_if
and an existing diagnostic group, which already has its own severity.
Diagnostic groups don't have severity. Individual diagnostics have severity. This just exposes the same semantics as the tablegen files. i.e. you specify a default and if that default is overridden by the command line or pragmas that severity is used instead. I'm not sure where the confusion is.
67c264e
to
e2750ef
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!
This just exposes the same semantics as the tablegen files.
alright, i guess I was missing this perspective. that makes sense now, thanks for the explanation!
…n, take 2 This is take two of llvm#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.
e2750ef
to
0f1a111
Compare
It looks like one of the header changes here is expensive, adding 0.5% to the time to build clang. Per-file breakdown: https://llvm-compile-time-tracker.com/compare_clang.php?from=aab25f20f6c06bab7aac6fb83d54705ec4cdfadd&to=0865ecc5150b9a55ba1f9e30b6d463a66ac362a6&stat=instructions%3Au&sortBy=interestingness Possibly the DiagnosticCategories.h include in DiagnosticIDs.h? Or maybe the additional code in the DiagnosticIDs.h header? Is it possible to implement this feature in a way that doesn't impact build times? |
I guess it's be possible to move the |
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.