Skip to content

Precompile boost/decimal.hpp for the tests - #1464

Merged
mborland merged 7 commits into
boostorg:developfrom
ibmibmibm:worktree-test-pch
Sep 23, 2026
Merged

mborland merged 7 commits into
boostorg:developfrom
ibmibmibm:worktree-test-pch

Conversation

@ibmibmibm

@ibmibmibm ibmibmibm commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

b2 builds test/pch.hpp once per variant and force-includes boost/decimal.hpp into every
test. The test directory then needs 1136 s of CPU with clang 22 instead of 4562 s, and 1442 s
with gcc 16 instead of 2227 s. In CI the 32-bit gcc-14 job went from 171 min to 68 min, MSVC
x64 from 118 min to 37 min and clang-win x64 from 248 min to 51 min.

A test opts out with <pch>off when it defines a library macro or declares code before the include, when it
takes a detail header on its own, or when a compiler defect needs it. Four header changes come
first, because every test sees the headers through the pch after this.

Fixes #1461

Precompile boost/decimal.hpp for the tests
  • b2 builds test/pch.hpp once per variant and force-includes it into every test.
  • A private feature adds the pch as a source to every target but the pch itself.
  • A test which defines a library macro before the include opts out with <pch>off.
  • github_issue_1384 opts out as well, because it declares a namespace boost before the
    include, and that order is what the test is about.
  • The compile tests of the separate headers opt out as well.
  • Three tests which take a detail header on its own opt out too, so that a missing include
    of that header still shows.
  • The opt-out is on a second line, so the CMake test list stays the same.
  • The pch defines _SILENCE_CXX23_DENORM_DEPRECATION_WARNING, because the MSVC standard
    library reads it when the pch parses . The Boost.Math tests define it only later.
  • GCC pch is off on MinGW, as in Boost.Math.
  • test_asinh opts out on clang 6 to 8, which fail its constexpr at C++14 with the pch.
  • github_issue_1329 and test_cbrt_from_math opt out: 32-bit GCC 12 loses the -Wstringop-overflow
    pragma of libstdc++ with the pch and then rejects the cpp_dec_float output of Boost.Multiprecision.
  • MSVC on an ARM64 host builds without the pch, because it fails to map the pch there now and then.
  • Clang 22 needs 4562 s of CPU for the test directory without the pch and 1136 s with it.
  • GCC 16 needs 2227 s without and 1442 s with it. Both numbers include the test runs.
  • In CI the 32-bit gcc-14 job went from 171 min to 68 min, MSVC x64 from 118 min to 37 min,
    and clang-win x64 from 248 min to 51 min.
Classify NaN and the infinities without a pragma or an exception
  • The float constructors of the six types tested NaN with != and ±inf with == against
    numeric_limits under a -Wfloat-equal pragma. GCC 8 to 14 do not apply the pragmas of a
    precompiled header to the templates which they instantiate in the including file, so the
    pch commit needs that region gone.
  • A NaN now comes from __builtin_isnan, which raises nothing. An ordered compare raises
    FE_INVALID for a NaN, and == or != draws the warning. MSVC has no such warning, so it
    keeps the compare with !=.
  • An infinity now comes from an ordered compare with the infinity of the type, which
    raises nothing either. Arithmetic such as inf - inf would raise FE_INVALID, and it would
    also stop the constructor of a constant expression on GCC.
  • numeric_limits is empty for __float128 on libstdc++ before GCC 16, so infinity_value
    takes the infinity of double there, which converts exactly. The old test made a
    __float128 zero an infinity and let a __float128 infinity through as a finite value.
  • compute_float80_128 tests its magnitude against max() now and loses its region too.
  • test_construct_from_nonfinite covers the zero, the infinities and NaN for the six types
    and every binary float type. It makes sure that the constructor raises no FE_INVALID and
    still gives a constant expression.
  • On GCC 8 and 13 the new test fails 18 times without this change, once for the __float128
    zero and twice for the __float128 infinities of each type.
Keep the warnings which the diagnostic pragmas hide out of the headers
  • GCC 8 to 14 do not apply the diagnostic pragmas of a precompiled header to the
    templates which they instantiate in the including file. With -Werror every test then
    fails when boost/decimal.hpp is precompiled, which the pch commit does.
  • coefficient_rounding converts the shift to unsigned before T1 takes it.
  • memcpy into a uint128, an int128 or a bit_cast result goes through a void* (the
    documented way to keep -Wclass-memaccess quiet).
  • pow10 tells the optimizer that the index is in range, or GCC 8 to 12 report
    -Warray-bounds on dead paths.
  • The whole test directory compiles without a warning on gcc 8 to 16, with and without
    the pch, and on clang 22.
