-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[diagtool] Make the BuiltinDiagnosticsByID table sorted #120321
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
Conversation
|
@llvm/pr-subscribers-clang Author: Karl-Johan Karlsson (karka228) ChangesWhen building with -DLLVM_ENABLE_EXPENSIVE_CHECKS=ON with a recent libstdc++ (e.g. from gcc 13.3.0) the testcase The reason for this error is that std::lower_bound is called on BuiltinDiagnosticsByID without it being entirely sorted. Calling std::lower_bound If the range is not sorted, the behavior of this function is undefined. This is detected when building with expensive checks. To make BuiltinDiagnosticsByID sorted we need to slightly change the order the inc-files are included. Full diff: https://github.com/llvm/llvm-project/pull/120321.diff 1 Files Affected:
diff --git a/clang/tools/diagtool/DiagnosticNames.cpp b/clang/tools/diagtool/DiagnosticNames.cpp
index eb90f082437b33..d6c80ddf72cb27 100644
--- a/clang/tools/diagtool/DiagnosticNames.cpp
+++ b/clang/tools/diagtool/DiagnosticNames.cpp
@@ -31,7 +31,6 @@ static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFER, CATEGORY) \
{#ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t)},
#include "clang/Basic/DiagnosticCommonKinds.inc"
-#include "clang/Basic/DiagnosticCrossTUKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#include "clang/Basic/DiagnosticSerializationKinds.inc"
@@ -39,6 +38,7 @@ static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticCommentKinds.inc"
+#include "clang/Basic/DiagnosticCrossTUKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
When building with -DLLVM_ENABLE_EXPENSIVE_CHECKS=ON with a recent
libstdc++ (e.g. from gcc 13.3.0) the testcase
clang/test/Misc/warning-flags-tree.c fail with the message:
+ diagtool tree --internal
.../include/c++/13.3.0/bits/stl_algo.h:2013:
In function:
_ForwardIterator std::lower_bound(_ForwardIterator, _ForwardIterator,
const _Tp &, _Compare) [_ForwardIterator = const
diagtool::DiagnosticRecord *, _Tp = diagtool::DiagnosticRecord, _Compare
= bool (*)(const diagtool::DiagnosticRecord &, const
diagtool::DiagnosticRecord &)]
Error: elements in iterator range [first, last) are not partitioned by the
predicate __comp and value __val.
Objects involved in the operation:
iterator "first" @ 0x7ffea8ef2fd8 {
}
iterator "last" @ 0x7ffea8ef2fd0 {
}
The reason for this error is that std::lower_bound is called on
BuiltinDiagnosticsByID without it being entirely sorted. Calling
std::lower_bound If the range is not sorted, the behavior of this
function is undefined. This is detected when building with expensive
checks.
To make BuiltinDiagnosticsByID sorted we need to slightly change the
order the inc-files are included.
|
Added some reviewers based on people that have touched code related to "diagnostics" (but don't really know much about the fix, nor who might know anything about this particular code in diagtool). Feel free to redirect to someone else (or let me know if I should try to find other reviewers). |
|
|
||
| // FIXME: Is it worth having two tables, especially when this one can get | ||
| // out of sync easily? | ||
| // clang-format off |
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.
Add a comment about why we turn off clang-format:
// Turn off clang-format, as the order of the includes are important
// to make sure the table is sorted.
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.
also it's unclear where the "ground truth" for this order is coming from. AFAICT, order is defined by https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Basic/DiagnosticIDs.h#L49-L65
and enforced by very subtle interactions between tablegen and how particular headers include these.
since this order needs to be preserved in multiple places, can you put together a wrapper header, which includes individual diagnostic kinds in the specific order and explain the relationship between these pieces? (I'd rather have a solution that puts all of this logic into tablegen instead, generating enums with a particular order once, but I can see that's a much bigger change that you might not want to sign up).
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.
"since this order needs to be preserved in multiple places, can you put together a wrapper header, which includes individual diagnostic kinds in the specific order and explain the relationship between these pieces?"
@kadircet I added a new file DiagnosticsID.inc as a "wrapper header".
| #include "clang/Basic/DiagnosticParseKinds.inc" | ||
| #include "clang/Basic/DiagnosticASTKinds.inc" | ||
| #include "clang/Basic/DiagnosticCommentKinds.inc" | ||
| #include "clang/Basic/DiagnosticCrossTUKinds.inc" |
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.
Verify the changed include order by adding an assert in getDiagnosticForID below:
// The requirement for lower_bound to produce a valid result it is
// enough if the BuiltinDiagnosticsByID is partitioned (by DiagID),
// but as we want this function to work for all possible values of
// DiagID sent in as argument it is better to right away check if
// BuiltinDiagnosticsByID is sorted.
assert(llvm::is_sorted(BuiltinDiagnosticsByID, orderByID) &&
"IDs in BuiltinDiagnosticsByID must be sorted.");
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 seems brittle - Maybe we should call std::sort somewhere instead?
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 seems brittle - Maybe we should call
std::sortsomewhere instead?
I agree that it is a bit brittle, but it is hard to find a good place where to insert a std::sort. As @kadircet wrote it is probably better in the future to solve this in a better way in tablegen.
|
|
||
| // FIXME: Is it worth having two tables, especially when this one can get | ||
| // out of sync easily? | ||
| // clang-format off |
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.
also it's unclear where the "ground truth" for this order is coming from. AFAICT, order is defined by https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Basic/DiagnosticIDs.h#L49-L65
and enforced by very subtle interactions between tablegen and how particular headers include these.
since this order needs to be preserved in multiple places, can you put together a wrapper header, which includes individual diagnostic kinds in the specific order and explain the relationship between these pieces? (I'd rather have a solution that puts all of this logic into tablegen instead, generating enums with a particular order once, but I can see that's a much bigger change that you might not want to sign up).
Extracted the includes into a wrapper header file DiagnosticIDs.inc. Added is_sorted assert.
Renamed DiagnosticIDs.inc to AllDiagnosticKinds.inc Minor changes in comments.
kadircet
left a 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.
thanks!
When building with -DLLVM_ENABLE_EXPENSIVE_CHECKS=ON with a recent libstdc++ (e.g. from gcc 13.3.0) the testcase
clang/test/Misc/warning-flags-tree.c fail with the message:
The reason for this error is that std::lower_bound is called on BuiltinDiagnosticsByID without it being entirely sorted. Calling std::lower_bound If the range is not sorted, the behavior of this function is undefined. This is detected when building with expensive checks.
To make BuiltinDiagnosticsByID sorted we need to slightly change the order the inc-files are included. The include of DiagnosticCrossTUKinds.inc in DiagnosticNames.cpp is included too early and should be moved down directly after DiagnosticCommentKinds.inc.
As a part of pull request the includes that build up BuiltinDiagnosticsByID table are extracted into a common wrapper header file AllDiagnosticKinds.inc that is used by both clang and diagtool.