Skip to content
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

Discussion: upgrading to C++17 #16684

Closed
dongcarl opened this issue Aug 22, 2019 · 37 comments
Closed

Discussion: upgrading to C++17 #16684

dongcarl opened this issue Aug 22, 2019 · 37 comments
Milestone

Comments

@dongcarl
Copy link
Contributor

dongcarl commented Aug 22, 2019

UPDATE: Release plan summary from April 2nd, 2020 meeting:

C++11 Compat C++17 Compat Gitian/Guix Release
v0.20 ✔️ if easy C++11
v0.21 ✔️ ✔️ C++17
v0.22 ✔️ C++17

Meeting logs can be found here: http://www.erisian.com.au/meetbot/bitcoin-core-dev/2020/bitcoin-core-dev.2020-04-02-19.01.log.html


There were some discussion around upgrading to C++17. It seems to be able to give us library and language features that will simplify future code. For example, for library features, our current optional.h is just a wrapper around boost::optional, and can be replaced with std::optional. Other library features that might be useful include (non-exhaustively): std::variant, the file system library, and std::shared_mutex. @elichai has kindly provided a table summarizing features useful for Bitcoin Core here: #16684 (comment).

I want to apologize for misspeaking about C++17 requiring GCC8, that is untrue, and I believe all of the features we would want will be covered by GCC7, and some by GCC6.

For some background on the cons: #13356 (comment)


Default GCC versions major distros (as of Aug 22nd):

Operating System release version GCC version Notes
✔️ Debian Buster 8.3
✔️ Ubuntu 18.04 LTS 7.4
✔️ Fedora 30 9.1.1
✔️ RHEL 8 8.2
CentOS 7 4.8.5 CentOS 8 (GCC 8.2) is being released as we speak

In-depth code examples of

C++17 features: https://github.com/AnthonyCalandra/modern-cpp-features/blob/master/CPP17.md
C++14 features: https://github.com/AnthonyCalandra/modern-cpp-features/blob/master/CPP14.md


Here are some compatibility tables from https://en.cppreference.com/w/cpp/compiler_support#cpp17

Library features:
Screen Shot 2019-08-22 at 19 39 24

Language features:
Screen Shot 2019-08-22 at 19 38 32

@practicalswift
Copy link
Contributor

Some C++14 features worth mentioning as well: std::make_unique, more expressive constexpr functions allowed, return type deduction (auto foo() { … }), [[deprecated]], binary literals (0b10101110) and polymorphic lambdas ([](auto foo) { … }).

@elichai
Copy link
Contributor

elichai commented Aug 22, 2019

A table on features in C++14/17 which I think would be very useful (feel free to comment if you disagree or think other stuff should be added)

Name Important Nice to have Boost Replacement
std::variant ✔️
std::make_unique
Variable Templates
Conditions in constexpr functions ✔️
auto in lambdas params
Binary literals ✔️
std::filesystem ✔️ ✔️
std::optional ✔️
[[nodiscard]]+[[fallthrough]] ✔️
de-structuring initialization
shared_mutex + scoped_lock + shared_lock ✔️

@elichai
Copy link
Contributor

elichai commented Oct 3, 2019

Another reason we might want to upgrade:
very powerful const expressions. both c++14 and 17 made constexpr way more powerfull.
such that we could start making a lot of functions constexpr which might maybe result in some performance increase (for functions that might be able to be evaluated at compile time)

@maflcko
Copy link
Member

maflcko commented Oct 3, 2019

Is C++17 supported on Ubuntu Xenial, Debian 9, and the *BSD operating systems?

@ysangkok
Copy link

ysangkok commented Oct 3, 2019

Debian 9 ships GCC 6.3 according to the development packages listing. GCC 6 is listed as supporting some features of C++17 experimentally.

Ubuntu Xenial ships with a default GCC 5.3, which is even older. A PPA offers newer GCC versions: ~ubuntu-toolchain-r

@laanwj
Copy link
Member

laanwj commented Dec 9, 2019

Added 0.21 milestone optimistically

@sanjaykdragon
Copy link
Contributor

I agree with moving to C++17, but when do we plan to move to the soon coming C++20?

