Skip to content

Commit 1eb0ce4

Browse files
author
Clément Metz
committed
Removed captured variable test, that MSVC doesn't like in C++17, but supports in C++20 only. Also enabled runtime execution of the constexpr section
1 parent 579fc31 commit 1eb0ce4

File tree

3 files changed

+62
-19
lines changed

3 files changed

+62
-19
lines changed

docs/compile-time-testing.md

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,38 @@
11
<a id="top"></a>
22

3-
# Compile time testing
3+
# Compile-time testing
44

55
Catch2 provides a way to test code during compilation. This is
66
useful for ensuring the code does not lead to undefined behavior.
77

88
> [!IMPORTANT]
99
> This feature is only available with **C++17**
1010
11+
## Why should I test code at compile-time ?
12+
13+
Testing code during compilation is the only way for ensuring the code does
14+
not lead to [undefined behavior](https://en.cppreference.com/w/cpp/language/ub.html).
15+
This is critical to make your program safe, prevent unexpected crashes and worse
16+
consequences of undefined behavior.
17+
18+
## How ?
19+
20+
Catch2 made it easy to test code at compile-time.
21+
1122
The usage is pretty similar to testing at runtime:
1223

1324
| Runtime macro | Compile time macro |
1425
|-----------------|---------------------------|
1526
| `SECTION` | `CONSTEXPR_SECTION` |
1627
| `REQUIRE` | `CONSTEXPR_REQUIRE` |
1728
| `REQUIRE_FALSE` | `CONSTEXPR_REQUIRE_FALSE` |
29+
| `CHECK` | - |
30+
| `CHECK_FALSE` | - |
1831

1932
```c++
2033
TEST_CASE("My compile time test")
2134
{
22-
CONSTEXPR_SECTION("Use it the same way as SECTION !")
35+
CONSTEXPR_SECTION("std::array subscript and size")
2336
{
2437
std::array v = {1, 2, 3, 4, 5};
2538
CONSTEXPR_REQUIRE( v.size() == 5 );
@@ -31,27 +44,61 @@ TEST_CASE("My compile time test")
3144
3245
All code inside the `CONSTEXPR_SECTION` will be evaluated during compilation.
3346
If any of the `CONSTEXPR_REQUIRE` or `CONSTEXPR_REQUIRE_FALSE` fails,
34-
it will cause a compilation error.
47+
it will cause a **compilation error**.
48+
49+
> [!WARNING]
50+
> You cannot use `REQUIRE` or `CHECK` inside a `CONSTEXPR_SECTION`.
51+
> Be careful not to mistake `CONSTEXPR_REQUIRE` with `STATIC_REQUIRE`.
52+
> They both concern compilation-time testing, but they do not have the same
53+
> purpose.
54+
55+
> [!WARNING]
56+
> You cannot nest `CONSTEXPR_SECTION`s or put a `SECTION` inside a
57+
> `CONSTEXPR_SECTION`
3558
3659
> [!NOTE]
37-
> The code inside the `CONSTEXPR_SECTION` is never evaluated at runtime.
60+
> The code inside the `CONSTEXPR_SECTION` is also evaluated at
61+
> runtime. This way, it remains debuggable, and it contributes to the code
62+
> coverage analysis.
63+
64+
## What can I test ?
65+
66+
You can test anything that can be evaluated in a `constexpr` function.
67+
This will depend on your compiler and the C++ standard you are using.
68+
C++20, C++23 and C++26 improved a lot the support for `constexpr`.
69+
70+
Take a look at the C++ compiler support on [cppreference](https://en.cppreference.com/w/cpp/compiler_support.html)
71+
to see what you can use.
3872
39-
## Debuging compile time tests
73+
## Debug failing compile-time tests
4074
41-
### Investigate
75+
### Investigate from the compiler output
4276
4377
You can check the output of your compiler to find the failing assertion.
44-
The failing line should be highlighted somewhere.
78+
The failing line should be highlighted somewhere. If you cannot see any
79+
line:
80+
81+
- Ensure the `CONSTEXPR_SECTION` runs only code that can be evaluated
82+
at compile-time. This will depend on your compiler and the C++ standard you
83+
are using.
84+
- Ensure you did not use unsupported Catch2 macros inside the `CONSTEXPR_SECTION`.
85+
The only supported macros are `CONSTEXPR_REQUIRE` and `CONSTEXPR_REQUIRE_FALSE`.
86+
- Ensure the code you wrote doesn't produce undefined behavior (UB cannot
87+
compile). Reading a range outside its bounds, dereferencing an invalid pointer,
88+
reading a variable after it has been destroyed, are widespread undefined
89+
behaviors. They will be all caught by these tests.
4590
4691
### Investigate at runtime
4792
48-
If you want to debug the code in a `CONSTEXPR_SECTION`, you can simply replace
49-
the `CONSTEXPR_SECTION` with a `SECTION` and the code will be evaluated at runtime
50-
instead.
93+
> [!TIP]
94+
> If you want to debug the code in a `CONSTEXPR_SECTION`, you can simply replace
95+
> the `CONSTEXPR_SECTION` with a `SECTION` and the code will be evaluated at runtime
96+
> only instead. Remember to come back to the `CONSTEXPR_SECTION` once you are
97+
> done !
5198
5299
## Compile time test report
53100
54-
At runtime, a `CONSTEXPR_SECTION` will add a section in the test report. These sections run nothing, but they
101+
At runtime, a `CONSTEXPR_SECTION` will add a section in the test report. These sections
55102
provide a way to see what was tested during compilation in the test report.
56103
57104
For instance, given the following test case:

src/catch2/internal/catch_constexpr_section.hpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#ifndef CATCH_CONSTEXPR_SECTION_HPP_INCLUDED
99
#define CATCH_CONSTEXPR_SECTION_HPP_INCLUDED
1010

11-
#if defined(CATCH_CPP17_OR_GREATER) && __cpp_constexpr >= 201603
12-
#define CATCH_CONFIG_CONSTEXPR_SECTIONS
11+
#if defined( CATCH_CPP17_OR_GREATER ) && __cpp_constexpr >= 201603
12+
# define CATCH_CONFIG_CONSTEXPR_SECTIONS
1313
#endif
1414

1515
#include <catch2/internal/catch_compiler_capabilities.hpp>
@@ -31,9 +31,7 @@ namespace Catch {
3131
}(),
3232
"compile time section error" );
3333
addFakeAssertion( "unknown-file", 0 );
34-
#ifdef CATCH_CONFIG_RUNTIME_CONSTEXPR_SECTIONS
3534
callable();
36-
#endif
3735
}
3836

3937
// Add a fake assertion to the section to avoid failures because the
@@ -47,13 +45,13 @@ namespace Catch {
4745
# define INTERNAL_CATCH_CONSTEXPR_SECTION( ... ) \
4846
INTERNAL_CATCH_SECTION( "[Passed during compilation] " __VA_ARGS__ ) \
4947
[[maybe_unused]] const ::Catch::ConstexprSection \
50-
INTERNAL_CATCH_UNIQUE_NAME( \
48+
INTERNAL_CATCH_UNIQUE_NAME( \
5149
catch_internal_CompileTimeSection ) = [&]()
5250

5351
#else
5452
# define INTERNAL_CATCH_CONSTEXPR_SECTION( ... ) \
5553
static_assert( false, "C++17 is required for CONSTEXPR_SECTION" ); \
56-
if ( false ) { \
54+
if ( false ) { \
5755
} else
5856
#endif
5957

tests/SelfTest/UsageTests/CompileTimeTests.tests.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@
1212
#ifdef CATCH_CONFIG_CONSTEXPR_SECTIONS
1313

1414
TEST_CASE( "Simple compile time section" ) {
15-
constexpr int captured = 38;
1615
CONSTEXPR_SECTION( "Simple compile time section" ) {
1716
int x = 5;
1817
x *= 10;
1918
CONSTEXPR_REQUIRE( x == 50 );
20-
CONSTEXPR_REQUIRE( captured == 38 );
2119
CONSTEXPR_REQUIRE_FALSE( x != 50 );
2220
};
2321
}

0 commit comments

Comments
 (0)