mirror of
https://github.com/catchorg/Catch2.git
synced 2024-12-23 03:43:28 +01:00
Add support for -fno-exceptions (or equivalent)
This means * Adding new configuration toggle `CATCH_CONFIG_DISABLE_EXCEPTIONS` and a best-guess configuration auto-checking for it. * Adding new set of internal macros, `CATCH_TRY`, `CATCH_CATCH_ALL` and `CATCH_CATCH_ANON` that can be used in place of regular `try`, `catch(...)` and `catch(T const&)` respectively, while disappearing when `CATCH_CONFIG_DISABLE_EXCEPTIONS` is enabled. * Replacing all uses of `throw` with calls to `Catch::throw_exception` customization point. * Providing a default implementation for the above customization point when `CATCH_CONFIG_DISABLE_EXCEPTIONS` is set. * Letting users override this implementation with their own. * Some minor changes and ifdefs all around to support the above
This commit is contained in:
parent
86da2846af
commit
8b01883854
@ -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;
|
||||
|
@ -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*
|
||||
|
@ -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
|
||||
|
||||
|
19
include/internal/catch_enforce.cpp
Normal file
19
include/internal/catch_enforce.cpp
Normal file
@ -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;
|
@ -8,19 +8,35 @@
|
||||
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
#include "catch_compiler_capabilities.h"
|
||||
#include "catch_stream.h"
|
||||
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Catch {
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
template <typename Ex>
|
||||
[[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
|
||||
|
@ -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<const IExceptionTranslator>( 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());
|
||||
|
@ -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 ) {
|
||||
|
@ -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<int>(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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user