Skip to content

Conversation

maflcko
Copy link
Member

@maflcko maflcko commented Oct 4, 2023

Generally, compile-time checks should be close to the code that use them. Especially, since compat/assumptions.h is only included in one place, where iwyu suggests to remove it.

Fix all issues:

  • The NDEBUG check is used in util/check, so it is redundant in compat/assumptions.h.
  • The __cplusplus check is redundant with doc/dependencies.md (see commit message).
  • Add missing // IWYU pragma: keep to avoid removing the include by accident.

MarcoFalke added 3 commits October 4, 2023 11:05
The check is already done in util/check.h, which is more widely
included.
It is unclear what the goal of this check is, given that the value may
need to be set lower for the mimimum supported version of compilers that
forgot to bump the value, see
bitcoin#28349 (comment) .

The minimum supported compiler versions are already documented in
doc/dependencies.md and using an older compiler will already result in a
compile failure, so this check can be removed as redundant. Especially
given that it is only included in one file, where iwyu suggests to
remove it.
Also add the <IWYU pragma: keep> to avoid removing it by accident.
@DrahtBot
Copy link
Contributor

DrahtBot commented Oct 4, 2023

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage

For detailed information about the code coverage, see the test coverage report.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK TheCharlatan, theuni, achow101
Concept ACK fanquake

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #28674 ([POC] C++20 std::endian by fanquake)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@hebasto
Copy link
Member

hebasto commented Oct 4, 2023

Also see #20274 and #20274 (comment) particularly.

@maflcko
Copy link
Member Author

maflcko commented Oct 4, 2023

Also see #20274 and #20274 (comment) particularly.

How would you enforce this? Include assumptions.h in every file where assert() is used? Not sure about that. A better approach might be to disallow assert() completely and force the use of Assert() (thus forcing the util/check include and compile-time check). However, that seems unrelated to the changes here.

Also, have you seen the commit message, which explains that util/check is included in more places than assumptions.h? You can check this via:

$ git grep 'include <util/check.h' | wc -l
67
$ git grep 'include <compat/assumptions.h' | wc -l
1

Copy link
Contributor

@TheCharlatan TheCharlatan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that this change moves the remaining assumption checks to where they are actually used (serialize.h). Checking the standard version again at compile time is kind of weird, especially if it is only done for files that include the assumption header.
I was thinking about this in the context of the kernel library currently not including the assumption header. Currently, a user just compiling the library would not get these compile-time checks, since the kernel does not use the one file that includes the assumption header. This PR improves on this current status.

De-duplicating the NDEBUG check between check.h and assumptions.h seem like a slight improvement to me. I don't think leaving it in assumptions.h for documentation purposes is a compelling reason.

ACK 8888753

Copy link
Contributor

@TheCharlatan TheCharlatan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK fa1a384

Copy link
Member

@theuni theuni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK. Largely agree with @TheCharlatan, except I think the belt-and-suspenders std version check is fine to keep around.

// ISO Standard C++17 [cpp.predefined]p1:
// "The name __cplusplus is defined to the value 201703L when compiling a C++
// translation unit."
static_assert(__cplusplus >= 201703L, "C++17 standard assumed");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the harm in leaving this? It could be that it's possible to compile certain parts of the code as c++14, but we want to document through code that c++17 is THE supported standard.

For ex, I have no idea, but it may currently be possible (or possible soon, after the next refactors) to build an app using libbitcoinkernel's headers in c++14 mode. If that's the case, we want to force that to be an error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The harm is that no one knows what value to put here, see #28349 (comment) . Basically we'd have to go out and hand-pick the supported compilers and then ask them for their __cplusplus value and then put the minimum of all of them here. That seems backward.

I think a better approach would be to just write the code that the presumed supported compilers can compile correctly.

