diff options
Diffstat (limited to 'libmemcached-awesome-catch.patch')
-rw-r--r-- | libmemcached-awesome-catch.patch | 957 |
1 files changed, 957 insertions, 0 deletions
diff --git a/libmemcached-awesome-catch.patch b/libmemcached-awesome-catch.patch new file mode 100644 index 0000000..79e7d93 --- /dev/null +++ b/libmemcached-awesome-catch.patch @@ -0,0 +1,957 @@ +From ec4b275c7dab0af781c8e2571021d4821736eef9 Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Fri, 25 Jun 2021 08:17:53 +0200 +Subject: [PATCH] fix gh issue #113 + +--- + ChangeLog-1.1.md | 8 + + docs/source/ChangeLog-1.1.rst | 12 + + scripts/download_catch2.sh | 5 + + test/lib/catch.hpp | 548 +++++++++++++++++++++------------- + 4 files changed, 368 insertions(+), 205 deletions(-) + create mode 100755 scripts/download_catch2.sh + +diff --git a/ChangeLog-1.1.md b/ChangeLog-1.1.md +index c5ff5971..719140ff 100644 +--- a/ChangeLog-1.1.md ++++ b/ChangeLog-1.1.md +@@ -1,5 +1,13 @@ + # ChangeLog v1.1 + ++## v 1.1.1 ++ ++> released TBD ++ ++* Fix [gh #113](https://github.com/awesomized/libmemcached/issues/105): ++ Build failure with Catch2 < 2.13.5. ++ ++ + ## v 1.1.0 + + > released 2021-06-23 +diff --git a/docs/source/ChangeLog-1.1.rst b/docs/source/ChangeLog-1.1.rst +index 6a9cb3c1..4e31142d 100644 +--- a/docs/source/ChangeLog-1.1.rst ++++ b/docs/source/ChangeLog-1.1.rst +@@ -5,6 +5,18 @@ + ChangeLog v1.1 + ============== + ++v 1.1.1 ++------- ++ ++.. ++ ++ released TBD ++ ++ ++ ++* Fix `gh #113 <https://github.com/awesomized/libmemcached/issues/105>`_\ : ++ Build failure with Catch2 < 2.13.5. ++ + v 1.1.0 + ------- + +diff --git a/scripts/download_catch2.sh b/scripts/download_catch2.sh +new file mode 100755 +index 00000000..24383983 +--- /dev/null ++++ b/scripts/download_catch2.sh +@@ -0,0 +1,5 @@ ++#!/bin/bash ++curl -sSLO $(curl -sSI https://github.com/catchorg/Catch2/releases/latest | sed -ne '\,^[Ll]ocation: *, !d ++s,[Ll]ocation: *\(.*\)/tag/,\1/download/, ++s,.$,/catch.hpp, ++p') +diff --git a/test/lib/catch.hpp b/test/lib/catch.hpp +index cf1fae15..36eaeb27 100644 +--- a/test/lib/catch.hpp ++++ b/test/lib/catch.hpp +@@ -1,9 +1,9 @@ + /* +- * Catch v2.13.0 +- * Generated: 2020-07-12 20:07:49.015950 ++ * Catch v2.13.6 ++ * Generated: 2021-04-16 18:23:38.044268 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly +- * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. ++ * Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved. + * + * 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) +@@ -15,7 +15,7 @@ + + #define CATCH_VERSION_MAJOR 2 + #define CATCH_VERSION_MINOR 13 +-#define CATCH_VERSION_PATCH 0 ++#define CATCH_VERSION_PATCH 6 + + #ifdef __clang__ + # pragma clang system_header +@@ -66,13 +66,16 @@ + #if !defined(CATCH_CONFIG_IMPL_ONLY) + // start catch_platform.h + ++// See e.g.: ++// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html + #ifdef __APPLE__ +-# include <TargetConditionals.h> +-# if TARGET_OS_OSX == 1 +-# define CATCH_PLATFORM_MAC +-# elif TARGET_OS_IPHONE == 1 +-# define CATCH_PLATFORM_IPHONE +-# endif ++# include <TargetConditionals.h> ++# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ ++ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) ++# define CATCH_PLATFORM_MAC ++# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) ++# define CATCH_PLATFORM_IPHONE ++# endif + + #elif defined(linux) || defined(__linux) || defined(__linux__) + # define CATCH_PLATFORM_LINUX +@@ -132,13 +135,9 @@ namespace Catch { + + #endif + +-#if defined(__cpp_lib_uncaught_exceptions) +-# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +-#endif +- +-// We have to avoid both ICC and Clang, because they try to mask themselves +-// as gcc, and we want only GCC in this block +-#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) ++// Only GCC compiler should be used in this block, so other compilers trying to ++// mask themselves as GCC should be ignored. ++#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) + # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) + # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +@@ -162,7 +161,7 @@ namespace Catch { + // ``` + // + // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +-# if !defined(__ibmxl__) ++# if !defined(__ibmxl__) && !defined(__CUDACC__) + # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ + # endif + +@@ -244,10 +243,6 @@ namespace Catch { + # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) + # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +-# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +-# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +-# endif +- + // Universal Windows platform does not support SEH + // Or console colours (or console at all...) + # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +@@ -330,7 +325,10 @@ namespace Catch { + + // Check if byte is available and usable + # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) +- # define CATCH_INTERNAL_CONFIG_CPP17_BYTE ++ # include <cstddef> ++ # if __cpp_lib_byte > 0 ++ # define CATCH_INTERNAL_CONFIG_CPP17_BYTE ++ # endif + # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable +@@ -373,10 +371,6 @@ namespace Catch { + # define CATCH_CONFIG_CPP17_OPTIONAL + #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 +- + #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) + # define CATCH_CONFIG_CPP17_STRING_VIEW + #endif +@@ -1105,7 +1099,7 @@ struct AutoReg : NonCopyable { + int index = 0; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ + using expander = int[];\ +- (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \ ++ (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ +@@ -1151,7 +1145,7 @@ struct AutoReg : NonCopyable { + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ + constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ + constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ +- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\ ++ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\ + } \ + }; \ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ +@@ -1195,7 +1189,7 @@ struct AutoReg : NonCopyable { + void reg_tests() { \ + int index = 0; \ + using expander = int[]; \ +- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */\ ++ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ + } \ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ +@@ -1229,7 +1223,7 @@ struct AutoReg : NonCopyable { + int index = 0; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ + using expander = int[];\ +- (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \ ++ (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ +@@ -1278,7 +1272,7 @@ struct AutoReg : NonCopyable { + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ + constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ + constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ +- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \ ++ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ +@@ -1325,7 +1319,7 @@ struct AutoReg : NonCopyable { + void reg_tests(){\ + int index = 0;\ + using expander = int[];\ +- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */ \ ++ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ +@@ -1829,8 +1823,8 @@ namespace Catch { + #endif + + namespace Detail { +- template<typename InputIterator> +- std::string rangeToString(InputIterator first, InputIterator last) { ++ template<typename InputIterator, typename Sentinel = InputIterator> ++ std::string rangeToString(InputIterator first, Sentinel last) { + ReusableStringStream rss; + rss << "{ "; + if (first != last) { +@@ -7063,8 +7057,8 @@ namespace Catch { + double b2 = bias - z1; + double a1 = a(b1); + double a2 = a(b2); +- auto lo = std::max(cumn(a1), 0); +- auto hi = std::min(cumn(a2), n - 1); ++ auto lo = (std::max)(cumn(a1), 0); ++ auto hi = (std::min)(cumn(a2), n - 1); + + return { point, resample[lo], resample[hi], confidence_level }; + } +@@ -7133,7 +7127,9 @@ namespace Catch { + } + template <typename Clock> + EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) { +- auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit)); ++ auto time_limit = (std::min)( ++ resolution * clock_cost_estimation_tick_limit, ++ FloatDuration<Clock>(clock_cost_estimation_time_limit)); + auto time_clock = [](int k) { + return Detail::measure<Clock>([k] { + for (int i = 0; i < k; ++i) { +@@ -7611,6 +7607,10 @@ namespace TestCaseTracking { + + void addInitialFilters( std::vector<std::string> const& filters ); + void addNextFilters( std::vector<std::string> const& filters ); ++ //! Returns filters active in this tracker ++ std::vector<std::string> const& getFilters() const; ++ //! Returns whitespace-trimmed name of the tracked section ++ std::string const& trimmedName() const; + }; + + } // namespace TestCaseTracking +@@ -7776,7 +7776,7 @@ namespace Catch { + double sb = stddev.point; + double mn = mean.point / n; + double mg_min = mn / 2.; +- double sg = std::min(mg_min / 4., sb / std::sqrt(n)); ++ double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); + double sg2 = sg * sg; + double sb2 = sb * sb; + +@@ -7795,7 +7795,7 @@ namespace Catch { + return (nc / n) * (sb2 - nc * sg2); + }; + +- return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2; ++ return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; + } + + bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) { +@@ -7985,86 +7985,58 @@ namespace Catch { + + // start catch_fatal_condition.h + +-// start catch_windows_h_proxy.h +- +- +-#if defined(CATCH_PLATFORM_WINDOWS) +- +-#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +-# define CATCH_DEFINED_NOMINMAX +-# define NOMINMAX +-#endif +-#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +-# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +-# define WIN32_LEAN_AND_MEAN +-#endif +- +-#ifdef __AFXDLL +-#include <AfxWin.h> +-#else +-#include <windows.h> +-#endif +- +-#ifdef CATCH_DEFINED_NOMINMAX +-# undef NOMINMAX +-#endif +-#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +-# undef WIN32_LEAN_AND_MEAN +-#endif +- +-#endif // defined(CATCH_PLATFORM_WINDOWS) +- +-// end catch_windows_h_proxy.h +-#if defined( CATCH_CONFIG_WINDOWS_SEH ) ++#include <cassert> + + namespace Catch { + +- struct FatalConditionHandler { +- +- static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); ++ // Wrapper for platform-specific fatal error (signals/SEH) handlers ++ // ++ // Tries to be cooperative with other handlers, and not step over ++ // other handlers. This means that unknown structured exceptions ++ // are passed on, previous signal handlers are called, and so on. ++ // ++ // Can only be instantiated once, and assumes that once a signal ++ // is caught, the binary will end up terminating. Thus, there ++ class FatalConditionHandler { ++ bool m_started = false; ++ ++ // Install/disengage implementation for specific platform. ++ // Should be if-defed to work on current platform, can assume ++ // engage-disengage 1:1 pairing. ++ void engage_platform(); ++ void disengage_platform(); ++ public: ++ // Should also have platform-specific implementations as needed + FatalConditionHandler(); +- static void reset(); + ~FatalConditionHandler(); + +- private: +- static bool isSet; +- static ULONG guaranteeSize; +- static PVOID exceptionHandlerHandle; +- }; +- +-} // namespace Catch +- +-#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) +- +-#include <signal.h> +- +-namespace Catch { +- +- struct FatalConditionHandler { +- +- static bool isSet; +- static struct sigaction oldSigActions[]; +- static stack_t oldSigStack; +- static char altStackMem[]; +- +- static void handleSignal( int sig ); ++ void engage() { ++ assert(!m_started && "Handler cannot be installed twice."); ++ m_started = true; ++ engage_platform(); ++ } + +- FatalConditionHandler(); +- ~FatalConditionHandler(); +- static void reset(); ++ void disengage() { ++ assert(m_started && "Handler cannot be uninstalled without being installed first"); ++ m_started = false; ++ disengage_platform(); ++ } + }; + +-} // namespace Catch +- +-#else +- +-namespace Catch { +- struct FatalConditionHandler { +- void reset(); ++ //! Simple RAII guard for (dis)engaging the FatalConditionHandler ++ class FatalConditionHandlerGuard { ++ FatalConditionHandler* m_handler; ++ public: ++ FatalConditionHandlerGuard(FatalConditionHandler* handler): ++ m_handler(handler) { ++ m_handler->engage(); ++ } ++ ~FatalConditionHandlerGuard() { ++ m_handler->disengage(); ++ } + }; +-} + +-#endif ++} // end namespace Catch + + // end catch_fatal_condition.h + #include <string> +@@ -8190,6 +8162,7 @@ namespace Catch { + std::vector<SectionEndInfo> m_unfinishedSections; + std::vector<ITracker*> m_activeSections; + TrackerContext m_trackerContext; ++ FatalConditionHandler m_fatalConditionhandler; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; +@@ -10062,6 +10035,36 @@ namespace Catch { + } + + // end catch_errno_guard.h ++// start catch_windows_h_proxy.h ++ ++ ++#if defined(CATCH_PLATFORM_WINDOWS) ++ ++#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) ++# define CATCH_DEFINED_NOMINMAX ++# define NOMINMAX ++#endif ++#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) ++# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN ++# define WIN32_LEAN_AND_MEAN ++#endif ++ ++#ifdef __AFXDLL ++#include <AfxWin.h> ++#else ++#include <windows.h> ++#endif ++ ++#ifdef CATCH_DEFINED_NOMINMAX ++# undef NOMINMAX ++#endif ++#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN ++# undef WIN32_LEAN_AND_MEAN ++#endif ++ ++#endif // defined(CATCH_PLATFORM_WINDOWS) ++ ++// end catch_windows_h_proxy.h + #include <sstream> + + namespace Catch { +@@ -10578,7 +10581,7 @@ namespace Catch { + // Extracts the actual name part of an enum instance + // In other words, it returns the Blue part of Bikeshed::Colour::Blue + StringRef extractInstanceName(StringRef enumInstance) { +- // Find last occurence of ":" ++ // Find last occurrence of ":" + size_t name_start = enumInstance.size(); + while (name_start > 0 && enumInstance[name_start - 1] != ':') { + --name_start; +@@ -10740,25 +10743,47 @@ namespace Catch { + // end catch_exception_translator_registry.cpp + // start catch_fatal_condition.cpp + +-#if defined(__GNUC__) +-# pragma GCC diagnostic push +-# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +-#endif ++#include <algorithm> ++ ++#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) ++ ++namespace Catch { ++ ++ // If neither SEH nor signal handling is required, the handler impls ++ // do not have to do anything, and can be empty. ++ void FatalConditionHandler::engage_platform() {} ++ void FatalConditionHandler::disengage_platform() {} ++ FatalConditionHandler::FatalConditionHandler() = default; ++ FatalConditionHandler::~FatalConditionHandler() = default; ++ ++} // end namespace Catch ++ ++#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS ++ ++#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) ++#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" ++#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS + + #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) + + namespace { +- // Report the error condition ++ //! Signals fatal error message to the run context + void reportFatal( char const * const message ) { + Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); + } +-} + +-#endif // signals/SEH handling ++ //! Minimal size Catch2 needs for its own fatal error handling. ++ //! Picked anecdotally, so it might not be sufficient on all ++ //! platforms, and for all configurations. ++ constexpr std::size_t minStackSizeForErrors = 32 * 1024; ++} // end unnamed namespace ++ ++#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS + + #if defined( CATCH_CONFIG_WINDOWS_SEH ) + + namespace Catch { ++ + struct SignalDefs { DWORD id; const char* name; }; + + // There is no 1-1 mapping between signals and windows exceptions. +@@ -10771,7 +10796,7 @@ namespace Catch { + { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, + }; + +- LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { ++ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (auto const& def : signalDefs) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { + reportFatal(def.name); +@@ -10782,38 +10807,50 @@ namespace Catch { + return EXCEPTION_CONTINUE_SEARCH; + } + ++ // Since we do not support multiple instantiations, we put these ++ // into global variables and rely on cleaning them up in outlined ++ // constructors/destructors ++ static PVOID exceptionHandlerHandle = nullptr; ++ ++ // For MSVC, we reserve part of the stack memory for handling ++ // memory overflow structured exception. + FatalConditionHandler::FatalConditionHandler() { +- isSet = true; +- // 32k seems enough for Catch to handle stack overflow, +- // but the value was found experimentally, so there is no strong guarantee +- guaranteeSize = 32 * 1024; +- exceptionHandlerHandle = nullptr; ++ ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors); ++ if (!SetThreadStackGuarantee(&guaranteeSize)) { ++ // We do not want to fully error out, because needing ++ // the stack reserve should be rare enough anyway. ++ Catch::cerr() ++ << "Failed to reserve piece of stack." ++ << " Stack overflows will not be reported successfully."; ++ } ++ } ++ ++ // We do not attempt to unset the stack guarantee, because ++ // Windows does not support lowering the stack size guarantee. ++ FatalConditionHandler::~FatalConditionHandler() = default; ++ ++ void FatalConditionHandler::engage_platform() { + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); +- // Pass in guarantee size to be filled +- SetThreadStackGuarantee(&guaranteeSize); ++ if (!exceptionHandlerHandle) { ++ CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); ++ } + } + +- void FatalConditionHandler::reset() { +- if (isSet) { +- RemoveVectoredExceptionHandler(exceptionHandlerHandle); +- SetThreadStackGuarantee(&guaranteeSize); +- exceptionHandlerHandle = nullptr; +- isSet = false; ++ void FatalConditionHandler::disengage_platform() { ++ if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { ++ CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); + } ++ exceptionHandlerHandle = nullptr; + } + +- FatalConditionHandler::~FatalConditionHandler() { +- reset(); +- } ++} // end namespace Catch + +-bool FatalConditionHandler::isSet = false; +-ULONG FatalConditionHandler::guaranteeSize = 0; +-PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; ++#endif // CATCH_CONFIG_WINDOWS_SEH + +-} // namespace Catch ++#if defined( CATCH_CONFIG_POSIX_SIGNALS ) + +-#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) ++#include <signal.h> + + namespace Catch { + +@@ -10822,10 +10859,6 @@ namespace Catch { + const char* name; + }; + +- // 32kb for the alternate stack seems to be sufficient. However, this value +- // is experimentally determined, so that's not guaranteed. +- static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; +- + static SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, +@@ -10835,7 +10868,32 @@ namespace Catch { + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + +- void FatalConditionHandler::handleSignal( int sig ) { ++// Older GCCs trigger -Wmissing-field-initializers for T foo = {} ++// which is zero initialization, but not explicit. We want to avoid ++// that. ++#if defined(__GNUC__) ++# pragma GCC diagnostic push ++# pragma GCC diagnostic ignored "-Wmissing-field-initializers" ++#endif ++ ++ static char* altStackMem = nullptr; ++ static std::size_t altStackSize = 0; ++ static stack_t oldSigStack{}; ++ static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; ++ ++ static void restorePreviousSignalHandlers() { ++ // We set signal handlers back to the previous ones. Hopefully ++ // nobody overwrote them in the meantime, and doesn't expect ++ // their signal handlers to live past ours given that they ++ // installed them after ours.. ++ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { ++ sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); ++ } ++ // Return the old stack ++ sigaltstack(&oldSigStack, nullptr); ++ } ++ ++ static void handleSignal( int sig ) { + char const * name = "<unknown signal>"; + for (auto const& def : signalDefs) { + if (sig == def.id) { +@@ -10843,16 +10901,33 @@ namespace Catch { + break; + } + } +- reset(); +- reportFatal(name); ++ // We need to restore previous signal handlers and let them do ++ // their thing, so that the users can have the debugger break ++ // when a signal is raised, and so on. ++ restorePreviousSignalHandlers(); ++ reportFatal( name ); + raise( sig ); + } + + FatalConditionHandler::FatalConditionHandler() { +- isSet = true; ++ assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists"); ++ if (altStackSize == 0) { ++ altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors); ++ } ++ altStackMem = new char[altStackSize](); ++ } ++ ++ FatalConditionHandler::~FatalConditionHandler() { ++ delete[] altStackMem; ++ // We signal that another instance can be constructed by zeroing ++ // out the pointer. ++ altStackMem = nullptr; ++ } ++ ++ void FatalConditionHandler::engage_platform() { + stack_t sigStack; + sigStack.ss_sp = altStackMem; +- sigStack.ss_size = sigStackSize; ++ sigStack.ss_size = altStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { }; +@@ -10864,40 +10939,17 @@ namespace Catch { + } + } + +- FatalConditionHandler::~FatalConditionHandler() { +- reset(); +- } ++#if defined(__GNUC__) ++# pragma GCC diagnostic pop ++#endif + +- void FatalConditionHandler::reset() { +- if( isSet ) { +- // Set signals back to previous values -- hopefully nobody overwrote them in the meantime +- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { +- sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); +- } +- // Return the old stack +- sigaltstack(&oldSigStack, nullptr); +- isSet = false; +- } ++ void FatalConditionHandler::disengage_platform() { ++ restorePreviousSignalHandlers(); + } + +- bool FatalConditionHandler::isSet = false; +- struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; +- stack_t FatalConditionHandler::oldSigStack = {}; +- char FatalConditionHandler::altStackMem[sigStackSize] = {}; +- +-} // namespace Catch +- +-#else +- +-namespace Catch { +- void FatalConditionHandler::reset() {} +-} +- +-#endif // signals/SEH handling ++} // end namespace Catch + +-#if defined(__GNUC__) +-# pragma GCC diagnostic pop +-#endif ++#endif // CATCH_CONFIG_POSIX_SIGNALS + // end catch_fatal_condition.cpp + // start catch_generators.cpp + +@@ -11452,7 +11504,8 @@ namespace { + return lhs == rhs; + } + +- auto ulpDiff = std::abs(lc - rc); ++ // static cast as a workaround for IBM XLC ++ auto ulpDiff = std::abs(static_cast<FP>(lc - rc)); + return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff; + } + +@@ -11626,7 +11679,6 @@ Floating::WithinRelMatcher WithinRel(float target) { + + } // namespace Matchers + } // namespace Catch +- + // end catch_matchers_floating.cpp + // start catch_matchers_generic.cpp + +@@ -12042,7 +12094,7 @@ namespace Catch { + if (tmpnam_s(m_buffer)) { + CATCH_RUNTIME_ERROR("Could not get a temp filename"); + } +- if (fopen_s(&m_file, m_buffer, "w")) { ++ if (fopen_s(&m_file, m_buffer, "w+")) { + char buffer[100]; + if (strerror_s(buffer, errno)) { + CATCH_RUNTIME_ERROR("Could not translate errno to a string"); +@@ -12580,13 +12632,53 @@ namespace Catch { + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by `SECTION`s. +- const bool should_wait_for_child = +- !m_children.empty() && +- std::find_if( m_children.begin(), +- m_children.end(), +- []( TestCaseTracking::ITrackerPtr tracker ) { +- return tracker->hasStarted(); +- } ) == m_children.end(); ++ const bool should_wait_for_child = [&]() { ++ // No children -> nobody to wait for ++ if ( m_children.empty() ) { ++ return false; ++ } ++ // If at least one child started executing, don't wait ++ if ( std::find_if( ++ m_children.begin(), ++ m_children.end(), ++ []( TestCaseTracking::ITrackerPtr tracker ) { ++ return tracker->hasStarted(); ++ } ) != m_children.end() ) { ++ return false; ++ } ++ ++ // No children have started. We need to check if they _can_ ++ // start, and thus we should wait for them, or they cannot ++ // start (due to filters), and we shouldn't wait for them ++ auto* parent = m_parent; ++ // This is safe: there is always at least one section ++ // tracker in a test case tracking tree ++ while ( !parent->isSectionTracker() ) { ++ parent = &( parent->parent() ); ++ } ++ assert( parent && ++ "Missing root (test case) level section" ); ++ ++ auto const& parentSection = ++ static_cast<SectionTracker&>( *parent ); ++ auto const& filters = parentSection.getFilters(); ++ // No filters -> no restrictions on running sections ++ if ( filters.empty() ) { ++ return true; ++ } ++ ++ for ( auto const& child : m_children ) { ++ if ( child->isSectionTracker() && ++ std::find( filters.begin(), ++ filters.end(), ++ static_cast<SectionTracker&>( *child ) ++ .trimmedName() ) != ++ filters.end() ) { ++ return true; ++ } ++ } ++ return false; ++ }(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current +@@ -12920,9 +13012,8 @@ namespace Catch { + } + + void RunContext::invokeActiveTestCase() { +- FatalConditionHandler fatalConditionHandler; // Handle signals ++ FatalConditionHandlerGuard _(&m_fatalConditionhandler); + m_activeTestCase->invoke(); +- fatalConditionHandler.reset(); + } + + void RunContext::handleUnfinishedSections() { +@@ -14091,24 +14182,28 @@ namespace Catch { + + namespace { + struct TestHasher { +- explicit TestHasher(Catch::SimplePcg32& rng) { +- basis = rng(); +- basis <<= 32; +- basis |= rng(); +- } ++ using hash_t = uint64_t; + +- uint64_t basis; ++ explicit TestHasher( hash_t hashSuffix ): ++ m_hashSuffix{ hashSuffix } {} + +- uint64_t operator()(TestCase const& t) const { +- // Modified FNV-1a hash +- static constexpr uint64_t prime = 1099511628211; +- uint64_t hash = basis; +- for (const char c : t.name) { ++ uint32_t operator()( TestCase const& t ) const { ++ // FNV-1a hash with multiplication fold. ++ const hash_t prime = 1099511628211u; ++ hash_t hash = 14695981039346656037u; ++ for ( const char c : t.name ) { + hash ^= c; + hash *= prime; + } +- return hash; ++ hash ^= m_hashSuffix; ++ hash *= prime; ++ const uint32_t low{ static_cast<uint32_t>( hash ) }; ++ const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) }; ++ return low * high; + } ++ ++ private: ++ hash_t m_hashSuffix; + }; + } // end unnamed namespace + +@@ -14126,9 +14221,9 @@ namespace Catch { + + case RunTests::InRandomOrder: { + seedRng( config ); +- TestHasher h( rng() ); ++ TestHasher h{ config.rngSeed() }; + +- using hashedTest = std::pair<uint64_t, TestCase const*>; ++ using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>; + std::vector<hashedTest> indexed_tests; + indexed_tests.reserve( unsortedTestCases.size() ); + +@@ -14458,6 +14553,14 @@ namespace TestCaseTracking { + m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); + } + ++ std::vector<std::string> const& SectionTracker::getFilters() const { ++ return m_filters; ++ } ++ ++ std::string const& SectionTracker::trimmedName() const { ++ return m_trimmed_name; ++ } ++ + } // namespace TestCaseTracking + + using TestCaseTracking::ITracker; +@@ -15192,6 +15295,41 @@ namespace Catch { + // end catch_totals.cpp + // start catch_uncaught_exceptions.cpp + ++// start catch_config_uncaught_exceptions.hpp ++ ++// Copyright Catch2 Authors ++// Distributed under the Boost Software License, Version 1.0. ++// (See accompanying file LICENSE_1_0.txt or copy at ++// https://www.boost.org/LICENSE_1_0.txt) ++ ++// SPDX-License-Identifier: BSL-1.0 ++ ++#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP ++#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP ++ ++#if defined(_MSC_VER) ++# if _MSC_VER >= 1900 // Visual Studio 2015 or newer ++# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS ++# endif ++#endif ++ ++#include <exception> ++ ++#if defined(__cpp_lib_uncaught_exceptions) \ ++ && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) ++ ++# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS ++#endif // __cpp_lib_uncaught_exceptions ++ ++#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 ++ ++#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP ++// end catch_config_uncaught_exceptions.hpp + #include <exception> + + namespace Catch { +@@ -15238,7 +15376,7 @@ namespace Catch { + } + + Version const& libraryVersion() { +- static Version version( 2, 13, 0, "", 0 ); ++ static Version version( 2, 13, 6, "", 0 ); + return version; + } + |