Skip to content

Commit cd30dd1

Browse files
committed
Workaround raw string literal bug in VS2017
1 parent 8e8c0c1 commit cd30dd1

File tree

3 files changed

+51
-9
lines changed

3 files changed

+51
-9
lines changed

docs/configuration.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ TEST_CASE ("Error in streamable check") {
107107
CATCH_CONFIG_FAST_COMPILE // Sacrifices some (rather minor) features for compilation speed
108108
CATCH_CONFIG_POSIX_SIGNALS // Enable handling POSIX signals
109109
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
110+
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
110111
111112
Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
112113
@@ -123,6 +124,9 @@ Defining this flag speeds up compilation of test files by ~20%, by making 2 chan
123124
124125
`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined, in all translation units that are linked into single test binary, or the behaviour of setting `-b` flag and throwing unexpected exceptions will be unpredictable.
125126
127+
## `CATCH_CONFIG_DISABLE_STRINGIFICATION`
128+
This toggle enables a workaround for VS 2017 bug. For details see [known limitations](limitations.md#Visual Studio 2017 -- raw string literal in assert fails to compile)
129+
126130
# Windows header clutter
127131
128132
On Windows Catch includes `windows.h`. To minimize global namespace clutter in the implementation file, it defines `NOMINMAX` and `WIN32_LEAN_AND_MEAN` before including it. You can control this behaviour via two macros:

docs/limitations.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,38 @@ Both of these solutions have their problems, but should let you wring parallelis
5050
## 3rd party bugs
5151
This section outlines known bugs in 3rd party components (this means compilers, standard libraries, standard runtimes).
5252

53+
### Visual Studio 2017 -- raw string literal in assert fails to compile
54+
There is a known bug in Visual Studio 2017 (VC 15), that causes compilation error when preprocessor attempts to stringize a raw string literal (`#` preprocessor is applied to it). This snippet is sufficient to trigger the compilation error:
55+
```cpp
56+
#define CATCH_CONFIG_MAIN
57+
#include "catch.hpp"
58+
59+
TEST_CASE("test") {
60+
CHECK(std::string(R"("\)") == "\"\\");
61+
}
62+
```
63+
64+
Catch provides a workaround, it is possible to disable stringification of original expressions by defining `CATCH_CONFIG_DISABLE_STRINGIFICATION`:
65+
```cpp
66+
#define CATCH_CONFIG_FAST_COMPILE
67+
#define CATCH_CONFIG_DISABLE_STRINGIFICATION
68+
#include "catch.hpp"
69+
70+
TEST_CASE("test") {
71+
CHECK(std::string(R"("\)") == "\"\\");
72+
}
73+
```
74+
75+
_Do note that this changes the output somewhat_
76+
```
77+
catchwork\test1.cpp(6):
78+
PASSED:
79+
CHECK( Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION )
80+
with expansion:
81+
""\" == ""\"
82+
```
83+
84+
5385
### Visual Studio 2013 -- do-while loop withing range based for fails to compile (C2059)
5486
There is a known bug in Visual Studio 2013 (VC 12), that causes compilation error if range based for is followed by an assertion macro, without enclosing the block in braces. This snippet is sufficient to trigger the error
5587
```cpp

include/internal/catch_capture.hpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
#include "catch_compiler_capabilities.h"
1919

2020

21+
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
22+
# define CATCH_INTERNAL_STRINGIFY(expr) #expr
23+
#else
24+
# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
25+
#endif
26+
2127
#if defined(CATCH_CONFIG_FAST_COMPILE)
2228
///////////////////////////////////////////////////////////////////////////////
2329
// We can speedup compilation significantly by breaking into debugger lower in
@@ -33,7 +39,7 @@
3339
// the exception before it propagates back up to the runner.
3440
#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
3541
do { \
36-
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
42+
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
3743
__catchResult.setExceptionGuard(); \
3844
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
3945
( __catchResult <= expr ).endExpression(); \
@@ -45,9 +51,9 @@
4551

4652
#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
4753
do { \
48-
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
54+
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
4955
__catchResult.setExceptionGuard(); \
50-
__catchResult.captureMatch( arg, matcher, #matcher ); \
56+
__catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
5157
__catchResult.unsetExceptionGuard(); \
5258
INTERNAL_CATCH_REACT( __catchResult ) \
5359
} while( Catch::alwaysFalse() )
@@ -67,7 +73,7 @@
6773
///////////////////////////////////////////////////////////////////////////////
6874
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
6975
do { \
70-
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
76+
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
7177
try { \
7278
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
7379
( __catchResult <= expr ).endExpression(); \
@@ -93,7 +99,7 @@
9399
///////////////////////////////////////////////////////////////////////////////
94100
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
95101
do { \
96-
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
102+
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
97103
try { \
98104
static_cast<void>(expr); \
99105
__catchResult.captureResult( Catch::ResultWas::Ok ); \
@@ -107,7 +113,7 @@
107113
///////////////////////////////////////////////////////////////////////////////
108114
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
109115
do { \
110-
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
116+
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \
111117
if( __catchResult.allowThrows() ) \
112118
try { \
113119
static_cast<void>(expr); \
@@ -124,7 +130,7 @@
124130
///////////////////////////////////////////////////////////////////////////////
125131
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
126132
do { \
127-
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
133+
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
128134
if( __catchResult.allowThrows() ) \
129135
try { \
130136
static_cast<void>(expr); \
@@ -168,9 +174,9 @@
168174
///////////////////////////////////////////////////////////////////////////////
169175
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
170176
do { \
171-
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
177+
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
172178
try { \
173-
__catchResult.captureMatch( arg, matcher, #matcher ); \
179+
__catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
174180
} catch( ... ) { \
175181
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
176182
} \

0 commit comments

Comments
 (0)