diff --git a/packages/Catch2/.gitrepo b/packages/Catch2/.gitrepo
index 0accbeb85c8bd6751e1860c856f04f29d9f53db7..f0489ed62b2408124ccd6dc479c66fa99de2417b 100644
--- a/packages/Catch2/.gitrepo
+++ b/packages/Catch2/.gitrepo
@@ -6,6 +6,6 @@
 [subrepo]
 	remote = git@github.com:catchorg/Catch2.git
 	branch = master
-	commit = 8d5d49299be5b8c62ec90be7d6ee4f71cbe89ea0
-	parent = 6d44c5b577be5d55320b4a7f4e2668dec2293f5c
+	commit = 1dce91d78eb6764a474badee7559650502f1d2fc
+	parent = 5515dc5466f2c351639c28fdc16cce10cb067e12
 	cmdver = 0.3.1
diff --git a/packages/Catch2/CMakeLists.txt b/packages/Catch2/CMakeLists.txt
index c877a3ca8305c7d547b2ac952afa999458dc82e8..9fdb50866c35cbb2a5f83ae8f878d298dceb03b3 100644
--- a/packages/Catch2/CMakeLists.txt
+++ b/packages/Catch2/CMakeLists.txt
@@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME)
   set(NOT_SUBPROJECT ON)
 endif()
 
-project(Catch2 LANGUAGES CXX VERSION 2.2.2)
+project(Catch2 LANGUAGES CXX VERSION 2.2.3)
 
 include(GNUInstallDirs)
 