Pick the fast type of from_bid by an overload instead of a specialization
  • Clang 15 to 18 drop an explicit specialization of a constrained function template when
    it comes from a precompiled header, and the from_bid<fast> calls then fail to link.
  • The fast type now has its own overload, constrained with is_fast_type_v, and the
    primary is constrained with is_ieee_type_v, so exactly one overload matches.
  • The fast overload asks for is_decimal_floating_point_v as well, because is_fast_type_v
    is the negation of is_ieee_type_v and is true for int, double and every other type.
  • test_bid_conversions makes sure that from_bid takes the six decimal types and no other.
  • The four from_bid tests compile and run at C++14, 17 and 20 with gcc and clang, and
    link with the pch on clang 15 and 16.
Name the file of the to_from_file example after its executable
  • b2 runs the variants of the example in one directory, some of them at the same time,
    and they all used example_values.txt. One variant then read a file which another one
    had removed, and exited with 1.
  • The name now comes from argv[0], so every variant has a file of its own. Two copies of
    the old example fail 4 times in 100 parallel runs, the new one never.
  • The standard allows argc to be 0, so the name falls back to a literal in that case.
  • The write side opens the file in binary mode like the read side, which matters on Windows.
  • The example exits with 1 when the write or the read fails, or when a value does not come
    back. Before, it read an uninitialized value after a short read, and a write to a full
    disk still exited with 0.
Drop the Node 20 workaround with the containers which needed it
  • Only the Ubuntu 16 and 18 containers could not run the Node 20 of actions/checkout, and
    the matrix has none of them any more.
  • The mount of /node20217 and the download into it are therefore dead, so both go.
  • ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION goes too, because no action of ci.yml needs an
    old Node any more.

@ibmibmibm
ibmibmibm force-pushed the worktree-test-pch branch 9 times, most recently from 06b2c2e to 32849c3 Compare September 22, 2026 05:55
@mborland

Copy link
Copy Markdown
Member

Hi @ibmibmibm. This looks good, but is currently marked as draft. Was there anything else you were intending to add before making it for review?

@ibmibmibm
ibmibmibm marked this pull request as ready for review September 23, 2026 13:34
@ibmibmibm

Copy link
Copy Markdown
Contributor Author

It seems that clang 6 to 8 had some issues on constexpr + pch, but i'll mark this as ready anyway.

@mborland

Copy link
Copy Markdown
Member

It seems that clang 6 to 8 had some issues on constexpr + pch, but i'll mark this as ready anyway.

Those are still running in the CI system in under an hour so not a big deal for the purposes of closing out the issue at least.

@ibmibmibm

Copy link
Copy Markdown
Contributor Author

In README.md:41-48, the project still support for GCC 8+ and Clang 6+, so we need to add other method that checks these compiler

@mborland

Copy link
Copy Markdown
Member

In README.md:41-48, the project still support for GCC 8+ and Clang 6+, so we need to add other method that checks these compiler

Those are still handled in Drone, just not on GitHub Actions. Boostorg has far more control over Drone so we can make sure those older images don't break

ibmibmibm and others added 7 commits September 24, 2026 00:12
- The float constructors of the six types tested NaN with != and ±inf with == against
  numeric_limits under a -Wfloat-equal pragma. GCC 8 to 14 do not apply the pragmas of a
  precompiled header to the templates which they instantiate in the including file, so the
  pch commit needs that region gone.
- A NaN now comes from __builtin_isnan, which raises nothing. An ordered compare raises
  FE_INVALID for a NaN, and == or != draws the warning. MSVC has no such warning, so it
  keeps the compare with !=.
- An infinity now comes from an ordered compare with the infinity of the type, which
  raises nothing either. Arithmetic such as inf - inf would raise FE_INVALID, and it would
  also stop the constructor of a constant expression on GCC.
- numeric_limits is empty for __float128 on libstdc++ before GCC 16, so infinity_value
  takes the infinity of double there, which converts exactly. The old test made a
  __float128 zero an infinity and let a __float128 infinity through as a finite value.
- compute_float80_128 tests its magnitude against max() now and loses its region too.
- test_construct_from_nonfinite covers the zero, the infinities and NaN for the six types
  and every binary float type. It makes sure that the constructor raises no FE_INVALID and
  still gives a constant expression.
- On GCC 8 and 13 the new test fails 18 times without this change, once for the __float128
  zero and twice for the __float128 infinities of each type.
- GCC 8 to 14 do not apply the diagnostic pragmas of a precompiled header to the
  templates which they instantiate in the including file. With -Werror every test then
  fails when boost/decimal.hpp is precompiled, which the pch commit does.
- coefficient_rounding converts the shift to unsigned before T1 takes it.
- memcpy into a uint128, an int128 or a bit_cast result goes through a void* (the
  documented way to keep -Wclass-memaccess quiet).
- pow10 tells the optimizer that the index is in range, or GCC 8 to 12 report
  -Warray-bounds on dead paths.
- The whole test directory compiles without a warning on gcc 8 to 16, with and without
  the pch, and on clang 22.
…tion