If there is a feature in a C++ version that we rely on explicitly in the code, I don't think anything needs to be done, because either a compiler can compile the code or it can't. For example, std::span. Using std::span and in the same file adding a static_assert that __cplusplus>=201709 (because GCC-10 sets that) doesn't make sense. A bit better would be to use the feature test macro for std::span, which is __cpp_lib_span | 202002L. Though, I don't see the benefit in that, over just using std::span directly.

If there is a feature in a C++ version that we rely on implicitly. For example, the epoch assumption in C++20 std::chrono, it could make sense to put the compile time assumption in our util/time.h header directly. (Either with a feature test macro or by using C++20 chrono code in the header)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference, __cpp_lib_span seems to work correctly: https://godbolt.org/z/4fsWE8WGf

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, issues (sorta kinda) like this are the ones I'm trying to guard against here: #27930 .

In that case, the definition of things changed in c++20/23. Ideally we'd be able to select exactly one behavior we're relying on (old or new) and fail to compile otherwise.

But yeah, I get that the state of things isn't perfect, so I don't care too much.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, the definition of things changed in c++20/23. Ideally we'd be able to select exactly one behavior we're relying on (old or new) and fail to compile otherwise.

Ok, I see, but then a check would need to be added for the upper bound, not the lower bound (which is removed in this pull). Currently there is no upper bound, so maybe it can be added in a separate/unrelated/parallel pull request?

Though, generally, we've been trying to also compile the codebase with the next major version of C++, so that any deprecation issues or other bugs would be caught early, ideally when new code is written. Thus, the code can be assumed to be (mildly) tested and working on the next version of C++ as well.

So I am not sure if adding an upper bound makes sense, because it would make testing minimally harder, such as the internal testing Microsoft did in #27930. (I understand they can just remove the one-line static assert, so no strong opinion).

@@ -7,7 +7,10 @@
#define BITCOIN_SERIALIZE_H

#include <attributes.h>
#include <compat/assumptions.h> // IWYU pragma: keep
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is that this is basically our lowest-level header? Or because these assumptions mostly involve serialization?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both: yes. I think anything that involves consensus/kernel would include this header. Also, the assumptions are used in serialize. (Also for block heights and in the wallet, ..., but all those include serialize as well).

@fanquake
Copy link
Member

Concept ACK. We need to fixup/remove the __cplusplus so we can do C++20 while also supporting GCC 10.

@maflcko
Copy link
Member Author

maflcko commented Nov 16, 2023

Concept ACK. We need to fixup/remove the __cplusplus so we can do C++20 while also supporting GCC 10.

Yeah, it would be a bit cleaner style-wise, if this was merged before C++20. However, it is not a blocker, because the check accepts anything greater than C++17, which should always pass for all supported compilers:

static_assert(__cplusplus >= 201703L, "C++17 standard assumed");

@maflcko
Copy link
Member Author

maflcko commented Nov 16, 2023

I was mostly waiting for a re-reply from @theuni and @hebasto. Though, given that they haven't replied in more than a month now, I presume they are fine with this pull in the current form?

Copy link
Member

@theuni theuni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK fa1a384

// ISO Standard C++17 [cpp.predefined]p1:
// "The name __cplusplus is defined to the value 201703L when compiling a C++
// translation unit."
static_assert(__cplusplus >= 201703L, "C++17 standard assumed");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, issues (sorta kinda) like this are the ones I'm trying to guard against here: #27930 .

In that case, the definition of things changed in c++20/23. Ideally we'd be able to select exactly one behavior we're relying on (old or new) and fail to compile otherwise.

But yeah, I get that the state of things isn't perfect, so I don't care too much.

@DrahtBot DrahtBot requested a review from fanquake November 16, 2023 17:53
@achow101
Copy link
Member

ACK fa1a384

@achow101 achow101 merged commit 16b5b4b into bitcoin:master Nov 28, 2023
@maflcko maflcko deleted the 2310-assume- branch November 28, 2023 22:00
@bitcoin bitcoin locked and limited conversation to collaborators Nov 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants