Skip to content

Commit 8697e33

Browse files
jmplanes02josemahsutter
authored
fix compilation errors with exceptions disabled (#1355)
* fix compilation errors with exceptions disabled * Add include for cerrno And add an assertion for `end` being not null, which `strtol` guarantees but it's good to check it anyway - and that needs moving contracts earlier in the file --------- Co-authored-by: josema <[email protected]> Co-authored-by: Herb Sutter <[email protected]>
1 parent 3b4fa23 commit 8697e33

File tree

1 file changed

+170
-136
lines changed

1 file changed

+170
-136
lines changed

include/cpp2util.h

Lines changed: 170 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
// to the 'include std' path
5959
#if defined(CPP2_IMPORT_STD) && defined(__cpp_lib_modules)
6060
import std.compat;
61+
#include <cerrno>
6162
// If 'include std' was requested, include all standard headers.
6263
// This list tracks the current draft standard, so as of this
6364
// writing includes draft C++26 headers like <debugging>.
@@ -254,6 +255,7 @@
254255
#endif
255256
#include <algorithm>
256257
#include <any>
258+
#include <cerrno>
257259
#include <compare>
258260
#include <concepts>
259261
#include <cstddef>
@@ -451,6 +453,144 @@ using _schar = signed char; // normally use i8 instead
451453
using _uchar = unsigned char; // normally use u8 instead
452454

453455

456+
//-----------------------------------------------------------------------
457+
//
458+
// An implementation of GSL's narrow_cast with a clearly 'unchecked' name
459+
//
460+
//-----------------------------------------------------------------------
461+
//
462+
namespace impl {
463+
464+
template< typename To, typename From >
465+
constexpr auto is_narrowing_v =
466+
// [dcl.init.list] 7.1
467+
(std::is_floating_point_v<From> && std::is_integral_v<To>) ||
468+
// [dcl.init.list] 7.2
469+
(std::is_floating_point_v<From> && std::is_floating_point_v<To> && sizeof(From) > sizeof(To)) || // NOLINT(misc-redundant-expression)
470+
// [dcl.init.list] 7.3
471+
(std::is_integral_v<From> && std::is_floating_point_v<To>) ||
472+
(std::is_enum_v<From> && std::is_floating_point_v<To>) ||
473+
// [dcl.init.list] 7.4
474+
(std::is_integral_v<From> && std::is_integral_v<To> && sizeof(From) > sizeof(To)) || // NOLINT(misc-redundant-expression)
475+
(std::is_enum_v<From> && std::is_integral_v<To> && sizeof(From) > sizeof(To)) ||
476+
// [dcl.init.list] 7.5
477+
(std::is_pointer_v<From> && std::is_same_v<To, bool>)
478+
;
479+
480+
}
481+
482+
483+
template <typename C, typename X>
484+
constexpr auto unchecked_narrow( X x ) noexcept
485+
-> decltype(auto)
486+
requires (
487+
impl::is_narrowing_v<C, X>
488+
|| (
489+
std::is_arithmetic_v<C>
490+
&& std::is_arithmetic_v<X>
491+
)
492+
)
493+
{
494+
return static_cast<C>(x);
495+
}
496+
497+
498+
template <typename C, typename X>
499+
constexpr auto unchecked_cast( X&& x ) noexcept
500+
-> decltype(auto)
501+
{
502+
return static_cast<C>(CPP2_FORWARD(x));
503+
}
504+
505+
506+
//-----------------------------------------------------------------------
507+
//
508+
// contract_group
509+
//
510+
//-----------------------------------------------------------------------
511+
//
512+
513+
#ifdef CPP2_USE_SOURCE_LOCATION
514+
#define CPP2_SOURCE_LOCATION_PARAM , [[maybe_unused]] std::source_location where
515+
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT , [[maybe_unused]] std::source_location where = std::source_location::current()
516+
#define CPP2_SOURCE_LOCATION_PARAM_SOLO [[maybe_unused]] std::source_location where
517+
#define CPP2_SOURCE_LOCATION_ARG , where
518+
#define CPP2_SOURCE_LOCATION_VALUE (cpp2::to_string(where.file_name()) + "(" + cpp2::to_string(where.line()) + ") " + where.function_name())
519+
#else
520+
#define CPP2_SOURCE_LOCATION_PARAM
521+
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT
522+
#define CPP2_SOURCE_LOCATION_PARAM_SOLO
523+
#define CPP2_SOURCE_LOCATION_ARG
524+
#define CPP2_SOURCE_LOCATION_VALUE std::string("")
525+
#endif
526+
527+
// For C++23: make this std::string_view and drop the macro
528+
// Before C++23 std::string_view was not guaranteed to be trivially copyable,
529+
// and so in<T> will pass it by const& and really it should be by value
530+
#define CPP2_MESSAGE_PARAM char const*
531+
#define CPP2_CONTRACT_MSG cpp2::message_to_cstr_adapter
532+
533+
inline auto message_to_cstr_adapter( CPP2_MESSAGE_PARAM msg ) -> CPP2_MESSAGE_PARAM { return msg ? msg : ""; }
534+
inline auto message_to_cstr_adapter( std::string const& msg ) -> CPP2_MESSAGE_PARAM { return msg.c_str(); }
535+
536+
class contract_group {
537+
public:
538+
using handler = void (*)(CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM);
539+
540+
constexpr contract_group (handler h = {}) : reporter{h} { }
541+
constexpr auto set_handler(handler h = {}) { reporter = h; }
542+
constexpr auto is_active () const -> bool { return reporter != handler{}; }
543+
544+
constexpr auto enforce(bool b, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
545+
-> void { if (!b) report_violation(msg CPP2_SOURCE_LOCATION_ARG); }
546+
constexpr auto report_violation(CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
547+
-> void { if (reporter) reporter(msg CPP2_SOURCE_LOCATION_ARG); }
548+
private:
549+
handler reporter;
550+
};
551+
552+
[[noreturn]] inline auto report_and_terminate(std::string_view group, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) noexcept -> void {
553+
std::cerr
554+
#ifdef CPP2_USE_SOURCE_LOCATION
555+
<< where.file_name() << "("
556+
<< where.line() << ") "
557+
<< where.function_name() << ": "
558+
#endif
559+
<< group << " violation";
560+
if (msg && msg[0] != '\0') {
561+
std::cerr << ": " << msg;
562+
}
563+
std::cerr << "\n";
564+
std::terminate();
565+
}
566+
567+
auto inline cpp2_default = contract_group(
568+
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
569+
report_and_terminate("Contract", msg CPP2_SOURCE_LOCATION_ARG);
570+
}
571+
);
572+
auto inline bounds_safety = contract_group(
573+
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
574+
report_and_terminate("Bounds safety", msg CPP2_SOURCE_LOCATION_ARG);
575+
}
576+
);
577+
auto inline null_safety = contract_group(
578+
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
579+
report_and_terminate("Null safety", msg CPP2_SOURCE_LOCATION_ARG);
580+
}
581+
);
582+
auto inline type_safety = contract_group(
583+
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
584+
report_and_terminate("Type safety", msg CPP2_SOURCE_LOCATION_ARG);
585+
}
586+
);
587+
auto inline testing = contract_group(
588+
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
589+
report_and_terminate("Testing", msg CPP2_SOURCE_LOCATION_ARG);
590+
}
591+
);
592+
593+
454594
//-----------------------------------------------------------------------
455595
//
456596
// String utilities
@@ -557,6 +697,7 @@ constexpr bool is_escaped(std::string_view s) {
557697
}
558698