@sipa
Copy link
Member

sipa commented Jan 3, 2020

@sanjaykdragon It's not that easy, as we need to remain compatible with various stable Linux distributions, which don't update their C++ compilers that frequently (or at all, after release of a particular distro version).

C++20 does not exist yet, so that seems entirely out of scope.

@sanjaykdragon
Copy link
Contributor

@sanjaykdragon It's not that easy, as we need to remain compatible with various stable Linux distributions, which don't update their C++ compilers that frequently (or at all, after release of a particular distro version).

C++20 does not exist yet, so that seems entirely out of scope.

Are we just waiting for linux distributions to become compatible with C++17 for a migration?

@practicalswift
Copy link
Contributor

practicalswift commented Jan 9, 2020

Of the 13 build jobs we have in Travis it looks like three build jobs use compilers without C++17 support: CentOS 7, Ubuntu 16.04 (Xenial) and macOS Sierra (10.12). Sounds correct? :)

@laanwj
Copy link
Member

laanwj commented Jan 13, 2020

Are we just waiting for linux distributions to become compatible with C++17 for a migration?

Yes, that's the main factor holding it up.

@sanjaykdragon
Copy link
Contributor

Just a comment / improvement to make when we move to C++17:
use std::string_view more.

@practicalswift
Copy link
Contributor

practicalswift commented Jan 30, 2020

@sanjaykdragon std::string_view has really sharp edges with regards to life-time -- some would even claim it encourages use-after-free bugs.

I think our recommendation should be to try to avoid std::string_view in the general case, and use it only in places where it is both a.) needed for performance reasons (as demonstrated by benchmarks), and b.) guaranteed to be safe :)

@sanjaykdragon
Copy link
Contributor

@sanjaykdragon std::string_view has really sharp edges -- some would even claim it encourages use-after-free bugs. I think our recommendation should be to avoid std::string_view in the general case :)

I'll leave this discussion until we actually start moving to C++17, but I think string_view would bring a lot of benefits if we do use it

@dongcarl
Copy link
Contributor Author

dongcarl commented Apr 2, 2020

Updated issue description with release plan summary from April 2nd, 2020 meeting.

@JeremyRubin
Copy link
Contributor

On backporting:

I think the rough plan is to, as of 0.22, no longer worry about backporting features to 0.20 or below unless easy to do. Already we don't regularly backport 2 releases back, but end users may be doing their own back porting.

This means that modules like consensus can start using c++17 features more aggressively in 0.22, and mildly in 0.21 where there's a shim that can be implemented without much overhead.

An open question for 0.21 is if the backport shims can rely on other libraries; e.g., using boost option shim (which we already have in the code, but could cut with a c++17 build). For example, libconsensus 0.20 could be built with c++17 with no shims, and c++11 with shims, that might be sufficient for most users. Instead of dealing with this complex build issue, we can also wait until 0.22 to deploy boost in those contexts. The shim question is important because it points to needing a more rigorous definition of what c++11 compatibility means, but that seems to be an open question.

Personally, I think if 0.20 can be c++17 built, we can immediately start using c++17 APIs in new code for 0.21, and make 0.20 backports c++17 released without shims (by the time there is an important backport, c++17 support will only be better!), but this is probably a bit more aggressive than necessary.

@JeremyRubin
Copy link
Contributor

To clarify; there is a difference between modules needed "compatibility level" without requiring linking in boost. A good rule of thumb is if in your module boost is already linked, then it would be OK to use a backport shim in it. This rules out libconsensus afaik; and is relevant to e.g. the work on Span.

I don't have a good understanding of who is using libconsensus to comment on how bad it would be to require a backport to either use ++17 or link in boost, so I'll demur on making a policy there.

@sipa
Copy link
Member

sipa commented Apr 2, 2020

FWIW, with #18468, it seems the codebase is entirely C++17 compilable.

laanwj added a commit that referenced this issue Apr 30, 2020
c31cbe7 Add C++17 test to Travis (Pieter Wuille)
7829685 Add configure option for c++17 (Pieter Wuille)
0fbde48 Support conversion between Spans of compatible types (Pieter Wuille)
7cbfebb Update ax_cxx_compile_stdcxx.m4 (Pieter Wuille)