@@ -187,6 +187,7 @@ set(INTERNAL_HEADERS
         ${HEADER_DIR}/internal/catch_test_spec_parser.h
         ${HEADER_DIR}/internal/catch_text.h
         ${HEADER_DIR}/internal/catch_timer.h
+        ${HEADER_DIR}/internal/catch_to_string.hpp
         ${HEADER_DIR}/internal/catch_tostring.h
         ${HEADER_DIR}/internal/catch_totals.h
         ${HEADER_DIR}/internal/catch_uncaught_exceptions.h
diff --git a/packages/Catch2/README.md b/packages/Catch2/README.md
index 5d7f4ff8dc51687aee5126ef903fc1b1fd2b98e7..7defcd5567594ea24f21c65812ac3268ee2b44f6 100644
--- a/packages/Catch2/README.md
+++ b/packages/Catch2/README.md
@@ -5,9 +5,9 @@
 [![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
 [![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
 [![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
-[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/fRDMfYjUnrbOFwLn)
+[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/u7qF77qgv9YqOr55)
 
-<a href="https://github.com/catchorg/Catch2/releases/download/v2.2.2/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
+<a href="https://github.com/catchorg/Catch2/releases/download/v2.2.3/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
 
 ## Catch2 is released!
 
diff --git a/packages/Catch2/codecov.yml b/packages/Catch2/codecov.yml
index d81582d7ec44d0814d79ecdf777abf7e8605a625..94d88d8331eec87994d49c0802a08a794617c8f8 100644
--- a/packages/Catch2/codecov.yml
+++ b/packages/Catch2/codecov.yml
@@ -9,6 +9,12 @@ coverage:
     patch:
       default:
         target: 80%
+  ignore:
+    - "projects/SelfTest"
+    - "**/catch_reporter_tap.hpp"
+    - "**/catch_reporter_automake.hpp"
+    - "**/catch_reporter_teamcity.hpp"
+    - "**/external/clara.hpp"
 
 
 codecov:
@@ -16,11 +22,3 @@ codecov:
 
 comment:
   layout: "diff"
-
-coverage:
-  ignore:
-    - "projects/SelfTest"
-    - "**/catch_reporter_tap.hpp"
-    - "**/catch_reporter_automake.hpp"
-    - "**/catch_reporter_teamcity.hpp"
-    - "**/external/clara.hpp"
diff --git a/packages/Catch2/conanfile.py b/packages/Catch2/conanfile.py
index a3949588548875d8e3c6a813d1f48876c9f91976..716ca420ecb8f088ba82b509888bc6ef78f0a819 100644
--- a/packages/Catch2/conanfile.py
+++ b/packages/Catch2/conanfile.py
@@ -4,7 +4,7 @@ from conans import ConanFile
 
 class CatchConan(ConanFile):
     name = "Catch"
-    version = "2.2.2"
+    version = "2.2.3"
     description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
     author = "philsquared"
     generators = "cmake"
diff --git a/packages/Catch2/contrib/CatchAddTests.cmake b/packages/Catch2/contrib/CatchAddTests.cmake
index c68921e4f83b0c7eb5038cf6744a437c7060d880..07856130663918ddf6c6bfa9154c87f20046c6a1 100644
--- a/packages/Catch2/contrib/CatchAddTests.cmake
+++ b/packages/Catch2/contrib/CatchAddTests.cmake
@@ -50,8 +50,7 @@ string(REPLACE "\n" ";" output "${output}")
 
 # Parse output
 foreach(line ${output})
-  # Test name; strip spaces to get just the name...
-  string(REGEX REPLACE " +" "" test "${line}")
+  set(test ${line})
   # ...and add to script
   add_command(add_test
     "${prefix}${test}${suffix}"
diff --git a/packages/Catch2/contrib/gdbinit b/packages/Catch2/contrib/gdbinit
new file mode 100644
index 0000000000000000000000000000000000000000..fb3608aebafc2e07cea24510cf00eb8c8fb611f2
--- /dev/null
+++ b/packages/Catch2/contrib/gdbinit
@@ -0,0 +1,16 @@
+#
+# This file provides a way to skip stepping into Catch code when debugging with gdb.
+#
+# With the gdb "skip" command you can tell gdb to skip files or functions during debugging.
+# see https://xaizek.github.io/2016-05-26/skipping-standard-library-in-gdb/ for an example
+#
+# Basically the following line tells gdb to skip all functions containing the
+# regexp "Catch", which matches the complete Catch namespace.
+# If you want to skip just some parts of the Catch code you can modify the
+# regexp accordingly.
+# 
+# If you want to permanently skip stepping into Catch code copy the following
+# line into your ~/.gdbinit file
+# 
+
+skip -rfu Catch
diff --git a/packages/Catch2/contrib/lldbinit b/packages/Catch2/contrib/lldbinit
new file mode 100644
index 0000000000000000000000000000000000000000..4f13634d0b483e69df9fcd6a35ba166aca971c80
--- /dev/null
+++ b/packages/Catch2/contrib/lldbinit
@@ -0,0 +1,16 @@
+#
+# This file provides a way to skip stepping into Catch code when debugging with lldb.
+#
+# With the setting "target.process.thread.step-avoid-regexp" you can tell lldb
+# to skip functions matching the regexp
+#
+# Basically the following line tells lldb to skip all functions containing the
+# regexp "Catch", which matches the complete Catch namespace.
+# If you want to skip just some parts of the Catch code you can modify the
+# regexp accordingly.
+#
+# If you want to permanently skip stepping into Catch code copy the following
+# line into your ~/.lldbinit file
+#
+
+settings set target.process.thread.step-avoid-regexp Catch
\ No newline at end of file
diff --git a/packages/Catch2/docs/assertions.md b/packages/Catch2/docs/assertions.md
index 187b7ea8cc1d50ea17b246eafc553f0920e7d4aa..90c0856cb3ea63aad9af63f4909b29de23af0070 100644
--- a/packages/Catch2/docs/assertions.md
+++ b/packages/Catch2/docs/assertions.md
@@ -162,7 +162,7 @@ Because the preprocessor parses code using different rules than the
 compiler, multiple-argument assertions (e.g. `REQUIRE_THROWS_AS`) have
 problems with commas inside the provided expressions. As an example
 `REQUIRE_THROWS_AS(std::pair<int, int>(1, 2), std::invalid_argument);`
-will fails to compile, because the preprocessor sees 3 arguments provided,
+will fail to compile, because the preprocessor sees 3 arguments provided,
 but the macro accepts only 2. There are two possible workarounds.
 
 1) Use typedef:
diff --git a/packages/Catch2/docs/configuration.md b/packages/Catch2/docs/configuration.md
index 00d012df82878dda891e68bf37ae2ecb7e71c739..81bf292aa7b998075c7ccef9178155c0244cb6f2 100644
--- a/packages/Catch2/docs/configuration.md
+++ b/packages/Catch2/docs/configuration.md
@@ -77,13 +77,16 @@ This can be useful on certain platforms that do not provide the standard iostrea
 
 ## Fallback stringifier
 
-By default Catch's stringification machinery falls back to a "{?}". To
-let projects reuse their own existing stringification machinery, this
-fallback can be overridden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER`
-to a name of a function that should perform the stringification instead.
+By default, when Catch's stringification machinery has to stringify
+a type that does not specialize `StringMaker`, does not overload `operator<<`,
+is not an enumeration and is not a range, it uses `"{?}"`. This can be
+overriden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER` to name of a
+function that should perform the stringification instead.
 
-The provided function must return std::string and must accept any type
-(e.g. via overloading).
+All types that do not provide `StringMaker` specialization or `operator<<`
+overload will be sent to this function (this includes enums and ranges).
+The provided function must return `std::string` and must accept any type,
+e.g. via overloading.
 
 _Note that if the provided function does not handle a type and this type
 requires to be stringified, the compilation will fail._
@@ -99,6 +102,19 @@ This means that defining `CATCH_CONFIG_DEFAULT_REPORTER` to `"console"`
 is equivalent with the out-of-the-box experience.
 
 
+## C++11 toggles
+
+    CATCH_CONFIG_CPP11_TO_STRING // Use `std::to_string`
+
+Because we support platforms whose standard library does not contain
+`std::to_string`, it is possible to force Catch to use a workaround
+based on `std::stringstream`. On platforms other than Android,
+the default is to use `std::to_string`. On Android, the default is to
+use the `stringstream` workaround. As always, it is possible to override
+Catch's selection, by defining either `CATCH_CONFIG_CPP11_TO_STRING` or
+`CATCH_CONFIG_NO_CPP11_TO_STRING`.
+
+
 ## C++17 toggles
 
     CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS  // Use std::uncaught_exceptions instead of std::uncaught_exception
diff --git a/packages/Catch2/docs/list-of-examples.md b/packages/Catch2/docs/list-of-examples.md
index 6517d5d367bfa5e5c2b00cd7d034832fc3aa951e..81f5a903f067dbc5a18e24bcef39ff7d43a02388 100644
--- a/packages/Catch2/docs/list-of-examples.md
+++ b/packages/Catch2/docs/list-of-examples.md
@@ -1,18 +1,25 @@
 <a id="top"></a>
 # List of examples
 
+## Already available
+
 - Test Case: [Single-file](../examples/010-TestCase.cpp)
 - Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-1.cpp)
 - Assertion: [REQUIRE, CHECK](../examples/030-Asn-Require-Check.cpp)
+- Fixture: [Sections](../examples/100-Fix-Section.cpp)
+- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
+- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
+- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
+
+
+## Planned
+
 - Assertion: [REQUIRE_THAT and Matchers](../examples/040-Asn-RequireThat.cpp)
 - Assertion: [REQUIRE_NO_THROW](../examples/050-Asn-RequireNoThrow.cpp)
 - Assertion: [REQUIRE_THROWS](../examples/050-Asn-RequireThrows.cpp)
 - Assertion: [REQUIRE_THROWS_AS](../examples/070-Asn-RequireThrowsAs.cpp)
 - Assertion: [REQUIRE_THROWS_WITH](../examples/080-Asn-RequireThrowsWith.cpp)
 - Assertion: [REQUIRE_THROWS_MATCHES](../examples/090-Asn-RequireThrowsMatches.cpp)
-- Fixture: [Sections](../examples/100-Fix-Section.cpp)
-- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
-- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
 - Floating point: [Approx - Comparisons](../examples/130-Fpt-Approx.cpp)
 - Logging: [CAPTURE - Capture expression](../examples/140-Log-Capture.cpp)
 - Logging: [INFO - Provide information with failure](../examples/150-Log-Info.cpp)
@@ -21,7 +28,6 @@
 - Logging: [SUCCEED - Issue message and continue](../examples/180-Log-Succeed.cpp)
 - Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
 - Report: [Reporter](../examples/200-Rpt-UserDefinedReporter.cpp)
-- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
 - Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
 - Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
 - Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)
diff --git a/packages/Catch2/docs/release-notes.md b/packages/Catch2/docs/release-notes.md
index 37849affcab30ccf1b6e5a478ed02200eb8dbe24..6ebe4d03d0d85138a720383676b6373c9fc6c22c 100644
--- a/packages/Catch2/docs/release-notes.md
+++ b/packages/Catch2/docs/release-notes.md
@@ -1,5 +1,43 @@
 <a id="top"></a>
 
+# 2.2.3
+
+**To fix some of the bugs, some behavior had to change in potentially breaking manner.**
+**This means that even though this is a patch release, it might not be a drop-in replacement.**
+
+## Fixes
+* Listeners are now called before reporter
+  * This was always documented to be the case, now it actually works that way
+* Catch's commandline will no longer accept multiple reporters
+  * This was done because multiple reporters never worked properly and broke things in non-obvious ways
+  * **This has potential to be a breaking change**
+* MinGW is now detected as Windows platform w/o SEH support (#1257)
+  * This means that Catch2 no longer tries to use POSIX signal handling when compiled with MinGW
+* Fixed potential UB in parsing tags using non-ASCII characters (#1266)
+  * Note that Catch2 still supports only ASCII test names/tags/etc
+* `TEST_CASE_METHOD` can now be used on classnames containing commas (#1245)
+  * You have to enclose the classname in extra set of parentheses
+* Fixed insufficient alt stack size for POSIX signal handling (#1225)
+* Fixed compilation error on Android due to missing `std::to_string` in C++11 mode (#1280)
+* Fixed the order of user-provided `FALLBACK_STRINGIFIER` in stringification machinery (#1024)
+  * It was intended to be replacement for built-in fallbacks, but it was used _after_ them.
+  * **This has potential to be a breaking change**
+* Fixed compilation error when a type has an `operator<<` with templated lhs (#1285, #1306)
+
+## Improvements
+* Added a new, experimental, output capture (#1243)
+  * This capture can also redirect output written via C apis, e.g. `printf`
+  * To opt-in, define `CATCH_CONFIG_EXPERIMENTAL_REDIRECT` in the implementation file
+* Added a new fallback stringifier for classes derived from `std::exception`
+  * Both `StringMaker` specialization and `operator<<` overload are given priority
+
+## Miscellaneous
+* `contrib/` now contains dbg scripts that skip over Catch's internals (#904, #1283)
+  * `gdbinit` for gdb `lldbinit` for lldb
+* `CatchAddTests.cmake` no longer strips whitespace from tests (#1265, #1281)
+* Online documentation now describes `--use-colour` option (#1263)
+
+
 # 2.2.2
 
 ## Fixes
diff --git a/packages/Catch2/docs/release-process.md b/packages/Catch2/docs/release-process.md
index 9990bab2b6da281059ebed13ce368bca76a8f704..b556c3990cd980cbbf61ac20c2dd8648cc21e696 100644
--- a/packages/Catch2/docs/release-process.md
+++ b/packages/Catch2/docs/release-process.md
@@ -49,17 +49,5 @@ on a specific version of the single-include header.
 
 ## Optional steps
 
-The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they *should* happen, but they can happen the next day without losing anything significant.
-
-
-### vcpkg update
-
-Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of necessary work for you, it creates a branch and commits necessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
-
-Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so:
-```
-GitHub
-    Catch
-    vcpkg
-```
-
+Because Catch's [vcpkg](https://github.com/Microsoft/vcpkg) port updates
+itself automagically, there are no optional steps at this time.
diff --git a/packages/Catch2/include/catch.hpp b/packages/Catch2/include/catch.hpp
index 10388cece2e1262cb0a9bca47fdbbc72033644a3..0c92ed3af153a90a51f9def57dcfa45c13b38617 100644
--- a/packages/Catch2/include/catch.hpp
+++ b/packages/Catch2/include/catch.hpp
@@ -11,7 +11,7 @@
 
 #define CATCH_VERSION_MAJOR 2
 #define CATCH_VERSION_MINOR 2
-#define CATCH_VERSION_PATCH 2
+#define CATCH_VERSION_PATCH 3
 
 #ifdef __clang__
 #    pragma clang system_header
diff --git a/packages/Catch2/include/internal/catch_assertionhandler.cpp b/packages/Catch2/include/internal/catch_assertionhandler.cpp
index c6818c14d3bc78d4c6346da2dbbcc1c5bfe73e77..28768077ab50eabb4a8d78beba651893a44e0188 100644
--- a/packages/Catch2/include/internal/catch_assertionhandler.cpp
+++ b/packages/Catch2/include/internal/catch_assertionhandler.cpp
@@ -18,9 +18,11 @@
 
 namespace Catch {
 
-    auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
-        expr.streamReconstructedExpression( os );
-        return os;
+    namespace {
+        auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
+            expr.streamReconstructedExpression( os );
+            return os;
+        }
     }
 
     LazyExpression::LazyExpression( bool isNegated )
diff --git a/packages/Catch2/include/internal/catch_compiler_capabilities.h b/packages/Catch2/include/internal/catch_compiler_capabilities.h
index c78c9d6d796650230fae393e50815f3b33c3d50a..37f625b2827c43b040dcd39802e5d1686a56626d 100644
--- a/packages/Catch2/include/internal/catch_compiler_capabilities.h
+++ b/packages/Catch2/include/internal/catch_compiler_capabilities.h
@@ -24,6 +24,7 @@
 // Many features, at point of detection, define an _INTERNAL_ macro, so they
 // can be combined, en-mass, with the _NO_ forms later.
 
+#include "catch_platform.h"
 
 #ifdef __cplusplus
 
@@ -76,7 +77,11 @@
 #       define CATCH_CONFIG_COLOUR_NONE
 #endif
 
-
+////////////////////////////////////////////////////////////////////////////////
+// Android somehow still does not support std::to_string
+#if defined(__ANDROID__)
+#    define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+#endif
 
 ////////////////////////////////////////////////////////////////////////////////
 // Not all Windows environments support SEH properly
@@ -146,6 +151,10 @@
 #   define CATCH_CONFIG_WCHAR
 #endif
 
+#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
+#    define CATCH_CONFIG_CPP11_TO_STRING
+#endif
+
 #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
 #  define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
 #endif
diff --git a/packages/Catch2/include/internal/catch_fatal_condition.cpp b/packages/Catch2/include/internal/catch_fatal_condition.cpp
index ca72d980db15ac0e93bf7a5846b7a7b10652e00a..24e16d3c611e4f7d5dc6a86d56361b8955ad8e24 100644
--- a/packages/Catch2/include/internal/catch_fatal_condition.cpp
+++ b/packages/Catch2/include/internal/catch_fatal_condition.cpp
@@ -94,6 +94,11 @@ namespace Catch {
         int id;
         const char* name;
     };
+    
+    // 32kb for the alternate stack seems to be sufficient. However, this value
+    // is experimentally determined, so that's not guaranteed.
+    constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
+
     static SignalDefs signalDefs[] = {
         { SIGINT,  "SIGINT - Terminal interrupt signal" },
         { SIGILL,  "SIGILL - Illegal instruction signal" },
@@ -121,7 +126,7 @@ namespace Catch {
         isSet = true;
         stack_t sigStack;
         sigStack.ss_sp = altStackMem;
-        sigStack.ss_size = SIGSTKSZ;
+        sigStack.ss_size = sigStackSize;
         sigStack.ss_flags = 0;
         sigaltstack(&sigStack, &oldSigStack);
         struct sigaction sa = { };
@@ -153,7 +158,7 @@ namespace Catch {
     bool FatalConditionHandler::isSet = false;
     struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
     stack_t FatalConditionHandler::oldSigStack = {};
-    char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+    char FatalConditionHandler::altStackMem[sigStackSize] = {};
 
 
 } // namespace Catch
diff --git a/packages/Catch2/include/internal/catch_matchers_floating.cpp b/packages/Catch2/include/internal/catch_matchers_floating.cpp
index b758bcf9e8ecb28a5026f2e53de4148f2cfe495f..72728a83d2d5f7786317d43d1d274b863cdadfbb 100644
--- a/packages/Catch2/include/internal/catch_matchers_floating.cpp
+++ b/packages/Catch2/include/internal/catch_matchers_floating.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "catch_matchers_floating.h"
+#include "catch_to_string.hpp"
 #include "catch_tostring.h"
 
 #include <cstdlib>
@@ -115,7 +116,7 @@ namespace Floating {
     }
 
     std::string WithinUlpsMatcher::describe() const {
-        return "is within " + std::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
+        return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
     }
 
 }// namespace Floating
diff --git a/packages/Catch2/include/internal/catch_objc.hpp b/packages/Catch2/include/internal/catch_objc.hpp
index b43f3352f8d08633508775ca8bed88ff81ca09db..39cbb1fa8965d40dfc98704a569154d3fd5f9418 100644
--- a/packages/Catch2/include/internal/catch_objc.hpp
+++ b/packages/Catch2/include/internal/catch_objc.hpp
@@ -93,7 +93,7 @@ namespace Catch {
                         std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
                         const char* className = class_getName( cls );
 
-                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) );
+                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );
                         noTestMethods++;
                     }
                 }
diff --git a/packages/Catch2/include/internal/catch_output_redirect.cpp b/packages/Catch2/include/internal/catch_output_redirect.cpp
index 07d4a33c816496cfd27b2fd44ab2b5fce948df96..c43dca04870026d742dceeb0a18fef89b1fc4e1d 100644
--- a/packages/Catch2/include/internal/catch_output_redirect.cpp
+++ b/packages/Catch2/include/internal/catch_output_redirect.cpp
@@ -49,7 +49,7 @@ namespace Catch {
 
 
 
-#if defined(CATCH_PLATFORM_WINDOWS)
+#if defined(_MSC_VER)
     TempFile::TempFile() {
         if (tmpnam_s(m_buffer)) {
             throw std::runtime_error("Could not get a temp filename");
@@ -77,7 +77,7 @@ namespace Catch {
          std::fclose(m_file);
          // We manually create the file on Windows only, on Linux
          // it will be autodeleted
-#if defined(CATCH_PLATFORM_WINDOWS)
+#if defined(_MSC_VER)
          std::remove(m_buffer);
 #endif
     }
@@ -125,7 +125,7 @@ namespace Catch {
 
 } // namespace Catch
 
-#if defined(CATCH_PLATFORM_WINDOWS)
+#if defined(_MSC_VER)
 #undef dup
 #undef dup2
 #undef fileno
diff --git a/packages/Catch2/include/internal/catch_string_manip.cpp b/packages/Catch2/include/internal/catch_string_manip.cpp
index 8476204495a84a6107f69d9d022ed854a26924aa..904d10138ffe10ea6cd38ca1f6c1ea1331e6425d 100644
--- a/packages/Catch2/include/internal/catch_string_manip.cpp
+++ b/packages/Catch2/include/internal/catch_string_manip.cpp
@@ -14,6 +14,12 @@
 
 namespace Catch {
 
+    namespace {
+        char toLowerCh(char c) {
+            return static_cast<char>( std::tolower( c ) );
+        }
+    }
+
     bool startsWith( std::string const& s, std::string const& prefix ) {
         return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
     }
@@ -29,9 +35,6 @@ namespace Catch {
     bool contains( std::string const& s, std::string const& infix ) {
         return s.find( infix ) != std::string::npos;
     }
-    char toLowerCh(char c) {
-        return static_cast<char>( std::tolower( c ) );
-    }
     void toLowerInPlace( std::string& s ) {
         std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
     }
diff --git a/packages/Catch2/include/internal/catch_test_case_info.cpp b/packages/Catch2/include/internal/catch_test_case_info.cpp
index 461642212514addf10ebab538e2abf259abf68d3..536462d114b2ac76e2bd3be78c82390aafb225fb 100644
--- a/packages/Catch2/include/internal/catch_test_case_info.cpp
+++ b/packages/Catch2/include/internal/catch_test_case_info.cpp
@@ -19,31 +19,33 @@
 
 namespace Catch {
 
-    TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
-        if( startsWith( tag, '.' ) ||
-            tag == "!hide" )
-            return TestCaseInfo::IsHidden;
-        else if( tag == "!throws" )
-            return TestCaseInfo::Throws;
-        else if( tag == "!shouldfail" )
-            return TestCaseInfo::ShouldFail;
-        else if( tag == "!mayfail" )
-            return TestCaseInfo::MayFail;
-        else if( tag == "!nonportable" )
-            return TestCaseInfo::NonPortable;
-        else if( tag == "!benchmark" )
-            return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
-        else
-            return TestCaseInfo::None;
-    }
-    bool isReservedTag( std::string const& tag ) {
-        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
-    }
-    void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
-        CATCH_ENFORCE( !isReservedTag(tag),
-                      "Tag name: [" << tag << "] is not allowed.\n"
-                      << "Tag names starting with non alpha-numeric characters are reserved\n"
-                      << _lineInfo );
+    namespace {
+        TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+            if( startsWith( tag, '.' ) ||
+                tag == "!hide" )
+                return TestCaseInfo::IsHidden;
+            else if( tag == "!throws" )
+                return TestCaseInfo::Throws;
+            else if( tag == "!shouldfail" )
+                return TestCaseInfo::ShouldFail;
+            else if( tag == "!mayfail" )
+                return TestCaseInfo::MayFail;
+            else if( tag == "!nonportable" )
+                return TestCaseInfo::NonPortable;
+            else if( tag == "!benchmark" )
+                return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
+            else
+                return TestCaseInfo::None;
+        }
+        bool isReservedTag( std::string const& tag ) {
+            return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
+        }
+        void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+            CATCH_ENFORCE( !isReservedTag(tag),
+                          "Tag name: [" << tag << "] is not allowed.\n"
+                          << "Tag names starting with non alpha-numeric characters are reserved\n"
+                          << _lineInfo );
+        }
     }
 
     TestCase makeTestCase(  ITestInvoker* _testCase,
diff --git a/packages/Catch2/include/internal/catch_timer.cpp b/packages/Catch2/include/internal/catch_timer.cpp
index 6786efb04a2cfe1304440f7075a9a945ccd03c00..d52c0085c049bd09244306e09be7fe601a1b113f 100644
--- a/packages/Catch2/include/internal/catch_timer.cpp
+++ b/packages/Catch2/include/internal/catch_timer.cpp
@@ -18,34 +18,36 @@ namespace Catch {
         return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
     }
 
-    auto estimateClockResolution() -> uint64_t {
-        uint64_t sum = 0;
-        static const uint64_t iterations = 1000000;
+    namespace {
+        auto estimateClockResolution() -> uint64_t {
+            uint64_t sum = 0;
+            static const uint64_t iterations = 1000000;
 
-        auto startTime = getCurrentNanosecondsSinceEpoch();
+            auto startTime = getCurrentNanosecondsSinceEpoch();
 
-        for( std::size_t i = 0; i < iterations; ++i ) {
+            for( std::size_t i = 0; i < iterations; ++i ) {
 
-            uint64_t ticks;
-            uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
-            do {
-                ticks = getCurrentNanosecondsSinceEpoch();
-            } while( ticks == baseTicks );
+                uint64_t ticks;
+                uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
+                do {
+                    ticks = getCurrentNanosecondsSinceEpoch();
+                } while( ticks == baseTicks );
 
-            auto delta = ticks - baseTicks;
-            sum += delta;
+                auto delta = ticks - baseTicks;
+                sum += delta;
 
-            // If we have been calibrating for over 3 seconds -- the clock
-            // is terrible and we should move on.
-            // TBD: How to signal that the measured resolution is probably wrong?
-            if (ticks > startTime + 3 * nanosecondsInSecond) {
-                return sum / i;
+                // If we have been calibrating for over 3 seconds -- the clock
+                // is terrible and we should move on.
+                // TBD: How to signal that the measured resolution is probably wrong?
+                if (ticks > startTime + 3 * nanosecondsInSecond) {
+                    return sum / i;
+                }
             }
-        }
 
-        // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
-        // - and potentially do more iterations if there's a high variance.
-        return sum/iterations;
+            // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
+            // - and potentially do more iterations if there's a high variance.
+            return sum/iterations;
+        }
     }
     auto getEstimatedClockResolution() -> uint64_t {
         static auto s_resolution = estimateClockResolution();
diff --git a/packages/Catch2/include/internal/catch_to_string.hpp b/packages/Catch2/include/internal/catch_to_string.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3e2b5879061a7fa53fe3f684b37832df888ec626
--- /dev/null
+++ b/packages/Catch2/include/internal/catch_to_string.hpp
@@ -0,0 +1,28 @@
+/*
+ *  Created by Martin on 9/5/2018.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_CATCH_TO_STRING_H_INCLUDED
+#define TWOBLUECUBES_CATCH_TO_STRING_H_INCLUDED
+
+#include <string>
+
+#include "catch_compiler_capabilities.h"
+#include "catch_stream.h"
+
+namespace Catch {
+    template <typename T>
+    std::string to_string(T const& t) {
+#if defined(CATCH_CONFIG_CPP11_TO_STRING)
+        return std::to_string(t);
+#else
+        ReusableStringStream rss;
+        rss << t;
+        return rss.str();
+#endif
+    }
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_TO_STRING_H_INCLUDED
diff --git a/packages/Catch2/include/internal/catch_tostring.cpp b/packages/Catch2/include/internal/catch_tostring.cpp
index 0d0158fa677fed45366417bfe819b2079ee85cb5..ee6a815f9aa76196ed3949305fffdbb3fa965000 100644
--- a/packages/Catch2/include/internal/catch_tostring.cpp
+++ b/packages/Catch2/include/internal/catch_tostring.cpp
@@ -236,7 +236,6 @@ std::string  ratio_string<std::nano>::symbol() { return "n"; }
 std::string ratio_string<std::micro>::symbol() { return "u"; }
 std::string ratio_string<std::milli>::symbol() { return "m"; }
 
-
 } // end namespace Catch
 
 #if defined(__clang__)
diff --git a/packages/Catch2/include/internal/catch_tostring.h b/packages/Catch2/include/internal/catch_tostring.h
index 79e1001f63db64b0b50e4f5e1e6bd86aeeafc855..2aa06f442752e891ec651c8281f648393a3cb580 100644
--- a/packages/Catch2/include/internal/catch_tostring.h
+++ b/packages/Catch2/include/internal/catch_tostring.h
@@ -62,20 +62,26 @@ namespace Catch {
         std::string convertUnknownEnumToString( E e );
 
         template<typename T>
-        typename std::enable_if<!std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) {
-#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
-            (void)value;
+        typename std::enable_if<
+            !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
+        std::string>::type convertUnstreamable( T const& ) {
             return Detail::unprintableString;
-#else
-            return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
-#endif
         }
         template<typename T>
-        typename std::enable_if<std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) {
-            return convertUnknownEnumToString( value );
+        typename std::enable_if<
+            !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
+         std::string>::type convertUnstreamable(T const& ex) {
+            return ex.what();
         }
 
 
+        template<typename T>
+        typename std::enable_if<
+            std::is_enum<T>::value
+        , std::string>::type convertUnstreamable( T const& value ) {
+            return convertUnknownEnumToString( value );
+        }
+
 #if defined(_MANAGED)
         //! Convert a CLR string to a utf8 std::string
         template<typename T>
@@ -99,7 +105,9 @@ namespace Catch {
         typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
             convert(const Fake& value) {
                 ReusableStringStream rss;
-                rss << value;
+                // NB: call using the function-like syntax to avoid ambiguity with
+                // user-defined templated operator<< under clang.
+                rss.operator<<(value);
                 return rss.str();
         }
 
@@ -107,7 +115,11 @@ namespace Catch {
         static
         typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
             convert( const Fake& value ) {
-                return Detail::convertUnstreamable( value );
+#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
+            return Detail::convertUnstreamable(value);
+#else
+            return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
+#endif
         }
     };
 
diff --git a/packages/Catch2/include/internal/catch_version.cpp b/packages/Catch2/include/internal/catch_version.cpp
index 561117cfb3c0fd64bebaa5518fdefa77b1d77cae..94e11e0851ec6ef6a68db8cb03cb6c86bb897017 100644
--- a/packages/Catch2/include/internal/catch_version.cpp
+++ b/packages/Catch2/include/internal/catch_version.cpp
@@ -37,7 +37,7 @@ namespace Catch {
     }
 
     Version const& libraryVersion() {
-        static Version version( 2, 2, 2, "", 0 );
+        static Version version( 2, 2, 3, "", 0 );
         return version;
     }
 
diff --git a/packages/Catch2/projects/SelfTest/Baselines/compact.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/compact.sw.approved.txt
index 6247761c153177d47bb3dfc7071883f62a73f3ac..24d9b1b792a14c184280dd16514ef6868f22f301 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/compact.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/compact.sw.approved.txt
@@ -211,14 +211,21 @@ Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Equals("this
 Matchers.tests.cpp:<line number>: passed: testStringForMatching(), Equals("this string contains 'ABC' as a substring", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" equals: "this string contains 'abc' as a substring" (case insensitive)
 Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Equals("this string contains 'ABC' as a substring") for: "this string contains 'abc' as a substring" equals: "this string contains 'ABC' as a substring"
 Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Equals("something else", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" equals: "something else" (case insensitive)
+ToStringGeneral.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(WhatException{}) == "This exception has overriden what() method" for: "This exception has overriden what() method"
+==
+"This exception has overriden what() method"
+ToStringGeneral.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(OperatorException{}) == "OperatorException" for: "OperatorException" == "OperatorException"
+ToStringGeneral.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(StringMakerException{}) == "StringMakerException" for: "StringMakerException"
+==
+"StringMakerException"
 Matchers.tests.cpp:<line number>: failed: expected exception, got none; expression was: doesNotThrow(), SpecialException, ExceptionMatcher{1}
 Matchers.tests.cpp:<line number>: failed: expected exception, got none; expression was: doesNotThrow(), SpecialException, ExceptionMatcher{1}
 Matchers.tests.cpp:<line number>: failed: unexpected exception with message: 'Unknown exception'; expression was: throwsAsInt(1), SpecialException, ExceptionMatcher{1}
 Matchers.tests.cpp:<line number>: failed: unexpected exception with message: 'Unknown exception'; expression was: throwsAsInt(1), SpecialException, ExceptionMatcher{1}
-Matchers.tests.cpp:<line number>: failed: throws(3), SpecialException, ExceptionMatcher{1} for: {?} special exception has value of 1
-Matchers.tests.cpp:<line number>: failed: throws(4), SpecialException, ExceptionMatcher{1} for: {?} special exception has value of 1
-Matchers.tests.cpp:<line number>: passed: throws(1), SpecialException, ExceptionMatcher{1} for: {?} special exception has value of 1
-Matchers.tests.cpp:<line number>: passed: throws(2), SpecialException, ExceptionMatcher{2} for: {?} special exception has value of 2
+Matchers.tests.cpp:<line number>: failed: throws(3), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
+Matchers.tests.cpp:<line number>: failed: throws(4), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
+Matchers.tests.cpp:<line number>: passed: throws(1), SpecialException, ExceptionMatcher{1} for: SpecialException::what special exception has value of 1
+Matchers.tests.cpp:<line number>: passed: throws(2), SpecialException, ExceptionMatcher{2} for: SpecialException::what special exception has value of 2
 Exception.tests.cpp:<line number>: passed: thisThrows(), "expected exception" for: "expected exception" equals: "expected exception"
 Exception.tests.cpp:<line number>: passed: thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) for: "expected exception" equals: "expected exception" (case insensitive)
 Exception.tests.cpp:<line number>: passed: thisThrows(), StartsWith( "expected" ) for: "expected exception" starts with: "expected"
@@ -1058,6 +1065,9 @@ ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(item)
 ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" for: "operator<<( has_operator )"
 ==
 "operator<<( has_operator )"
+ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" for: "operator<<( has_template_operator )"
+==
+"operator<<( has_template_operator )"
 ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" for: "{ StringMaker<has_maker> }"
 ==
 "{ StringMaker<has_maker> }"
diff --git a/packages/Catch2/projects/SelfTest/Baselines/console.std.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/console.std.approved.txt
index 79e1bf89052738eb64e1e638575ccab931f6f964..1992fb9fc2ca43773f4e551132aec016ef1b0ad3 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/console.std.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/console.std.approved.txt
@@ -335,12 +335,12 @@ Matchers.tests.cpp:<line number>
 Matchers.tests.cpp:<line number>: FAILED:
   CHECK_THROWS_MATCHES( throws(3), SpecialException, ExceptionMatcher{1} )
 with expansion:
-  {?} special exception has value of 1
+  SpecialException::what special exception has value of 1
 
 Matchers.tests.cpp:<line number>: FAILED:
   REQUIRE_THROWS_MATCHES( throws(4), SpecialException, ExceptionMatcher{1} )
 with expansion:
-  {?} special exception has value of 1
+  SpecialException::what special exception has value of 1
 
 -------------------------------------------------------------------------------
 Expected exceptions that don't throw or unexpected exceptions fail the test
@@ -1084,6 +1084,6 @@ due to unexpected exception with message:
   Why would you throw a std::string?
 
 ===============================================================================
-test cases:  206 | 153 passed |  49 failed |  4 failed as expected
-assertions: 1061 | 933 passed | 107 failed | 21 failed as expected
+test cases:  208 | 155 passed |  49 failed |  4 failed as expected
+assertions: 1065 | 937 passed | 107 failed | 21 failed as expected
 
diff --git a/packages/Catch2/projects/SelfTest/Baselines/console.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/console.sw.approved.txt
index 5a62613daf6b81b4892bad61a1e2e79b7c3fb702..047c7163754c18b2da9eebdea8f0b12e95674fdc 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/console.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/console.sw.approved.txt
@@ -1680,6 +1680,34 @@ with expansion:
   "this string contains 'abc' as a substring" equals: "something else" (case
   insensitive)
 
+-------------------------------------------------------------------------------
+Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified
+-------------------------------------------------------------------------------
+ToStringGeneral.tests.cpp:<line number>
+...............................................................................
+
+ToStringGeneral.tests.cpp:<line number>:
+PASSED:
+  REQUIRE( ::Catch::Detail::stringify(WhatException{}) == "This exception has overriden what() method" )
+with expansion:
+  "This exception has overriden what() method"
+  ==
+  "This exception has overriden what() method"
+
+ToStringGeneral.tests.cpp:<line number>:
+PASSED:
+  REQUIRE( ::Catch::Detail::stringify(OperatorException{}) == "OperatorException" )
+with expansion:
+  "OperatorException" == "OperatorException"
+
+ToStringGeneral.tests.cpp:<line number>:
+PASSED:
+  REQUIRE( ::Catch::Detail::stringify(StringMakerException{}) == "StringMakerException" )
+with expansion:
+  "StringMakerException"
+  ==
+  "StringMakerException"
+
 -------------------------------------------------------------------------------
 Exception matchers that fail
   No exception
@@ -1722,12 +1750,12 @@ Matchers.tests.cpp:<line number>
 Matchers.tests.cpp:<line number>: FAILED:
   CHECK_THROWS_MATCHES( throws(3), SpecialException, ExceptionMatcher{1} )
 with expansion:
-  {?} special exception has value of 1
+  SpecialException::what special exception has value of 1
 
 Matchers.tests.cpp:<line number>: FAILED:
   REQUIRE_THROWS_MATCHES( throws(4), SpecialException, ExceptionMatcher{1} )
 with expansion:
-  {?} special exception has value of 1
+  SpecialException::what special exception has value of 1
 
 -------------------------------------------------------------------------------
 Exception matchers that succeed
@@ -1739,13 +1767,13 @@ Matchers.tests.cpp:<line number>:
 PASSED:
   CHECK_THROWS_MATCHES( throws(1), SpecialException, ExceptionMatcher{1} )
 with expansion:
-  {?} special exception has value of 1
+  SpecialException::what special exception has value of 1
 
 Matchers.tests.cpp:<line number>:
 PASSED:
   REQUIRE_THROWS_MATCHES( throws(2), SpecialException, ExceptionMatcher{2} )
 with expansion:
-  {?} special exception has value of 2
+  SpecialException::what special exception has value of 2
 
 -------------------------------------------------------------------------------
 Exception messages can be tested for
@@ -8379,6 +8407,20 @@ with expansion:
   ==
   "operator<<( has_operator )"
 
+-------------------------------------------------------------------------------
+stringify( has_template_operator )
+-------------------------------------------------------------------------------
+ToStringWhich.tests.cpp:<line number>
+...............................................................................
+
+ToStringWhich.tests.cpp:<line number>:
+PASSED:
+  REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" )
+with expansion:
+  "operator<<( has_template_operator )"
+  ==
+  "operator<<( has_template_operator )"
+
 -------------------------------------------------------------------------------
 stringify( vectors<has_maker> )
 -------------------------------------------------------------------------------
@@ -8950,6 +8992,6 @@ Misc.tests.cpp:<line number>:
 PASSED:
 
 ===============================================================================
-test cases:  206 | 140 passed |  62 failed |  4 failed as expected
-assertions: 1075 | 933 passed | 121 failed | 21 failed as expected
+test cases:  208 | 142 passed |  62 failed |  4 failed as expected
+assertions: 1079 | 937 passed | 121 failed | 21 failed as expected
 
diff --git a/packages/Catch2/projects/SelfTest/Baselines/junit.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/junit.sw.approved.txt
index 02579344e87901dd00d8e3d7c1bc967f78fdd35c..62ca9094090e9e63f1578f64beb88a31f4d7173f 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/junit.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/junit.sw.approved.txt
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <testsuitesloose text artifact
 >
-  <testsuite name="<exe-name>" errors="17" failures="105" tests="1076" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
+  <testsuite name="<exe-name>" errors="17" failures="105" tests="1080" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
     <testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
     <testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
     <testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
@@ -218,6 +218,7 @@ Matchers.tests.cpp:<line number>
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
+    <testcase classname="<exe-name>.global" name="Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified" time="{duration}"/>
     <testcase classname="<exe-name>.global" name="Exception matchers that fail/No exception" time="{duration}">
       <failure message="doesNotThrow(), SpecialException, ExceptionMatcher{1}" type="CHECK_THROWS_MATCHES">
 Matchers.tests.cpp:<line number>
@@ -237,10 +238,10 @@ Matchers.tests.cpp:<line number>
       </error>
     </testcase>
     <testcase classname="<exe-name>.global" name="Exception matchers that fail/Contents are wrong" time="{duration}">
-      <failure message="{?} special exception has value of 1" type="CHECK_THROWS_MATCHES">
+      <failure message="SpecialException::what special exception has value of 1" type="CHECK_THROWS_MATCHES">
 Matchers.tests.cpp:<line number>
       </failure>
-      <failure message="{?} special exception has value of 1" type="REQUIRE_THROWS_MATCHES">
+      <failure message="SpecialException::what special exception has value of 1" type="REQUIRE_THROWS_MATCHES">
 Matchers.tests.cpp:<line number>
       </failure>
     </testcase>
@@ -837,6 +838,7 @@ Tricky.tests.cpp:<line number>
     <testcase classname="<exe-name>.global" name="stringify( has_maker_and_operator )" time="{duration}"/>
     <testcase classname="<exe-name>.global" name="stringify( has_neither )" time="{duration}"/>
     <testcase classname="<exe-name>.global" name="stringify( has_operator )" time="{duration}"/>
+    <testcase classname="<exe-name>.global" name="stringify( has_template_operator )" time="{duration}"/>
     <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker> )" time="{duration}"/>
     <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker_and_operator> )" time="{duration}"/>
     <testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_operator> )" time="{duration}"/>
diff --git a/packages/Catch2/projects/SelfTest/Baselines/xml.sw.approved.txt b/packages/Catch2/projects/SelfTest/Baselines/xml.sw.approved.txt
index 001cb0e1d18ac868eb5645194467c1574d1e7d86..5452f2fa36c8a3d3b3fc992f60531413233d6828 100644
--- a/packages/Catch2/projects/SelfTest/Baselines/xml.sw.approved.txt
+++ b/packages/Catch2/projects/SelfTest/Baselines/xml.sw.approved.txt
@@ -1901,6 +1901,37 @@
       </Expression>
       <OverallResult success="false"/>
     </TestCase>
+    <TestCase name="Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified" tags="[exception][toString]" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+        <Original>
+          ::Catch::Detail::stringify(WhatException{}) == "This exception has overriden what() method"
+        </Original>
+        <Expanded>
+          "This exception has overriden what() method"
+==
+"This exception has overriden what() method"
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+        <Original>
+          ::Catch::Detail::stringify(OperatorException{}) == "OperatorException"
+        </Original>
+        <Expanded>
+          "OperatorException" == "OperatorException"
+        </Expanded>
+      </Expression>
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringGeneral.tests.cpp" >
+        <Original>
+          ::Catch::Detail::stringify(StringMakerException{}) == "StringMakerException"
+        </Original>
+        <Expanded>
+          "StringMakerException"
+==
+"StringMakerException"
+        </Expanded>
+      </Expression>
+      <OverallResult success="true"/>
+    </TestCase>
     <TestCase name="Exception matchers that fail" tags="[!throws][.][.failing][exceptions][matchers]" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
       <Section name="No exception" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
         <Expression success="false" type="CHECK_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -1952,7 +1983,7 @@
             throws(3), SpecialException, ExceptionMatcher{1}
           </Original>
           <Expanded>
-            {?} special exception has value of 1
+            SpecialException::what special exception has value of 1
           </Expanded>
         </Expression>
         <Expression success="false" type="REQUIRE_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -1960,7 +1991,7 @@
             throws(4), SpecialException, ExceptionMatcher{1}
           </Original>
           <Expanded>
-            {?} special exception has value of 1
+            SpecialException::what special exception has value of 1
           </Expanded>
         </Expression>
         <OverallResults successes="0" failures="2" expectedFailures="0"/>
@@ -1973,7 +2004,7 @@
           throws(1), SpecialException, ExceptionMatcher{1}
         </Original>
         <Expanded>
-          {?} special exception has value of 1
+          SpecialException::what special exception has value of 1
         </Expanded>
       </Expression>
       <Expression success="true" type="REQUIRE_THROWS_MATCHES" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
@@ -1981,7 +2012,7 @@
           throws(2), SpecialException, ExceptionMatcher{2}
         </Original>
         <Expanded>
-          {?} special exception has value of 2
+          SpecialException::what special exception has value of 2
         </Expanded>
       </Expression>
       <OverallResult success="true"/>
@@ -9335,6 +9366,19 @@ loose text artifact
       </Expression>
       <OverallResult success="true"/>
     </TestCase>
+    <TestCase name="stringify( has_template_operator )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
+      <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
+        <Original>
+          ::Catch::Detail::stringify( item ) == "operator&lt;&lt;( has_template_operator )"
+        </Original>
+        <Expanded>
+          "operator&lt;&lt;( has_template_operator )"
+==
+"operator&lt;&lt;( has_template_operator )"
+        </Expanded>
+      </Expression>
+      <OverallResult success="true"/>
+    </TestCase>
     <TestCase name="stringify( vectors&lt;has_maker> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
       <Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
         <Original>
@@ -9892,7 +9936,7 @@ loose text artifact
       </Section>
       <OverallResult success="true"/>
     </TestCase>
-    <OverallResults successes="933" failures="122" expectedFailures="21"/>
+    <OverallResults successes="937" failures="122" expectedFailures="21"/>
   </Group>
-  <OverallResults successes="933" failures="121" expectedFailures="21"/>
+  <OverallResults successes="937" failures="121" expectedFailures="21"/>
 </Catch>
diff --git a/packages/Catch2/projects/SelfTest/UsageTests/Matchers.tests.cpp b/packages/Catch2/projects/SelfTest/UsageTests/Matchers.tests.cpp
index 7bdc466ba08bb787b2132ce3ce2fa1b6c751f9cc..71abb8688dbeb3400e3710b621c6f3ee98d0bc97 100644
--- a/packages/Catch2/projects/SelfTest/UsageTests/Matchers.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/UsageTests/Matchers.tests.cpp
@@ -45,6 +45,10 @@ namespace { namespace MatchersTests {
     struct SpecialException : std::exception {
         SpecialException(int i_) : i(i_) {}
 
+        char const* what() const noexcept override {
+            return "SpecialException::what";
+        }
+
         int i;
     };
 
diff --git a/packages/Catch2/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp b/packages/Catch2/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp
index 8ab33249e99f7c4499eb51ec2e1e2d4493b34e59..a1f8c233a25e3d386410470ed08ffff7ba05c844 100644
--- a/packages/Catch2/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/UsageTests/ToStringGeneral.tests.cpp
@@ -115,3 +115,46 @@ TEST_CASE("Static arrays are convertible to string", "[toString]") {
         REQUIRE(Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })");
     }
 }
+
+struct WhatException : std::exception {
+    char const* what() const noexcept override {
+        return "This exception has overriden what() method";
+    }
+    ~WhatException() override;
+};
+
+struct OperatorException : std::exception {
+    ~OperatorException() override;
+};
+
+std::ostream& operator<<(std::ostream& out, OperatorException const&) {
+    out << "OperatorException";
+    return out;
+}
+
+struct StringMakerException : std::exception {
+    ~StringMakerException() override;
+};
+
+namespace Catch {
+template <>
+struct StringMaker<StringMakerException> {
+    static std::string convert(StringMakerException const&) {
+        return "StringMakerException";
+    }
+};
+}
+
+// Avoid -Wweak-tables
+WhatException::~WhatException() = default;
+OperatorException::~OperatorException() = default;
+StringMakerException::~StringMakerException() = default;
+
+
+
+
+TEST_CASE("Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified", "[toString][exception]") {
+    REQUIRE(::Catch::Detail::stringify(WhatException{}) == "This exception has overriden what() method");
+    REQUIRE(::Catch::Detail::stringify(OperatorException{}) == "OperatorException");
+    REQUIRE(::Catch::Detail::stringify(StringMakerException{}) == "StringMakerException");
+}
diff --git a/packages/Catch2/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp b/packages/Catch2/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp
index 7be99dcd42249f6ce18ee39f8a75aca0ab38c9ca..26afa3b12fcea142a72f92b217564dec21962b22 100644
--- a/packages/Catch2/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp
+++ b/packages/Catch2/projects/SelfTest/UsageTests/ToStringWhich.tests.cpp
@@ -20,6 +20,7 @@ struct has_operator { };
 struct has_maker {};
 struct has_maker_and_operator {};
 struct has_neither {};
+struct has_template_operator {};
 
 std::ostream& operator<<(std::ostream& os, const has_operator&) {
     os << "operator<<( has_operator )";
@@ -31,6 +32,12 @@ std::ostream& operator<<(std::ostream& os, const has_maker_and_operator&) {
     return os;
 }
 
+template <typename StreamT>
+StreamT& operator<<(StreamT& os, const has_template_operator&) {
+    os << "operator<<( has_template_operator )";
+    return os;
+}
+
 namespace Catch {
     template<>
     struct StringMaker<has_maker> {
@@ -69,6 +76,12 @@ TEST_CASE("stringify( has_neither )", "[toString]") {
     REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" );
 }
 
+// Call the templated operator
+TEST_CASE( "stringify( has_template_operator )", "[toString]" ) {
+    has_template_operator item;
+    REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" );
+}
+
 
 // Vectors...
 
diff --git a/packages/Catch2/projects/XCode/OCTest/OCTest.xcodeproj/project.pbxproj b/packages/Catch2/projects/XCode/OCTest/OCTest.xcodeproj/project.pbxproj
index 91e2cd9a6836057b271c3a4683c41e2aa9598442..71532036046603eff7f7289626a164e5009a5e9b 100644
--- a/packages/Catch2/projects/XCode/OCTest/OCTest.xcodeproj/project.pbxproj
+++ b/packages/Catch2/projects/XCode/OCTest/OCTest.xcodeproj/project.pbxproj
@@ -120,7 +120,7 @@
 		4A63D29C14E3C1A900F615CB /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0500;
+				LastUpgradeCheck = 0940;
 			};
 			buildConfigurationList = 4A63D29F14E3C1A900F615CB /* Build configuration list for PBXProject "OCTest" */;
 			compatibilityVersion = "Xcode 3.2";
@@ -159,16 +159,30 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
@@ -194,16 +208,29 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = YES;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
diff --git a/packages/Catch2/projects/XCode/OCTest/OCTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/Catch2/projects/XCode/OCTest/OCTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000000000000000000000000000000000000..18d981003d68d0546c4804ac2ff47dd97c6e7921
--- /dev/null
+++ b/packages/Catch2/projects/XCode/OCTest/OCTest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>
diff --git a/packages/Catch2/projects/XCode/OCTest/catch_objc_impl.mm b/packages/Catch2/projects/XCode/OCTest/catch_objc_impl.mm
index 01443cc93487d80756392529fcfe1ac44d080977..e439a3ab7c50b312f9f054b9179b41cec43cf10b 100644
--- a/packages/Catch2/projects/XCode/OCTest/catch_objc_impl.mm
+++ b/packages/Catch2/projects/XCode/OCTest/catch_objc_impl.mm
@@ -1,6 +1,7 @@
 // This file #includes all the .cpp files into a single .mm
 // - so they get compiled as ObjectiveC++
 
+#include "../../../include/internal/catch_tostring.cpp"
 #include "../../../include/internal/catch_approx.cpp"
 #include "../../../include/internal/catch_assertionhandler.cpp"
 #include "../../../include/internal/catch_assertionresult.cpp"
@@ -29,6 +30,7 @@
 #include "../../../include/internal/catch_matchers.cpp"
 #include "../../../include/internal/catch_matchers_string.cpp"
 #include "../../../include/internal/catch_message.cpp"
+#include "../../../include/internal/catch_output_redirect.cpp"
 #include "../../../include/internal/catch_random_number_generator.cpp"
 #include "../../../include/internal/catch_registry_hub.cpp"
 #include "../../../include/internal/catch_reporter_registry.cpp"
@@ -51,8 +53,8 @@
 #include "../../../include/internal/catch_test_spec.cpp"
 #include "../../../include/internal/catch_test_spec_parser.cpp"
 #include "../../../include/internal/catch_timer.cpp"
-#include "../../../include/internal/catch_tostring.cpp"
 #include "../../../include/internal/catch_totals.cpp"
+#include "../../../include/internal/catch_uncaught_exceptions.cpp"
 #include "../../../include/internal/catch_version.cpp"
 #include "../../../include/internal/catch_wildcard_pattern.cpp"
 #include "../../../include/internal/catch_xmlwriter.cpp"
@@ -63,5 +65,5 @@
 #include "../../../include/reporters/catch_reporter_compact.cpp"
 #include "../../../include/reporters/catch_reporter_console.cpp"
 #include "../../../include/reporters/catch_reporter_junit.cpp"
-#include "../../../include/reporters/catch_reporter_multi.cpp"
+#include "../../../include/reporters/catch_reporter_listening.cpp"
 #include "../../../include/reporters/catch_reporter_xml.cpp"
diff --git a/packages/Catch2/scripts/approvalTests.py b/packages/Catch2/scripts/approvalTests.py
index ee6a8f15378545f5100725867f91e4c727053c7e..3293c938885036f7723dd95dd12a3dc2d402c931 100755
--- a/packages/Catch2/scripts/approvalTests.py
+++ b/packages/Catch2/scripts/approvalTests.py
@@ -12,6 +12,10 @@ import difflib
 import scriptCommon
 from scriptCommon import catchPath
 
+if os.name == 'nt':
+	# Enable console colours on windows
+	os.system('')
+
 rootPath = os.path.join(catchPath, 'projects/SelfTest/Baselines')
 
 
@@ -87,7 +91,7 @@ def diffFiles(fileA, fileB):
     return [line for line in diff if line[0] in ('+', '-')]
 
 
-def filterLine(line):
+def filterLine(line, isCompact):
     if catchPath in line:
         # make paths relative to Catch root
         line = line.replace(catchPath + os.sep, '')
@@ -105,6 +109,10 @@ def filterLine(line):
     else:
         line = lineNumberParser.sub(" ", line)
 
+    if isCompact:
+        line = line.replace(': FAILED', ': failed')
+        line = line.replace(': PASSED', ': passed')
+        
     # strip Catch version number
     line = versionParser.sub("<version>", line)
 
@@ -144,7 +152,7 @@ def approve(baseName, args):
     rawFile = io.open(rawResultsPath, 'r', encoding='utf-8', errors='surrogateescape')
     filteredFile = io.open(filteredResultsPath, 'w', encoding='utf-8', errors='surrogateescape')
     for line in rawFile:
-        filteredFile.write(filterLine(line).rstrip() + "\n")
+        filteredFile.write(filterLine(line, 'compact' in baseName).rstrip() + "\n")
     filteredFile.close()
     rawFile.close()
 
diff --git a/packages/Catch2/scripts/updateVcpkgPackage.py b/packages/Catch2/scripts/updateVcpkgPackage.py
deleted file mode 100644
index c1f40b59e3abe85d41cb1bed60a5e141d421805e..0000000000000000000000000000000000000000
--- a/packages/Catch2/scripts/updateVcpkgPackage.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env python
-
-import io, os, re, sys, subprocess
-import hashlib
-
-from scriptCommon import catchPath
-from releaseCommon import Version
-
-print(catchPath)
-
-default_path = '../vcpkg/ports/catch2/'
-
-def adjusted_path(path):
-    return os.path.join(catchPath, path)
-
-def get_hash(path):
-    BUFF_SIZE = 65536
-    sha512 = hashlib.sha512()
-    # The newlines should be normalized into \n, which is what we want
-    # If reused use 'rb' with a file written with io.open(newline='\n')
-    with open(path, 'r') as f:
-        while True:
-            data = f.read(BUFF_SIZE)
-            if not data:
-                break
-            if sys.version_info[0] < 3:
-                sha512.update(data)
-            else:
-                sha512.update(data.encode('utf-8'))
-    return sha512.hexdigest()
-
-def update_control(path):
-    v = Version()
-
-    # Update control
-    lines = []
-    control_path = os.path.join(path, 'CONTROL')
-    with open(control_path, 'r') as f:
-        for line in f:
-            lines.append(line)
-    with open(control_path, 'w') as f:
-        for line in lines:
-            if 'Version: ' in line:
-                line = 'Version: {}\n'.format(v.getVersionString())
-            f.write(line)
-
-def update_portfile(path, header_hash, licence_hash):
-    print('Updating portfile')
-    v = Version()
-
-    # Update portfile
-    lines = []
-    portfile_path = os.path.join(path, 'portfile.cmake')
-    with open(portfile_path, 'r') as f:
-        for line in f:
-            lines.append(line)
-    with open(portfile_path, 'w') as f:
-        # There are three things we need to change/update
-        # 1) CATCH_VERSION cmake variable
-        # 2) Hash of header
-        # 3) Hash of licence
-        # We could assume licence never changes, but where is the fun in that?
-        for line in lines:
-            # Update the version
-            if 'set(CATCH_VERSION' in line:
-                line = 'set(CATCH_VERSION v{})\n'.format(v.getVersionString())
-
-            # Determine which file we are updating
-            if 'vcpkg_download_distfile' in line:
-                kind = line.split('(')[-1].strip()
-
-            # Update the hashes
-            if 'SHA512' in line and kind == 'HEADER':
-                line = '    SHA512 {}\n'.format(header_hash)
-            if 'SHA512' in line and kind == 'LICENSE':
-                line = '    SHA512 {}\n'.format(licence_hash)
-            f.write(line)
-
-
-def git_push(path_to_repo):
-    v = Version()
-    ver_string = v.getVersionString()
-
-    os.chdir(path_to_repo)
-
-    # Work with git
-    # Make sure we branch off master
-    subprocess.call('git checkout master', shell=True)
-    
-    # Update repo to current master, so we don't work off old version of the portfile 
-    subprocess.call('git pull Microsoft master', shell=True)
-    subprocess.call('git push', shell=True)
-
-    # Create a new branch for the update
-    subprocess.call('git checkout -b catch-{}'.format(ver_string), shell=True)
-    # Add changed files (should be only our files)
-    subprocess.call('git add -u .', shell=True)
-    # Create a commit with these changes
-    subprocess.call('git commit -m "Update Catch to {}"'.format(ver_string), shell=True)
-    # Don't push, so author can review
-    print('Changes were commited to the vcpkg fork. Please check, push and open PR.')
-
-header_hash = get_hash(adjusted_path('single_include/catch.hpp'))
-licence_hash = get_hash(adjusted_path('LICENSE.txt'))
-update_control(adjusted_path(default_path))
-update_portfile(adjusted_path(default_path), header_hash, licence_hash)
-
-git_push(adjusted_path('../vcpkg'))
diff --git a/packages/Catch2/single_include/catch.hpp b/packages/Catch2/single_include/catch.hpp
index ecd8907ea30f1f2a2e0d184e7161c60a1aba80a0..28448ddb22e17f7f6a536fa8a932489447c2cfd7 100644
--- a/packages/Catch2/single_include/catch.hpp
+++ b/packages/Catch2/single_include/catch.hpp
@@ -1,6 +1,6 @@
 /*
- *  Catch v2.2.2
- *  Generated: 2018-04-06 12:05:03.186665
+ *  Catch v2.2.3
+ *  Generated: 2018-06-06 23:11:57.601416
  *  ----------------------------------------------------------
  *  This file has been merged from multiple headers. Please don't edit it directly
  *  Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved.
@@ -15,7 +15,7 @@
 
 #define CATCH_VERSION_MAJOR 2
 #define CATCH_VERSION_MINOR 2
-#define CATCH_VERSION_PATCH 2
+#define CATCH_VERSION_PATCH 3
 
 #ifdef __clang__
 #    pragma clang system_header
@@ -72,7 +72,7 @@
 #elif defined(linux) || defined(__linux) || defined(__linux__)
 #  define CATCH_PLATFORM_LINUX
 
-#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
 #  define CATCH_PLATFORM_WINDOWS
 #endif
 
@@ -164,6 +164,18 @@ namespace Catch {
 #       define CATCH_CONFIG_COLOUR_NONE
 #endif
 
+////////////////////////////////////////////////////////////////////////////////
+// Android somehow still does not support std::to_string
+#if defined(__ANDROID__)
+#    define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Not all Windows environments support SEH properly
+#if defined(__MINGW32__)
+#    define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
+#endif
+
 ////////////////////////////////////////////////////////////////////////////////
 // Cygwin
 #ifdef __CYGWIN__
@@ -213,7 +225,7 @@ namespace Catch {
 #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
 #   define CATCH_CONFIG_COUNTER
 #endif
-#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)
 #   define CATCH_CONFIG_WINDOWS_SEH
 #endif
 // This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
@@ -225,6 +237,10 @@ namespace Catch {
 #   define CATCH_CONFIG_WCHAR
 #endif
 
+#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
+#    define CATCH_CONFIG_CPP11_TO_STRING
+#endif
+
 #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
 #  define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
 #endif
@@ -513,12 +529,17 @@ struct AutoReg : NonCopyable {
 
 } // end namespace Catch
 
+#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)
+#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
+#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
+#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+
 #if defined(CATCH_CONFIG_DISABLE)
     #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
         static void TestName()
     #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
         namespace{                        \
-            struct TestName : ClassName { \
+            struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \
                 void test();              \
             };                            \
         }                                 \
@@ -546,7 +567,7 @@ struct AutoReg : NonCopyable {
     #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
         namespace{ \
-            struct TestName : ClassName{ \
+            struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \
                 void test(); \
             }; \
             Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
@@ -770,16 +791,22 @@ namespace Catch {
         std::string convertUnknownEnumToString( E e );
 
         template<typename T>
-        typename std::enable_if<!std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) {
-#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
-            (void)value;
+        typename std::enable_if<
+            !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
+        std::string>::type convertUnstreamable( T const& ) {
             return Detail::unprintableString;
-#else
-            return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
-#endif
         }
         template<typename T>
-        typename std::enable_if<std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) {
+        typename std::enable_if<
+            !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
+         std::string>::type convertUnstreamable(T const& ex) {
+            return ex.what();
+        }
+
+        template<typename T>
+        typename std::enable_if<
+            std::is_enum<T>::value
+        , std::string>::type convertUnstreamable( T const& value ) {
             return convertUnknownEnumToString( value );
         }
 
@@ -805,7 +832,9 @@ namespace Catch {
         typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
             convert(const Fake& value) {
                 ReusableStringStream rss;
-                rss << value;
+                // NB: call using the function-like syntax to avoid ambiguity with
+                // user-defined templated operator<< under clang.
+                rss.operator<<(value);
                 return rss.str();
         }
 
@@ -813,7 +842,11 @@ namespace Catch {
         static
         typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
             convert( const Fake& value ) {
-                return Detail::convertUnstreamable( value );
+#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
+            return Detail::convertUnstreamable(value);
+#else
+            return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
+#endif
         }
     };
 
@@ -3354,8 +3387,12 @@ namespace Catch {
         std::string outputFilename;
         std::string name;
         std::string processName;
+#ifndef CATCH_CONFIG_DEFAULT_REPORTER
+#define CATCH_CONFIG_DEFAULT_REPORTER "console"
+#endif
+        std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
+#undef CATCH_CONFIG_DEFAULT_REPORTER
 
-        std::vector<std::string> reporterNames;
         std::vector<std::string> testsOrTags;
         std::vector<std::string> sectionsToRun;
     };
@@ -3375,8 +3412,8 @@ namespace Catch {
         bool listReporters() const;
 
         std::string getProcessName() const;
+        std::string const& getReporterName() const;
 
-        std::vector<std::string> const& getReporterNames() const;
         std::vector<std::string> const& getTestsOrTags() const;
         std::vector<std::string> const& getSectionsToRun() const override;
 
@@ -3733,8 +3770,6 @@ namespace Catch {
         virtual Listeners const& getListeners() const = 0;
     };
 
-    void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
-
 } // end namespace Catch
 
 // end catch_interfaces_reporter.h
@@ -3742,7 +3777,7 @@ namespace Catch {
 #include <cstring>
 #include <cfloat>
 #include <cstdio>
-#include <assert.h>
+#include <cassert>
 #include <memory>
 #include <ostream>
 
@@ -6592,7 +6627,7 @@ namespace Catch {
             | Opt( config.outputFilename, "filename" )
                 ["-o"]["--out"]
                 ( "output filename" )
-            | Opt( config.reporterNames, "name" )
+            | Opt( config.reporterName, "name" )
                 ["-r"]["--reporter"]
                 ( "reporter to use (defaults to console)" )
             | Opt( config.name, "name" )
@@ -6734,8 +6769,8 @@ namespace Catch {
     bool Config::listReporters() const      { return m_data.listReporters; }
 
     std::string Config::getProcessName() const { return m_data.processName; }
+    std::string const& Config::getReporterName() const { return m_data.reporterName; }
 
-    std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
     std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
     std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
 
@@ -7381,6 +7416,11 @@ namespace Catch {
         int id;
         const char* name;
     };
+
+    // 32kb for the alternate stack seems to be sufficient. However, this value
+    // is experimentally determined, so that's not guaranteed.
+    constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
+
     static SignalDefs signalDefs[] = {
         { SIGINT,  "SIGINT - Terminal interrupt signal" },
         { SIGILL,  "SIGILL - Illegal instruction signal" },
@@ -7407,7 +7447,7 @@ namespace Catch {
         isSet = true;
         stack_t sigStack;
         sigStack.ss_sp = altStackMem;
-        sigStack.ss_size = SIGSTKSZ;
+        sigStack.ss_size = sigStackSize;
         sigStack.ss_flags = 0;
         sigaltstack(&sigStack, &oldSigStack);
         struct sigaction sa = { };
@@ -7438,7 +7478,7 @@ namespace Catch {
     bool FatalConditionHandler::isSet = false;
     struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
     stack_t FatalConditionHandler::oldSigStack = {};
-    char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+    char FatalConditionHandler::altStackMem[sigStackSize] = {};
 
 } // namespace Catch
 
@@ -7482,16 +7522,18 @@ namespace Catch {
 // end catch_interfaces_registry_hub.cpp
 // start catch_interfaces_reporter.cpp
 
-// start catch_reporter_multi.h
+// start catch_reporter_listening.h
 
 namespace Catch {
 
-    class MultipleReporters : public IStreamingReporter {
+    class ListeningReporter : public IStreamingReporter {
         using Reporters = std::vector<IStreamingReporterPtr>;
-        Reporters m_reporters;
+        Reporters m_listeners;
+        IStreamingReporterPtr m_reporter = nullptr;
 
     public:
-        void add( IStreamingReporterPtr&& reporter );
+        void addListener( IStreamingReporterPtr&& listener );
+        void addReporter( IStreamingReporterPtr&& reporter );
 
     public: // IStreamingReporter
 
@@ -7524,7 +7566,7 @@ namespace Catch {
 
 } // end namespace Catch
 
-// end catch_reporter_multi.h
+// end catch_reporter_listening.h
 namespace Catch {
 
     ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )
@@ -7625,27 +7667,6 @@ namespace Catch {
     IReporterFactory::~IReporterFactory() = default;
     IReporterRegistry::~IReporterRegistry() = default;
 
-    void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
-
-        if( !existingReporter ) {
-            existingReporter = std::move( additionalReporter );
-            return;
-        }
-
-        MultipleReporters* multi = nullptr;
-
-        if( existingReporter->isMulti() ) {
-            multi = static_cast<MultipleReporters*>( existingReporter.get() );
-        }
-        else {
-            auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
-            newMulti->add( std::move( existingReporter ) );
-            multi = newMulti.get();
-            existingReporter = std::move( newMulti );
-        }
-        multi->add( std::move( additionalReporter ) );
-    }
-
 } // end namespace Catch
 // end catch_interfaces_reporter.cpp
 // start catch_interfaces_runner.cpp
@@ -7887,6 +7908,24 @@ using Matchers::Impl::MatcherBase;
 // end catch_matchers.cpp
 // start catch_matchers_floating.cpp
 
+// start catch_to_string.hpp
+
+#include <string>
+
+namespace Catch {
+    template <typename T>
+    std::string to_string(T const& t) {
+#if defined(CATCH_CONFIG_CPP11_TO_STRING)
+        return std::to_string(t);
+#else
+        ReusableStringStream rss;
+        rss << t;
+        return rss.str();
+#endif
+    }
+} // end namespace Catch
+
+// end catch_to_string.hpp
 #include <cstdlib>
 #include <cstdint>
 #include <cstring>
@@ -7992,7 +8031,7 @@ namespace Floating {
     }
 
     std::string WithinUlpsMatcher::describe() const {
-        return "is within " + std::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
+        return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
     }
 
 }// namespace Floating
@@ -8179,6 +8218,213 @@ namespace Catch {
     }
 } // end namespace Catch
 // end catch_message.cpp
+// start catch_output_redirect.cpp
+
+// start catch_output_redirect.h
+#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+
+#include <cstdio>
+#include <iosfwd>
+#include <string>
+
+namespace Catch {
+
+    class RedirectedStream {
+        std::ostream& m_originalStream;
+        std::ostream& m_redirectionStream;
+        std::streambuf* m_prevBuf;
+
+    public:
+        RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
+        ~RedirectedStream();
+    };
+
+    class RedirectedStdOut {
+        ReusableStringStream m_rss;
+        RedirectedStream m_cout;
+    public:
+        RedirectedStdOut();
+        auto str() const -> std::string;
+    };
+
+    // StdErr has two constituent streams in C++, std::cerr and std::clog
+    // This means that we need to redirect 2 streams into 1 to keep proper
+    // order of writes
+    class RedirectedStdErr {
+        ReusableStringStream m_rss;
+        RedirectedStream m_cerr;
+        RedirectedStream m_clog;
+    public:
+        RedirectedStdErr();
+        auto str() const -> std::string;
+    };
+
+    // Windows's implementation of std::tmpfile is terrible (it tries
+    // to create a file inside system folder, thus requiring elevated
+    // privileges for the binary), so we have to use tmpnam(_s) and
+    // create the file ourselves there.
+    class TempFile {
+    public:
+        TempFile(TempFile const&) = delete;
+        TempFile& operator=(TempFile const&) = delete;
+        TempFile(TempFile&&) = delete;
+        TempFile& operator=(TempFile&&) = delete;
+
+        TempFile();
+        ~TempFile();
+
+        std::FILE* getFile();
+        std::string getContents();
+
+    private:
+        std::FILE* m_file = nullptr;
+    #if defined(_MSC_VER)
+        char m_buffer[L_tmpnam] = { 0 };
+    #endif
+    };
+
+    class OutputRedirect {
+    public:
+        OutputRedirect(OutputRedirect const&) = delete;
+        OutputRedirect& operator=(OutputRedirect const&) = delete;
+        OutputRedirect(OutputRedirect&&) = delete;
+        OutputRedirect& operator=(OutputRedirect&&) = delete;
+
+        OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
+        ~OutputRedirect();
+
+    private:
+        int m_originalStdout = -1;
+        int m_originalStderr = -1;
+        TempFile m_stdoutFile;
+        TempFile m_stderrFile;
+        std::string& m_stdoutDest;
+        std::string& m_stderrDest;
+    };
+
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+// end catch_output_redirect.h
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+
+#if defined(_MSC_VER)
+#include <io.h>      //_dup and _dup2
+#define dup _dup
+#define dup2 _dup2
+#define fileno _fileno
+#else
+#include <unistd.h>  // dup and dup2
+#endif
+
+namespace Catch {
+
+    RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
+    :   m_originalStream( originalStream ),
+        m_redirectionStream( redirectionStream ),
+        m_prevBuf( m_originalStream.rdbuf() )
+    {
+        m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
+    }
+
+    RedirectedStream::~RedirectedStream() {
+        m_originalStream.rdbuf( m_prevBuf );
+    }
+
+    RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
+    auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
+
+    RedirectedStdErr::RedirectedStdErr()
+    :   m_cerr( Catch::cerr(), m_rss.get() ),
+        m_clog( Catch::clog(), m_rss.get() )
+    {}
+    auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
+
+#if defined(_MSC_VER)
+    TempFile::TempFile() {
+        if (tmpnam_s(m_buffer)) {
+            throw std::runtime_error("Could not get a temp filename");
+        }
+        if (fopen_s(&m_file, m_buffer, "w")) {
+            char buffer[100];
+            if (strerror_s(buffer, errno)) {
+                throw std::runtime_error("Could not translate errno to string");
+            }
+            throw std::runtime_error("Could not open the temp file: " + std::string(m_buffer) + buffer);
+        }
+    }
+#else
+    TempFile::TempFile() {
+        m_file = std::tmpfile();
+        if (!m_file) {
+            throw std::runtime_error("Could not create a temp file.");
+        }
+    }
+
+#endif
+
+    TempFile::~TempFile() {
+         // TBD: What to do about errors here?
+         std::fclose(m_file);
+         // We manually create the file on Windows only, on Linux
+         // it will be autodeleted
+#if defined(_MSC_VER)
+         std::remove(m_buffer);
+#endif
+    }
+
+    FILE* TempFile::getFile() {
+        return m_file;
+    }
+
+    std::string TempFile::getContents() {
+        std::stringstream sstr;
+        char buffer[100] = {};
+        std::rewind(m_file);
+        while (std::fgets(buffer, sizeof(buffer), m_file)) {
+            sstr << buffer;
+        }
+        return sstr.str();
+    }
+
+    OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
+        m_originalStdout(dup(1)),
+        m_originalStderr(dup(2)),
+        m_stdoutDest(stdout_dest),
+        m_stderrDest(stderr_dest) {
+        dup2(fileno(m_stdoutFile.getFile()), 1);
+        dup2(fileno(m_stderrFile.getFile()), 2);
+    }
+
+    OutputRedirect::~OutputRedirect() {
+        Catch::cout() << std::flush;
+        fflush(stdout);
+        // Since we support overriding these streams, we flush cerr
+        // even though std::cerr is unbuffered
+        Catch::cerr() << std::flush;
+        Catch::clog() << std::flush;
+        fflush(stderr);
+
+        dup2(m_originalStdout, 1);
+        dup2(m_originalStderr, 2);
+
+        m_stdoutDest += m_stdoutFile.getContents();
+        m_stderrDest += m_stderrFile.getContents();
+    }
+
+} // namespace Catch
+
+#if defined(_MSC_VER)
+#undef dup
+#undef dup2
+#undef fileno
+#endif
+// end catch_output_redirect.cpp
 // start catch_random_number_generator.cpp
 
 // start catch_random_number_generator.h
@@ -8507,47 +8753,6 @@ namespace Catch {
 
 namespace Catch {
 
-    class RedirectedStream {
-        std::ostream& m_originalStream;
-        std::ostream& m_redirectionStream;
-        std::streambuf* m_prevBuf;
-
-    public:
-        RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
-        :   m_originalStream( originalStream ),
-            m_redirectionStream( redirectionStream ),
-            m_prevBuf( m_originalStream.rdbuf() )
-        {
-            m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
-        }
-        ~RedirectedStream() {
-            m_originalStream.rdbuf( m_prevBuf );
-        }
-    };
-
-    class RedirectedStdOut {
-        ReusableStringStream m_rss;
-        RedirectedStream m_cout;
-    public:
-        RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
-        auto str() const -> std::string { return m_rss.str(); }
-    };
-
-    // StdErr has two constituent streams in C++, std::cerr and std::clog
-    // This means that we need to redirect 2 streams into 1 to keep proper
-    // order of writes
-    class RedirectedStdErr {
-        ReusableStringStream m_rss;
-        RedirectedStream m_cerr;
-        RedirectedStream m_clog;
-    public:
-        RedirectedStdErr()
-        :   m_cerr( Catch::cerr(), m_rss.get() ),
-            m_clog( Catch::clog(), m_rss.get() )
-        {}
-        auto str() const -> std::string { return m_rss.str(); }
-    };
-
     RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
     :   m_runInfo(_config->name()),
         m_context(getCurrentMutableContext()),
@@ -8794,13 +8999,19 @@ namespace Catch {
         Timer timer;
         try {
             if (m_reporter->getPreferences().shouldRedirectStdOut) {
+#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
                 RedirectedStdOut redirectedStdOut;
                 RedirectedStdErr redirectedStdErr;
+
                 timer.start();
                 invokeActiveTestCase();
                 redirectedCout += redirectedStdOut.str();
                 redirectedCerr += redirectedStdErr.str();
-
+#else
+                OutputRedirect r(redirectedCout, redirectedCerr);
+                timer.start();
+                invokeActiveTestCase();
+#endif
             } else {
                 timer.start();
                 invokeActiveTestCase();
@@ -9094,32 +9305,25 @@ namespace Catch {
             return reporter;
         }
 
-#ifndef CATCH_CONFIG_DEFAULT_REPORTER
-#define CATCH_CONFIG_DEFAULT_REPORTER "console"
-#endif
-
         IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
-            auto const& reporterNames = config->getReporterNames();
-            if (reporterNames.empty())
-                return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config);
-
-            IStreamingReporterPtr reporter;
-            for (auto const& name : reporterNames)
-                addReporter(reporter, createReporter(name, config));
-            return reporter;
-        }
+            if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
+                return createReporter(config->getReporterName(), config);
+            }
 
-#undef CATCH_CONFIG_DEFAULT_REPORTER
+            auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
 
-        void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) {
             auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
-            for (auto const& listener : listeners)
-                addReporter(reporters, listener->create(Catch::ReporterConfig(config)));
+            for (auto const& listener : listeners) {
+                multi->addListener(listener->create(Catch::ReporterConfig(config)));
+            }
+            multi->addReporter(createReporter(config->getReporterName(), config));
+            return std::move(multi);
         }
 
         Catch::Totals runTests(std::shared_ptr<Config> const& config) {
-            IStreamingReporterPtr reporter = makeReporter(config);
-            addListeners(reporter, config);
+            // FixMe: Add listeners in order first, then add reporters.
+
+            auto reporter = makeReporter(config);
 
             RunContext context(config, std::move(reporter));
 
@@ -9847,7 +10051,7 @@ namespace Catch {
             return TestCaseInfo::None;
     }
     bool isReservedTag( std::string const& tag ) {
-        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
+        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
     }
     void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
         CATCH_ENFORCE( !isReservedTag(tag),
@@ -10085,7 +10289,7 @@ namespace Catch {
 // start catch_test_case_tracker.cpp
 
 #include <algorithm>
-#include <assert.h>
+#include <cassert>
 #include <stdexcept>
 #include <memory>
 #include <sstream>
@@ -10913,7 +11117,7 @@ namespace Catch {
     }
 
     Version const& libraryVersion() {
-        static Version version( 2, 2, 2, "", 0 );
+        static Version version( 2, 2, 3, "", 0 );
         return version;
     }
 
@@ -11240,7 +11444,7 @@ namespace {
 #include <cstring>
 #include <cfloat>
 #include <cstdio>
-#include <assert.h>
+#include <cassert>
 #include <memory>
 
 namespace Catch {
@@ -12183,7 +12387,7 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
 // end catch_reporter_console.cpp
 // start catch_reporter_junit.cpp
 
-#include <assert.h>
+#include <cassert>
 #include <sstream>
 #include <ctime>
 #include <algorithm>
@@ -12416,100 +12620,133 @@ namespace Catch {
 
 } // end namespace Catch
 // end catch_reporter_junit.cpp
-// start catch_reporter_multi.cpp
+// start catch_reporter_listening.cpp
+
+#include <cassert>
 
 namespace Catch {
 
-    void MultipleReporters::add( IStreamingReporterPtr&& reporter ) {
-        m_reporters.push_back( std::move( reporter ) );
+    void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {
+        m_listeners.push_back( std::move( listener ) );
     }
 
-    ReporterPreferences MultipleReporters::getPreferences() const {
-        return m_reporters[0]->getPreferences();
+    void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {
+        assert(!m_reporter && "Listening reporter can wrap only 1 real reporter");
+        m_reporter = std::move( reporter );
     }
 
-    std::set<Verbosity> MultipleReporters::getSupportedVerbosities() {
+    ReporterPreferences ListeningReporter::getPreferences() const {
+        return m_reporter->getPreferences();
+    }
+
+    std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {
         return std::set<Verbosity>{ };
     }
 
-    void MultipleReporters::noMatchingTestCases( std::string const& spec ) {
-        for( auto const& reporter : m_reporters )
-            reporter->noMatchingTestCases( spec );
+    void ListeningReporter::noMatchingTestCases( std::string const& spec ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->noMatchingTestCases( spec );
+        }
+        m_reporter->noMatchingTestCases( spec );
     }
 
-    void MultipleReporters::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->benchmarkStarting( benchmarkInfo );
+    void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->benchmarkStarting( benchmarkInfo );
+        }
+        m_reporter->benchmarkStarting( benchmarkInfo );
     }
-    void MultipleReporters::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->benchmarkEnded( benchmarkStats );
+    void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->benchmarkEnded( benchmarkStats );
+        }
+        m_reporter->benchmarkEnded( benchmarkStats );
     }
 
-    void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testRunStarting( testRunInfo );
+    void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testRunStarting( testRunInfo );
+        }
+        m_reporter->testRunStarting( testRunInfo );
     }
 
-    void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testGroupStarting( groupInfo );
+    void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testGroupStarting( groupInfo );
+        }
+        m_reporter->testGroupStarting( groupInfo );
     }
 
-    void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testCaseStarting( testInfo );
+    void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testCaseStarting( testInfo );
+        }
+        m_reporter->testCaseStarting( testInfo );
     }
 
-    void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->sectionStarting( sectionInfo );
+    void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->sectionStarting( sectionInfo );
+        }
+        m_reporter->sectionStarting( sectionInfo );
     }
 
-    void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->assertionStarting( assertionInfo );
+    void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->assertionStarting( assertionInfo );
+        }
+        m_reporter->assertionStarting( assertionInfo );
     }
 
     // The return value indicates if the messages buffer should be cleared:
-    bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) {
-        bool clearBuffer = false;
-        for( auto const& reporter : m_reporters )
-            clearBuffer |= reporter->assertionEnded( assertionStats );
-        return clearBuffer;
+    bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {
+        for( auto const& listener : m_listeners ) {
+            static_cast<void>( listener->assertionEnded( assertionStats ) );
+        }
+        return m_reporter->assertionEnded( assertionStats );
     }
 
-    void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->sectionEnded( sectionStats );
+    void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->sectionEnded( sectionStats );
+        }
+        m_reporter->sectionEnded( sectionStats );
     }
 
-    void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testCaseEnded( testCaseStats );
+    void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testCaseEnded( testCaseStats );
+        }
+        m_reporter->testCaseEnded( testCaseStats );
     }
 
-    void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testGroupEnded( testGroupStats );
+    void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testGroupEnded( testGroupStats );
+        }
+        m_reporter->testGroupEnded( testGroupStats );
     }
 
-    void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testRunEnded( testRunStats );
+    void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testRunEnded( testRunStats );
+        }
+        m_reporter->testRunEnded( testRunStats );
     }
 
-    void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->skipTest( testInfo );
+    void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->skipTest( testInfo );
+        }
+        m_reporter->skipTest( testInfo );
     }
 
-    bool MultipleReporters::isMulti() const {
+    bool ListeningReporter::isMulti() const {
         return true;
     }
 
 } // end namespace Catch
-// end catch_reporter_multi.cpp
+// end catch_reporter_listening.cpp
 // start catch_reporter_xml.cpp
 
 #if defined(_MSC_VER)
diff --git a/packages/Catch2/test_package/conanfile.py b/packages/Catch2/test_package/conanfile.py
index f95bfbdb45895254f638cdff691e90087af56481..7ed77b5cafa1477f80778ccff43b8ae1dcf9a010 100644
--- a/packages/Catch2/test_package/conanfile.py
+++ b/packages/Catch2/test_package/conanfile.py
@@ -10,7 +10,7 @@ class CatchConanTest(ConanFile):
     settings = "os", "compiler", "arch", "build_type"
     username = getenv("CONAN_USERNAME", "philsquared")
     channel = getenv("CONAN_CHANNEL", "testing")
-    requires = "Catch/2.2.2@%s/%s" % (username, channel)
+    requires = "Catch/2.2.3@%s/%s" % (username, channel)
 
     def build(self):
         cmake = CMake(self)