- Clang 15 to 18 drop an explicit specialization of a constrained function template when
  it comes from a precompiled header, and the from_bid<fast> calls then fail to link.
- The fast type now has its own overload, constrained with is_fast_type_v, and the
  primary is constrained with is_ieee_type_v, so exactly one overload matches.
- The fast overload asks for is_decimal_floating_point_v as well, because is_fast_type_v
  is the negation of is_ieee_type_v and is true for int, double and every other type.
- test_bid_conversions makes sure that from_bid takes the six decimal types and no other.
- The four from_bid tests compile and run at C++14, 17 and 20 with gcc and clang, and
  link with the pch on clang 15 and 16.
- b2 runs the variants of the example in one directory, some of them at the same time,
  and they all used example_values.txt. One variant then read a file which another one
  had removed, and exited with 1.
- The name now comes from argv[0], so every variant has a file of its own. Two copies of
  the old example fail 4 times in 100 parallel runs, the new one never.
- The standard allows argc to be 0, so the name falls back to a literal in that case.
- The write side opens the file in binary mode like the read side, which matters on Windows.
- The example exits with 1 when the write or the read fails, or when a value does not come
  back. Before, it read an uninitialized value after a short read, and a write to a full
  disk still exited with 0.
- b2 builds test/pch.hpp once per variant and force-includes it into every test.
- A private feature adds the pch as a source to every target but the pch itself.
- A test which defines a library macro before the include opts out with <pch>off.
- github_issue_1384 opts out as well, because it declares a namespace boost before the
  include, and that order is what the test is about.
- The compile tests of the separate headers opt out as well.
- Three tests which take a detail header on its own opt out too, so that a missing include
  of that header still shows.
- The opt-out is on a second line, so the CMake test list stays the same.
- The pch defines _SILENCE_CXX23_DENORM_DEPRECATION_WARNING, because the MSVC standard
  library reads it when the pch parses <limits>. The Boost.Math tests define it only later.
- GCC pch is off on MinGW, as in Boost.Math.
- test_asinh opts out on clang 6 to 8, which fail its constexpr at C++14 with the pch.
- github_issue_1329 and test_cbrt_from_math opt out: 32-bit GCC 12 loses the -Wstringop-overflow
  pragma of libstdc++ with the pch and then rejects the cpp_dec_float output of Boost.Multiprecision.
- MSVC on an ARM64 host builds without the pch, because it fails to map the pch there now and then.
- Clang 22 needs 4562 s of CPU for the test directory without the pch and 1136 s with it.
- GCC 16 needs 2227 s without and 1442 s with it. Both numbers include the test runs.
- In CI the 32-bit gcc-14 job went from 171 min to 68 min, MSVC x64 from 118 min to 37 min,
  and clang-win x64 from 248 min to 51 min.

Fixes boostorg#1461
- Only the Ubuntu 16 and 18 containers could not run the Node 20 of actions/checkout, and
  the matrix has none of them any more.
- The mount of /node20217 and the download into it are therefore dead, so both go.
- ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION goes too, because no action of ci.yml needs an
  old Node any more.
@mborland
mborland merged commit a7f0eeb into boostorg:develop Sep 23, 2026
72 of 73 checks passed
@codecov

codecov Bot commented Sep 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.6%. Comparing base (380e799) to head (fb7d32c).
⚠️ Report is 8 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##           develop   #1464     +/-   ##
=========================================
+ Coverage     98.6%   98.6%   +0.1%     
=========================================
  Files          305     306      +1     
  Lines        25570   25607     +37     
  Branches      2199    2202      +3     
=========================================
+ Hits         25203   25246     +43     
+ Misses         367     361      -6     
Files with missing lines Coverage Δ
include/boost/decimal/bid_conversion.hpp 100.0% <100.0%> (ø)
include/boost/decimal/decimal128_t.hpp 96.2% <100.0%> (+0.4%) ⬆️
include/boost/decimal/decimal32_t.hpp 96.5% <100.0%> (+0.1%) ⬆️
include/boost/decimal/decimal64_t.hpp 97.1% <100.0%> (+0.2%) ⬆️
include/boost/decimal/decimal_fast128_t.hpp 95.8% <100.0%> (+0.1%) ⬆️
include/boost/decimal/decimal_fast32_t.hpp 98.2% <100.0%> (+0.1%) ⬆️
include/boost/decimal/decimal_fast64_t.hpp 98.3% <100.0%> (+0.1%) ⬆️
.../decimal/detail/fast_float/compute_float80_128.hpp 95.7% <100.0%> (ø)
include/boost/decimal/detail/fenv_rounding.hpp 97.4% <100.0%> (ø)
include/boost/decimal/detail/power_tables.hpp 100.0% <100.0%> (ø)
... and 3 more

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 380e799...fb7d32c. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ibmibmibm
ibmibmibm deleted the worktree-test-pch branch September 24, 2026 01:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI is timing out

2 participants