diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index ced52312..77c3f1d4 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -81,8 +81,13 @@ namespace Catch { // (To go back to the test and change execution, jump over the throw, next) CATCH_BREAK_INTO_DEBUGGER(); } - if( m_reaction.shouldThrow ) + if (m_reaction.shouldThrow) { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) throw Catch::TestFailureException(); +#else + CATCH_ERROR( "Test failure requires aborting test!" ); +#endif + } } void AssertionHandler::setCompleted() { m_completed = true; diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 258cee61..a9c2e0d7 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -21,7 +21,7 @@ #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" #endif -#if defined(CATCH_CONFIG_FAST_COMPILE) +#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h index 2276dd36..0c20e6ea 100644 --- a/include/internal/catch_compiler_capabilities.h +++ b/include/internal/catch_compiler_capabilities.h @@ -14,6 +14,7 @@ // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too @@ -131,7 +132,12 @@ #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif +//////////////////////////////////////////////////////////////////////////////// // DJGPP #ifdef __DJGPP__ # define CATCH_INTERNAL_CONFIG_NO_WCHAR @@ -179,6 +185,10 @@ # define CATCH_CONFIG_NEW_CAPTURE #endif +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS @@ -192,6 +202,16 @@ # define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS #endif +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + #endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED diff --git a/include/internal/catch_enforce.cpp b/include/internal/catch_enforce.cpp new file mode 100644 index 00000000..f4db1c15 --- /dev/null +++ b/include/internal/catch_enforce.cpp @@ -0,0 +1,19 @@ +/* + * Created by Martin on 03/09/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) + */ + +#include "catch_enforce.h" + +namespace Catch { +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) + [[noreturn]] + void throw_exception(std::exception const& e) { + Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" + << "The message was: " << e.what() << '\n'; + std::terminate(); + } +#endif +} // namespace Catch; diff --git a/include/internal/catch_enforce.h b/include/internal/catch_enforce.h index 58cbe134..00694023 100644 --- a/include/internal/catch_enforce.h +++ b/include/internal/catch_enforce.h @@ -8,19 +8,35 @@ #define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED #include "catch_common.h" +#include "catch_compiler_capabilities.h" #include "catch_stream.h" + #include +namespace Catch { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + template + [[noreturn]] + void throw_exception(Ex const& e) { + throw e; + } +#else // ^^ Exceptions are enabled // Exceptions are disabled vv + [[noreturn]] + void throw_exception(std::exception const& e); +#endif +} // namespace Catch; + #define CATCH_PREPARE_EXCEPTION( type, msg ) \ type( ( Catch::ReusableStringStream() << msg ).str() ) #define CATCH_INTERNAL_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg)) #define CATCH_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg )) #define CATCH_RUNTIME_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ) + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg )) #define CATCH_ENFORCE( condition, msg ) \ do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) + #endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED diff --git a/include/internal/catch_exception_translator_registry.cpp b/include/internal/catch_exception_translator_registry.cpp index 78b9c573..b836cd9c 100644 --- a/include/internal/catch_exception_translator_registry.cpp +++ b/include/internal/catch_exception_translator_registry.cpp @@ -6,8 +6,10 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ -#include "catch_assertionhandler.h" #include "catch_exception_translator_registry.h" +#include "catch_assertionhandler.h" +#include "catch_compiler_capabilities.h" +#include "catch_enforce.h" #ifdef __OBJC__ #import "Foundation/Foundation.h" @@ -22,6 +24,7 @@ namespace Catch { m_translators.push_back( std::unique_ptr( translator ) ); } +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) std::string ExceptionTranslatorRegistry::translateActiveException() const { try { #ifdef __OBJC__ @@ -64,6 +67,13 @@ namespace Catch { } } +#else // ^^ Exceptions are enabled // Exceptions are disabled vv + std::string ExceptionTranslatorRegistry::translateActiveException() const { + CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); + } +#endif + + std::string ExceptionTranslatorRegistry::tryTranslators() const { if( m_translators.empty() ) std::rethrow_exception(std::current_exception()); diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index 2739284c..7e4b689e 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -1,4 +1,5 @@ #include "catch_run_context.h" +#include "catch_compiler_capabilities.h" #include "catch_context.h" #include "catch_enforce.h" #include "catch_random_number_generator.h" @@ -327,7 +328,7 @@ namespace Catch { seedRng(*m_config); Timer timer; - try { + CATCH_TRY { if (m_reporter->getPreferences().shouldRedirectStdOut) { #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) RedirectedStdOut redirectedStdOut; @@ -347,9 +348,9 @@ namespace Catch { invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); - } catch (TestFailureException&) { + } CATCH_CATCH_ANON (TestFailureException&) { // This just means the test was aborted due to failure - } catch (...) { + } CATCH_CATCH_ALL { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. if( m_shouldReportUnexpected ) { diff --git a/include/internal/catch_session.cpp b/include/internal/catch_session.cpp index 2c5fe08e..5d028ed2 100644 --- a/include/internal/catch_session.cpp +++ b/include/internal/catch_session.cpp @@ -119,10 +119,12 @@ namespace Catch { Session::Session() { static bool alreadyInstantiated = false; if( alreadyInstantiated ) { - try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } - catch(...) { getMutableRegistryHub().registerStartupException(); } + CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } + CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } } + // There cannot be exceptions at startup in no-exception mode. +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); if ( !exceptions.empty() ) { m_startupExceptions = true; @@ -137,6 +139,7 @@ namespace Catch { } } } +#endif alreadyInstantiated = true; m_cli = makeCommandLineParser( m_configData ); @@ -251,11 +254,11 @@ namespace Catch { if( m_startupExceptions ) return 1; - if( m_configData.showHelp || m_configData.libIdentify ) + if (m_configData.showHelp || m_configData.libIdentify) { return 0; + } - try - { + CATCH_TRY { config(); // Force config to be constructed seedRng( *m_config ); @@ -273,10 +276,12 @@ namespace Catch { // of 256 tests has failed return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); } +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; return MaxExitCode; } +#endif } } // end namespace Catch diff --git a/include/internal/catch_startup_exception_registry.cpp b/include/internal/catch_startup_exception_registry.cpp index d58d18a5..3c5bd22f 100644 --- a/include/internal/catch_startup_exception_registry.cpp +++ b/include/internal/catch_startup_exception_registry.cpp @@ -7,13 +7,13 @@ */ #include "catch_startup_exception_registry.h" +#include "catch_compiler_capabilities.h" namespace Catch { - void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { - try { +void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { + CATCH_TRY { m_exceptions.push_back(exception); - } - catch(...) { + } CATCH_CATCH_ALL { // If we run out of memory during start-up there's really not a lot more we can do about it std::terminate(); } diff --git a/include/internal/catch_tag_alias_autoregistrar.cpp b/include/internal/catch_tag_alias_autoregistrar.cpp index 35ed059f..6a292edf 100644 --- a/include/internal/catch_tag_alias_autoregistrar.cpp +++ b/include/internal/catch_tag_alias_autoregistrar.cpp @@ -1,12 +1,13 @@ #include "catch_tag_alias_autoregistrar.h" +#include "catch_compiler_capabilities.h" #include "catch_interfaces_registry_hub.h" namespace Catch { - + RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { - try { + CATCH_TRY { getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); - } catch (...) { + } CATCH_CATCH_ALL { // Do not throw when constructing global objects, instead register the exception to be processed later getMutableRegistryHub().registerStartupException(); } diff --git a/include/internal/catch_test_registry.cpp b/include/internal/catch_test_registry.cpp index ac83f333..248bee4c 100644 --- a/include/internal/catch_test_registry.cpp +++ b/include/internal/catch_test_registry.cpp @@ -6,6 +6,7 @@ */ #include "catch_test_registry.h" +#include "catch_compiler_capabilities.h" #include "catch_test_case_registry_impl.h" #include "catch_interfaces_registry_hub.h" @@ -18,7 +19,7 @@ namespace Catch { NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { - try { + CATCH_TRY { getMutableRegistryHub() .registerTest( makeTestCase( @@ -26,7 +27,7 @@ namespace Catch { extractClassName( classOrMethod ), nameAndTags, lineInfo)); - } catch (...) { + } CATCH_CATCH_ALL { // Do not throw when constructing global objects, instead register the exception to be processed later getMutableRegistryHub().registerStartupException(); } diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index f83d2bfb..a2ddb23b 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -173,6 +173,7 @@ set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_debug_console.cpp ${HEADER_DIR}/internal/catch_debugger.cpp ${HEADER_DIR}/internal/catch_decomposer.cpp + ${HEADER_DIR}/internal/catch_enforce.cpp ${HEADER_DIR}/internal/catch_errno_guard.cpp ${HEADER_DIR}/internal/catch_exception_translator_registry.cpp ${HEADER_DIR}/internal/catch_fatal_condition.cpp