Pull request description:

  This adds a `--enable-c++17` option to the configure script, fixes the only C++17 incompatibility (with a commit taken from #18468), and adds a Travis test for it.

  This is all off by default, and release builds remain C++11.

  It implements the first step of the plan in #16684.

ACKs for top commit:
  elichai:
    tACK c31cbe7
  practicalswift:
    Tested ACK c31cbe7
  hebasto:
    ACK c31cbe7, tested on Linux Mint 19.3 both C++11 and C++17 modes. Compiled and passed tests locally.

Tree-SHA512: a4b00776dbceef9c12abbb404c6bcd48f7916ce24c8c7a14116355f64e817578b7fcddbedd5ce435322319d1e4de43429b68553f4d96d970c308fe3e3e59b9d1
@laanwj
Copy link
Member

laanwj commented Oct 8, 2020

Moving this to the 0.22 milestone, I don't think there's anything left to do here for 0.21.

@theuni
Copy link
Member

theuni commented Nov 12, 2020

Noting this here so it doesn't get lost....

I'm afraid it'll be quite some time before we can safely use c++17's std::shared_mutex.

When working on another project which uses read/write locks, we ran into this nasty glibc bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23861.

Specifically the problem is that totally valid uses of std::shared_mutex may result in a deadlock deep in glibc.

Unfortunately, the shared mutex path (which we can't hit currently) was broken in glibc for quite a while. It was fixed here: https://sourceware.org/git/?p=glibc.git;a=commit;h=f21e8f8ca466320fed38bdb71526c574dae98026 in 2018.

Ubuntu (for ex) only got the backported fix last week: https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1864864

So until the world has moved on from this glibc bug, I'm afraid we'll need to pass on read/write locks :(

@maflcko
Copy link
Member

maflcko commented Nov 12, 2020

We should probably determine the version of libc that has this bug fixed (2.29?) and put that with a comment in the source code?

@ysangkok
Copy link

@theuni The bugzilla link you posted is for bug 23861. But the Ubuntu bug you posted links 23844 (a different bug number). I am letting you know since I found it confusing. @MarcoFalke Bug 23844 was deferred from 2.29 according to release notes.

@ilyapopov
Copy link

ilyapopov commented Nov 12, 2020

@theuni This Ubuntu bug is about Ubuntu 18.04 Bionic.

Newer versions of Ubuntu, such as 20.04 LTS and 20.10 already have had the fixed version from the beginning.

fanquake added a commit that referenced this issue Nov 19, 2020
fac7198 Use std::make_unique (MarcoFalke)
faaee81 build: Require C++17 compiler (MarcoFalke)

Pull request description:

  Developers have been compiling with C++17 for a few months now (fuzz tests and the msvc build have it even enabled by default). According to #16684, the 22.0 release shall be compiled with C++17 enabled.

  This only sets the build flag, any other changes need more discussion and can be done later.

ACKs for top commit:
  elichai:
    utACK fac7198
  hebasto:
    ACK fac7198, I've locally compiled on ARM 32bit SBC without GUI.
  fanquake:
    ACK fac7198

Tree-SHA512: 53eb40ba5d496376a2d2cf16e2000bef36616cc2a3696c3ec59a5366e41fa8b872817a7ca21751f030f9c1efb339dfa63cc655eaa5199b9a3d2e52c2de0ccb29
@maflcko
Copy link
Member

maflcko commented Nov 20, 2020

Closing this for now. If discussions about specific features are needed, they should go to #20419 or #19183 or whatever pull request proposes them.

@maflcko maflcko closed this as completed Nov 20, 2020
@maflcko
Copy link
Member

maflcko commented Nov 23, 2020

std::fs discussion here: #20460

laanwj added a commit to bitcoin-core/gui that referenced this issue Nov 23, 2020
a52ecc9 build: set minimum supported macOS to 10.14 (fanquake)

Pull request description:

  This is a requirement for C++17 support. See my comments [here](bitcoin/bitcoin#16684 (comment)):

  > You cannot use std::get with std::variant on macOS < 10.14, because Apples libc++ doesn't support the std::bad_variant_access exception. [Relevant comment](bitcoin/bitcoin#19183 (comment)) in #19183.

  > While we could work around this in our own code, using std::get_if, this would still be a problem for 3rd-party dependencies.

  > I've been testing Qt 5.15LTS (we'll have to enable C++17 in qt, and may upgrade to a newer version at the same time), and you can't enable -std c++17, while targeting a macOS deployment version < 10.14, configuring will fail. They are making use of std::get with std::variant throughout their cocoa code.

  We would have to had to have bumped to at least 10.13 in any case, as Qt 5.15 (#19716) [requires 10.13+](https://doc.qt.io/qt-5/supported-platforms.html).

ACKs for top commit:
  hebasto:
    ACK a52ecc9, I have reviewed the code and it looks OK, I agree it can be merged.

Tree-SHA512: f669b2fc777aeea1e9afdbbc7bd9afe3997418211db6ba53c934cae0e62a9b999603da539518c229f34961d275c9e2f315c7b022cf5fb97bd201a69c85d470cc
@ysangkok
Copy link

@MarcoFalke How old do the patched glibc version need to be before it can be assumed present? Glibc 2.30 which contains fixes for bugs 23861 and 23844 was released in August 2019, and backports are available. The bugs only affect users running old distros without updating.

@fanquake
Copy link
Member

The bugs only affect users running old distros without updating.

Ubuntu Bionic (18.04LTS) ships with glibc 2.27 and will remain supported until April 2023.

@ysangkok
Copy link

Bionic (18.04LTS) ships glibc 2.27

@fanquake Yes, but it received a backported fix as shown in the Launchpad link. All users have -updates enabled by default, so the only way you could miss it is if you didn't run apt upgrade since November. Does Core need to cater to that tiny minority that runs an LTS release but does not keep it updated? You can only use Bitcoin if you are internet-connected anyway, so what is the rationale for being internet-connected, but keeping your system buggy and vulnerable (other fixes could be more severe)?

laanwj added a commit to bitcoin-core/gui that referenced this issue Feb 1, 2021
dc8be12 refactor: remove boost::thread_group usage (fanquake)

Pull request description:

  Post #18710, there isn't much left using `boost::thread_group`, so should just be able to replace it with the standard library. This also removes the last use of `boost::thread_interrupted`.

  After this change, last piece of Boost Thread we'd be using is `boost::shared_mutex`. See the commentary [here](bitcoin/bitcoin#16684 (comment)) as to why it may be non-trivial to swap that for `std::shared_mutex` in the near future.

  Closes #17307

ACKs for top commit:
  laanwj:
    Code review re-ACK dc8be12
  MarcoFalke:
    review ACK dc8be12 🔁
  jonatack:
    Non-expert code review ACK dc8be12, also checked range-diff since last review and that local debug build is clean with gcc 10.2.1-6 on Debian

Tree-SHA512: 5510e2d760cce824234207dc86b1551ca8f21cbf3a2ce753c0254a0d03ffd83c94e449aec202fb7bd76e6fc64df783a6b70a736b0add9ece3734bb9c8ce8fc2f
laanwj added a commit to bitcoin-core/gui that referenced this issue Feb 12, 2021
060a2a6 ci: remove boost thread installation (fanquake)
06e1d7d build: don't build or use Boost Thread (fanquake)
7097add refactor: replace Boost shared_mutex with std shared_mutex in sigcache (fanquake)
8e55981 refactor: replace Boost shared_mutex with std shared_mutex in cuckoocache tests (fanquake)

Pull request description:

  This replaces `boost::shared_mutex` and `boost::unique_lock` with [`std::shared_mutex`](https://en.cppreference.com/w/cpp/thread/shared_mutex) & [`std::unique_lock`](https://en.cppreference.com/w/cpp/thread/unique_lock).

  Even though [some concerns were raised](bitcoin/bitcoin#16684 (comment)) in #16684 with regard to `std::shared_mutex` being unsafe to use across some glibc versions, I still think this change is an improvement. As I mentioned in #21022, I also think trying to restrict standard library feature usage based on bugs in glibc is not only hard to do, but it's not currently clear exactly how we do that in practice (does it also extend to patching out use in our dependencies, should we be implementing more runtime checks for features we are using, when do we consider an affected glibc "old enough" not to worry about? etc). If you take a look through the [glibc bug tracker](https://sourceware.org/bugzilla/describecomponents.cgi?product=glibc) you'll no doubt find plenty of (active) bug reports for standard library code we already using. Obviously not to say we shouldn't try and avoid buggy code where possible.

  Two other points:

  [Cory mentioned in #21022](bitcoin/bitcoin#21022 (comment)):
  > It also seems reasonable to me to worry that boost hits the same underlying glibc bug, and we've just not happened to trigger the right conditions yet.

  Moving away from Boost to the standard library also removes the potential for differences related to Boosts configuration. Boost has multiple versions of `shared_mutex`, and what you end up using, and what it's backed by depends on:
  * The version of Boost.
  * The platform you're building for.
  * Which version of `BOOST_THREAD_VERSION` is defined: (2,3,4 or 5) default=2. (see [here](https://www.boost.org/doc/libs/1_70_0/doc/html/thread/build.html#thread.build.configuration) for some of the differences).
  * Is `BOOST_THREAD_V2_SHARED_MUTEX` defined? (not by default). If so, you might get the ["less performant, but more robust"](boostorg/thread#230 (comment)) version of `shared_mutex`.

  A lot of these factors are eliminated by our use of depends, but users will have varying configurations. It's also not inconceivable to think that a distro, or some package manager might start defining something like `BOOST_THREAD_VERSION=3`. Boost tried to change the default from 2 to 3 at one point.

  With this change, we no longer use Boost Thread, so this PR also removes it from depends, the build system, CI etc.

  Previous similar PRs were #19183 & #20922. The authors are included in the commits here.
  Also related to #21022 - pthread sanity checking.

ACKs for top commit:
  laanwj:
    Code review ACK 060a2a6
  vasild:
    ACK 060a2a6

Tree-SHA512: 572d14d8c9de20bc434511f20d3f431836393ff915b2fe9de5a47a02dca76805ad5c3fc4cceecb4cd43f3ba939a0508178c4e60e62abdbaaa6b3e8db20b75b03
Fabcien added a commit to Bitcoin-ABC/bitcoin-abc that referenced this issue Aug 16, 2021
…nt in rwcollection.h

Summary:
This is possible since we use C++17.

Note that core raised some concerns about std::shared_mutex because of a couple bad glibc bugs that could cause deadlocks (bitcoin/bitcoin#16684 (comment)), so I checked that our release building version (Debian 10) was patched. As far as I can tell all our officially supported Linux are safe (all the ones we provide packages for). The only major distro I don't know for sure is CentOS 8, which runs a patched 2.28 version.

Ref T1634.

Test Plan:
  ninja all check-all
  ./contrib/teamcity/build-configurations.py build-tsan

Reviewers: #bitcoin_abc, majcosta

Reviewed By: #bitcoin_abc, majcosta

Maniphest Tasks: T1634

Differential Revision: https://reviews.bitcoinabc.org/D9877
Fabcien referenced this issue in Bitcoin-ABC/bitcoin-abc Feb 4, 2022
Summary:
> Post [[bitcoin/bitcoin#18710 | core#18710]], there isn't much left using boost::thread_group, so should just be able to replace it with the standard library. This also removes the last use of `boost::thread_interrupted`.
>
> After this change, last piece of Boost Thread we'd be using is `boost::shared_mutex`. See the commentary [[https://github.com/bitcoin/bitcoin/issues/16684#issuecomment-726214696|here]] as to why it may be non-trivial to swap that for `std::shared_mutex` in the near future.

This is a backport of [[bitcoin/bitcoin#21016 | core#21016]] and [[bitcoin/bitcoin#22433 | core#22433]]

Test Plan:
With clang + debug and (separate run) TSAN
`ninja && ninja check check-functional`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Subscribers: Fabien

Differential Revision: https://reviews.bitcoinabc.org/D10992
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

13 participants