Enable usage of gsl::narrow with exceptions disabled (#640)

* Enable usage of gsl::narrow with exceptions disabled

This solution uses the approach of boost::asio to enabling usage of the
library in environments where exception usage is either prohibited
or not feasible (due to code size constraints). A function template
gsl::throw_exception has been added, which in a normal environment just
throws the exception. However, when GSL_TERMINATE_ON_CONTRACT_VIOLATION
is defined the function is only declared by gsl and the definition of
this function template must be supplied by the library's user.

Closes: #468

Signed-off-by: Damian Jarek <damian.jarek93@gmail.com>

Addition:
- understand STL no exception macro
- use function static variable to set termination handler in kernel mode
- add compile-only tests for no-exception mode

* added termination tests and fixed bugs

* disabled warning C4577 for msvc 2015
This commit is contained in:
Anna Gringauze
2018-03-15 16:00:08 -07:00
committed by GitHub
parent c6bf25a5f6
commit d846fe50a3
5 changed files with 223 additions and 6 deletions
+56 -4
View File
@@ -20,6 +20,14 @@
#include <exception>
#include <stdexcept> // for logic_error
//
// Temporary until MSVC STL supports no-exceptions mode.
// Currently terminate is a no-op in this mode, so we add termination behavior back
//
#if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
#endif
//
// There are three configuration options for this GSL implementation's behavior
// when pre/post conditions on the GSL types are violated:
@@ -68,18 +76,62 @@ struct fail_fast : public std::logic_error
{
explicit fail_fast(char const* const message) : std::logic_error(message) {}
};
}
namespace details
{
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
typedef void (*terminate_handler)();
inline gsl::details::terminate_handler& get_terminate_handler() noexcept
{
static terminate_handler handler = &abort;
return handler;
}
#endif
[[noreturn]] inline void terminate() noexcept
{
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
(*gsl::details::get_terminate_handler())();
#else
std::terminate();
#endif
}
#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
template <typename Exception>
[[noreturn]] void throw_exception(Exception&&)
{
gsl::details::terminate();
}
#else
template <typename Exception>
[[noreturn]] void throw_exception(Exception&& exception)
{
throw exception;
}
#endif
} // namespace details
} // namespace gsl
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) \
: throw gsl::fail_fast("GSL: " type " failure at " __FILE__ \
": " GSL_STRINGIFY(__LINE__)))
: gsl::details::throw_exception(gsl::fail_fast( \
"GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__))))
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
#define GSL_CONTRACT_CHECK(type, cond) (GSL_LIKELY(cond) ? static_cast<void>(0) : std::terminate())
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
+2 -2
View File
@@ -110,9 +110,9 @@ template <class T, class U>
T narrow(U u)
{
T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u) throw narrowing_error();
if (static_cast<U>(t) != u) gsl::details::throw_exception(narrowing_error());
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
throw narrowing_error();
gsl::details::throw_exception(narrowing_error());
return t;
}