This was originally motivated by `REQUIRE((a <=> b) == 0)` no
longer compiling using MSVC. After some investigation, I found
that they changed their implementation of the zero literal
detector from the previous pointer-constructor with deleted
other constructors, into one that uses `consteval` constructor
from int.
This breaks the previous detection logic, because now
`is_foo_comparable<std::strong_ordering, int>` is true, but
actually trying to compare them is a compile-time error...
The solution was to make the decomposition `constexpr` and rely
on a late C++20 DR that makes it so that `consteval` propagates
up through the callstack of `constexpr` functions, until it either
runs out of `constexpr` functions, or succeeds.
However, the default handling of types in decomposition is to
take a reference to them. This reference never becomes dangling,
but because the constexpr evaluation engine cannot prove this,
decomposition paths taking references to objects cannot be
actually evaluated at compilation time. Thankfully we already
did have a value-oriented decomposition path for arithmetic types
(as these are common linkage-less types), so we could just
explicitly spell out the `std::foo_ordering` types as also being
supposed to be decomposed by-value.
Two more fun facts about these changes
1) The original motivation of the MSVC change was to avoid
trigering a `Wzero-as-null-pointer-constant` warning. I still
do not believe this was a good decision.
2) Current latest version of MSVC does not actually implement the
aforementioned C++20 DR, so even with this commit, MSVC cannot
compile `REQUIRE((a <=> b) == 0)`.
This triggers when running clang-tidy's bugprone-* family of checks
in code which uses Catch2 even if Catch2 headers are marked as
SYSTEM headers due to how code expanded from macros is treated as
first party even if the macro comes from a 3rd party library. The
fix is luckily pretty straightforward.
This check is added in clang-tidy-18 due for release later this year.
Classes will automatically inherit the virtual-ness of their base
class destructors. If the base class already has a virtual
destructor and the derived class needs default destructor semantics
then the derived class can omit defining the destructor in favor of
the compiler automatically defining it.
This has an additional benefit of reenabling move semantics. The
presence of a user-specified destructor automatically disables move
operations.
This is the recommended way of adding new Opts in our documentation
for using custom main, but we did not compile the code to see if it
works. We now compile the example as part of the BUILD_EXAMPLES
option.
Fixes#2787
This removes about 200 pointless copies from printing the help
message (the original motivation for the change), and also nicely
improves performance of the various reporters that depend on
TextFlow.
The code is now even worse mess than before, due to the ad-hoc
implementation of Result-ish type based on virtual functions in
Clara, but it has dropped the allocations for empty binary down
to 151.
Because TokenStream is copied around a lot, moving it to use
`StringRef` removes _a lot_ of allocations per `Opt` in the parser.
Args are not copied around much, but changing them as well makes it
obvious that they do not participate in the ownership.
The changes add up to removing ~180 allocations for "empty"
invocation of the test binary.
(`./tests/ExtraTests/NoTests --allow-running-no-tests -o /dev/null`
is down to 317 allocs)
This prevents the full construction from being O(N^2) in number
of `Opt`s, and also reduces the number of allocations for running
no tests significantly:
`tests/SelfTest`: 7705 -> 6095
`tests/ExtraTests/NoTests` 2215 -> 605
* Clara::Opt::getHelpColumns returns single item
It could never return multiple items, but for some reason it
was wrapping that single item in a vector.
* Use ReusableStringStream in Clara
* Reserve HelpColumns ahead of time
* Use StringRef for descriptions in HelpColumn type
The combination of these changes ends up removing about 7% (~200)
of allocations when Catch2 has to prepare output for `-h`.
There is no good reason for these to be std::strings, as these
are just (optional) constants for nice user output. This ends up
reducing the allocations significantly.
When measuring allocations when running no tests, the changes are
`tests/SelfTest` 9213 -> 7705
`tests/ExtraTests/NoTests` 3723 -> 2215
By moving to use our `uniform_integer_distribution`, which is
reproducible across different platforms, instead of the stdlib
one which is not, we can provide reproducible results for `float`s
and `double`s. Still no reproducibility for `long double`s, because
those are too different across different platforms.
* Utility for extended mult n x n bits -> 2n bits
* Utility to adapt output from URBG to target (unsigned) integral
type
* Utility to reorder signed values into unsigned type while keeping
the order.
Specifically we add
* `gamma(a, b)`, which returns the magnitude of largest 1-ULP
step in range [a, b].
* `count_equidistant_float(a, b, distance)`, which returns the
number of equi-distant floats in range [a, b].
Together with liberal use of `_sr` UDL to compile-time convert
string literals into StringRefs, this will reduce the number of
allocation and remove most of the strcpy calls inherent in
converting string lits into `std::string`s.
Because the issue comes from the expansions of `UNSCOPED_INFO`,
surrogate TUs could not catch this bug, and in common usage, the
include transitively comes from `catch_test_macros.hpp`.
Fixes#2758
Technically, the declaration should not have a space between
the quotes and the underscore, because `_foo` is a reserved
identifier, but `""_foo` is not. In general it works, but newer
Clang versions warn about this, because WG21 wants to deprecate
and later remove this form completely.