-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Cover remaining tinyformat usages in CheckFormatSpecifiers #30999
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
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process. ConflictsNo conflicts as of last run. |
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.
d49dfaf looks correct, but I am not sure the others.
// Helper to allow compile-time sanity checks while providing the number of | ||
// args directly. Normally PassFmt<sizeof...(Args)> would be used. | ||
template <unsigned NumArgs> | ||
inline void PassFmt(util::ConstevalFormatString<NumArgs> fmt) |
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.
in cba51f2: Not sure about turning the passing one into a runtime check from a compile-time check. Previously it was trivial to compile a single unit (this test) to sanity check the parser, as well as check the compile failures for various errors, by simply looking at the compile output. Also, the code was as close as possible to the real code, serving as documentation of how to use it.
Now, checking the passing cases requires not only compiling, but also linking and executing the test. Also, triggering a compile error to see that it works and to see how it looks is harder.
I understand you want better error messages on failure, but changing the passing cases isn't required for that.
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.
Valid complaint, I've added a consteval ValidFormatSpecifiers
local delegate and split the valid tests from the BOOST_CHECK_EXCEPTION
s - this way failures still show the correct lines both for the valid and invalid tests.
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.
What is the benefit of ValidFormatSpecifiers
over the existing PassFmt
, other than dropping the code coverage stats?
Seems fine to update the comment below to say // Execute compile-time check again at run-time to get code coverage stats.
, but not sure about dropping it.
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.
I've added the comment back, that's indeed important context.
Compared to PassFmt
I found the ValidFormatSpecifiers
to be more specific (I'm not a fan of abbrvs and // comments).
Don't have strong preference here, I can be convinced to rename it back, if you do.
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.
Compared to
PassFmt
I found theValidFormatSpecifiers
to be more specific (I'm not a fan of abbrvs and // comments).
I don't care about naming, so if you want to rename PassFmt
to something else, this is fine. However, the //
comment isn't useless: It explains that the goal of this helper function is to be close as possible to the real code (and document the only difference). I found that useful as a single compilation unit that serves as a close proxy to the real code, with almost the same compile-time error messages (and behavior).
I understand you want better error messages on failure, but changing the behavior of the passing cases isn't required for that.
Generally, if there isn't a reason to change something, it is better to leave the code as-is, because it was most likely intentionally written in that way.
src/util/string.h
Outdated
* | ||
* @note Counting of `*` dynamic width and precision fields (such as `%*c`, | ||
* `%2$*3$d`, `%.*f`) is not implemented to minimize code complexity as long as | ||
* they are not used in the codebase. Usage of these fields is not counted and | ||
* can lead to run-time exceptions. Code wanting to use the `*` specifier can | ||
* side-step this struct and call tinyformat directly. |
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.
Why remove this comment? format("'%1$*3$s %2$-*3$s'", "hi", "w", 12)
is still unsupported and parsed incorrectly at compile time.
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.
Added back the part that I think is relevant, let me know if you'd like me to rewrite it.
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.
Those are dynamic width fields, so I still don't understand why you remove that from the 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.
Because we do have some dynamic width support for the values that were used in the codebase.
But I've reverted the original comment (but deleted %*c
which is a compile-time failure now).
23f2887
to
44aa62e
Compare
* Renamed `Detail_CheckNumFormatSpecifiers` to `CheckFormatSpecifiers` since we're checking more than the number of parameters * Moved it out of `ConstevalFormatString` to make it easier to test * Inline `FailFmtWithError` (and rename `PassFmt` to `ValidFormatSpecifiers`) in tests to provide better errors messages on failure (e.g. line number)
They were used in bitcoin-cli
It's not supported in tinyformat: https://github.com/bitcoin/bitcoin/blob/master/src/tinyformat.h#L843-L845
44aa62e
to
6e4935d
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.
As mentioned previously, it looks like there is one correct commit. However, I have a hard time seeing how the others are useful in a great picture, given that some of them are incomplete anyway.
// Helper to allow compile-time sanity checks while providing the number of | ||
// args directly. Normally PassFmt<sizeof...(Args)> would be used. | ||
template <unsigned NumArgs> | ||
inline void PassFmt(util::ConstevalFormatString<NumArgs> fmt) |
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.
Compared to
PassFmt
I found theValidFormatSpecifiers
to be more specific (I'm not a fan of abbrvs and // comments).
I don't care about naming, so if you want to rename PassFmt
to something else, this is fine. However, the //
comment isn't useless: It explains that the goal of this helper function is to be close as possible to the real code (and document the only difference). I found that useful as a single compilation unit that serves as a close proxy to the real code, with almost the same compile-time error messages (and behavior).
I understand you want better error messages on failure, but changing the behavior of the passing cases isn't required for that.
Generally, if there isn't a reason to change something, it is better to leave the code as-is, because it was most likely intentionally written in that way.
* @note Counting of `*` dynamic width and precision fields (such as | ||
* `%2$*3$d`, `%.*f`) is not implemented to minimize code complexity as long as | ||
* they are not used in the codebase. Usage of these fields is not counted and |
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.
not sure about implementing a random and specific subset of *
in specifiers. I think it is easier to either fully support them, or not at all. But having developers read the parser to understand which subset they are allowed to use may be causing more frustration than solving any real issue.
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.
not implemented to minimize code complexity as long as they are not used in the codebase
I've implemented the part that was used, not a "random subset"
* `%2$*3$d`, `%.*f`) is not implemented to minimize code complexity as long as | ||
* they are not used in the codebase. Usage of these fields is not counted and | ||
* can lead to run-time exceptions. Code wanting to use the `*` specifier can | ||
* side-step this struct and call tinyformat directly. | ||
*/ | ||
constexpr static void CheckFormatSpecifiers(std::string_view str, unsigned num_params) |
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.
Not sure about moving this out. This will break the doxygen comment above. Also, it drops the "detail-namespace".
Generally, I think that test-only code should follow the real code, not the other way round. As long as real code is testable, optimizing other parts of the unit tests doesn't seem too useful, especially if it breaks the existing construct and documentation.
I'm closing it for lack of interest, feel free to cherry-pick changes to other PRs |
Split out of #30928 (comment)
The current string formatter couldn't validate every string format template that we were using.
Extended it with dynamic widths, fixed a number parsing bug that could go over the string's content and added a
%n
validation.