559699
inline bool string_to_int(std::string const& s, int& v, int base = 10) {
700+
#ifdef CPP2_NO_EXCEPTIONS
560701
try {
561702
v = stoi(s, nullptr, base);
562703
return true;
@@ -569,6 +710,32 @@ inline bool string_to_int(std::string const& s, int& v, int base = 10) {
569710
{
570711
return false;
571712
}
713+
#else
714+
errno = 0;
715+
char* end = nullptr;
716+
717+
auto const num = std::strtol(s.c_str(), &end, base);
718+
719+
cpp2_default.enforce(end != nullptr);
720+
if (
721+
end == s.c_str()
722+
|| *end != '\0'
723+
)
724+
{
725+
return false; // invalid argument
726+
}
727+
if (
728+
errno == ERANGE
729+
|| num < std::numeric_limits<int>::min()
730+
|| num > std::numeric_limits<int>::max()
731+
)
732+
{
733+
return false; // out of range
734+
}
735+
736+
v = unchecked_narrow<int>(num);
737+
return true;
738+
#endif
572739
}
573740

574741
template<int Base = 10>
@@ -922,94 +1089,6 @@ template<class T, class U>
9221089
}
9231090

9241091

925-
//-----------------------------------------------------------------------
926-
//
927-
// contract_group
928-
//
929-
//-----------------------------------------------------------------------
930-
//
931-
932-
#ifdef CPP2_USE_SOURCE_LOCATION
933-
#define CPP2_SOURCE_LOCATION_PARAM , [[maybe_unused]] std::source_location where
934-
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT , [[maybe_unused]] std::source_location where = std::source_location::current()
935-
#define CPP2_SOURCE_LOCATION_PARAM_SOLO [[maybe_unused]] std::source_location where
936-
#define CPP2_SOURCE_LOCATION_ARG , where
937-
#define CPP2_SOURCE_LOCATION_VALUE (cpp2::to_string(where.file_name()) + "(" + cpp2::to_string(where.line()) + ") " + where.function_name())
938-
#else
939-
#define CPP2_SOURCE_LOCATION_PARAM
940-
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT
941-
#define CPP2_SOURCE_LOCATION_PARAM_SOLO
942-
#define CPP2_SOURCE_LOCATION_ARG
943-
#define CPP2_SOURCE_LOCATION_VALUE std::string("")
944-
#endif
945-
946-
// For C++23: make this std::string_view and drop the macro
947-
// Before C++23 std::string_view was not guaranteed to be trivially copyable,
948-
// and so in<T> will pass it by const& and really it should be by value
949-
#define CPP2_MESSAGE_PARAM char const*
950-
#define CPP2_CONTRACT_MSG cpp2::message_to_cstr_adapter
951-
952-
inline auto message_to_cstr_adapter( CPP2_MESSAGE_PARAM msg ) -> CPP2_MESSAGE_PARAM { return msg ? msg : ""; }
953-
inline auto message_to_cstr_adapter( std::string const& msg ) -> CPP2_MESSAGE_PARAM { return msg.c_str(); }
954-
955-
class contract_group {
956-
public:
957-
using handler = void (*)(CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM);
958-
959-
constexpr contract_group (handler h = {}) : reporter{h} { }
960-
constexpr auto set_handler(handler h = {}) { reporter = h; }
961-
constexpr auto is_active () const -> bool { return reporter != handler{}; }
962-
963-
constexpr auto enforce(bool b, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
964-
-> void { if (!b) report_violation(msg CPP2_SOURCE_LOCATION_ARG); }
965-
constexpr auto report_violation(CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
966-
-> void { if (reporter) reporter(msg CPP2_SOURCE_LOCATION_ARG); }
967-
private:
968-
handler reporter;
969-
};
970-
971-
[[noreturn]] inline auto report_and_terminate(std::string_view group, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) noexcept -> void {
972-
std::cerr
973-
#ifdef CPP2_USE_SOURCE_LOCATION
974-
<< where.file_name() << "("
975-
<< where.line() << ") "
976-
<< where.function_name() << ": "
977-
#endif
978-
<< group << " violation";
979-
if (msg && msg[0] != '\0') {
980-
std::cerr << ": " << msg;
981-
}
982-
std::cerr << "\n";
983-
std::terminate();
984-
}
985-
986-
auto inline cpp2_default = contract_group(
987-
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
988-
report_and_terminate("Contract", msg CPP2_SOURCE_LOCATION_ARG);
989-
}
990-
);
991-
auto inline bounds_safety = contract_group(
992-
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
993-
report_and_terminate("Bounds safety", msg CPP2_SOURCE_LOCATION_ARG);
994-
}
995-
);
996-
auto inline null_safety = contract_group(
997-
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
998-
report_and_terminate("Null safety", msg CPP2_SOURCE_LOCATION_ARG);
999-
}
1000-
);
1001-
auto inline type_safety = contract_group(
1002-
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
1003-
report_and_terminate("Type safety", msg CPP2_SOURCE_LOCATION_ARG);
1004-
}
1005-
);
1006-
auto inline testing = contract_group(
1007-
[](CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
1008-
report_and_terminate("Testing", msg CPP2_SOURCE_LOCATION_ARG);
1009-
}
1010-
);
1011-
1012-
10131092
namespace impl {
10141093

10151094
template <class T> struct dependent_false : std::false_type {};
@@ -1405,7 +1484,7 @@ class deferred_init {
14051484
public:
14061485
constexpr deferred_init() noexcept { }
14071486
constexpr ~deferred_init() noexcept { destroy(); }
1408-
constexpr auto value() noexcept -> T& { cpp2_default.enforce(init); return t(); }
1487+
constexpr auto value() noexcept -> T& { cpp2_default.enforce(init); return t(); }
14091488

14101489
constexpr auto construct(auto&& ...args) -> void { cpp2_default.enforce(!init); new (&data) T{CPP2_FORWARD(args)...}; init = true; }
14111490
};
@@ -1762,22 +1841,6 @@ constexpr auto is( X const& x, bool (*value)(X const&) ) -> bool {
17621841
// The 'as' cast functions are <To, From> so use that order here
17631842
// If it's confusing, we can switch this to <From, To>
17641843

1765-
template< typename To, typename From >
1766-
constexpr auto is_narrowing_v =
1767-
// [dcl.init.list] 7.1
1768-
(std::is_floating_point_v<From> && std::is_integral_v<To>) ||
1769-
// [dcl.init.list] 7.2
1770-
(std::is_floating_point_v<From> && std::is_floating_point_v<To> && sizeof(From) > sizeof(To)) || // NOLINT(misc-redundant-expression)
1771-
// [dcl.init.list] 7.3
1772-
(std::is_integral_v<From> && std::is_floating_point_v<To>) ||
1773-
(std::is_enum_v<From> && std::is_floating_point_v<To>) ||
1774-
// [dcl.init.list] 7.4
1775-
(std::is_integral_v<From> && std::is_integral_v<To> && sizeof(From) > sizeof(To)) || // NOLINT(misc-redundant-expression)
1776-
(std::is_enum_v<From> && std::is_integral_v<To> && sizeof(From) > sizeof(To)) ||
1777-
// [dcl.init.list] 7.5
1778-
(std::is_pointer_v<From> && std::is_same_v<To, bool>)
1779-
;
1780-
17811844
template< typename To, typename From >
17821845
constexpr auto is_unsafe_pointer_conversion_v =
17831846
std::is_pointer_v<To>
@@ -2183,35 +2246,6 @@ class finally_presuccess
21832246
};
21842247

21852248

2186-
//-----------------------------------------------------------------------
2187-
//
2188-
// An implementation of GSL's narrow_cast with a clearly 'unchecked' name
2189-
//
2190-
//-----------------------------------------------------------------------
2191-
//
2192-
template <typename C, typename X>
2193-
constexpr auto unchecked_narrow( X x ) noexcept
2194-
-> decltype(auto)
2195-
requires (
2196-
impl::is_narrowing_v<C, X>
2197-
|| (
2198-
std::is_arithmetic_v<C>
2199-
&& std::is_arithmetic_v<X>
2200-
)
2201-
)
2202-
{
2203-
return static_cast<C>(x);
2204-
}
2205-
2206-
2207-
template <typename C, typename X>
2208-
constexpr auto unchecked_cast( X&& x ) noexcept
2209-
-> decltype(auto)
2210-
{
2211-
return static_cast<C>(CPP2_FORWARD(x));
2212-
}
2213-
2214-
22152249
//-----------------------------------------------------------------------
22162250
//
22172251
// args: see main() arguments as a container of string_views
@@ -2328,9 +2362,9 @@ class range
23282362
if (include_last) {
23292363
if constexpr (std::integral<TT>) {
23302364
if (last == std::numeric_limits<TT>::max()) {
2331-
throw std::runtime_error(
2365+
impl::Throw( std::runtime_error(
23322366
"range with last == numeric_limits<T>::max() will overflow"
2333-
);
2367+
), "range with last == numeric_limits<T>::max() will overflow");
23342368
}
23352369
}
23362370
++last;

0 commit comments

Comments
 (0)