Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/catch2
diff options
context:
space:
mode:
authorLeitwolf2026-10-11 10:09:19 +0300
committerGitHub2026-10-11 10:09:19 +0300
commitce6fa1996a8e358efdcff53a7628584077d9855c (patch)
treed76f5945311828511e3ea55712487f21fbf8f70f /src/catch2
parent5633c5c98ec073ae938253bcfc72430d5d9aee89 (diff)
parent1f78d8903c2fb18afea8c3055f8df83d8c60d9b5 (diff)
downloadcatch3-ce6fa1996a8e358efdcff53a7628584077d9855c.tar.gz
Merge pull request #4 from Progmasoft/backport/upstream-3.16.1
Backport Catch2 3.16.1
Diffstat (limited to 'src/catch2')
-rw-r--r--src/catch2/benchmark/catch_optimizer.hpp2
-rw-r--r--src/catch2/catch_session.cpp12
-rw-r--r--src/catch2/catch_session.hpp1
-rw-r--r--src/catch2/catch_version.cpp2
-rw-r--r--src/catch2/catch_version_macros.hpp2
-rw-r--r--src/catch2/internal/catch_assertion_handler.cpp2
-rw-r--r--src/catch2/internal/catch_assertion_handler.hpp15
-rw-r--r--src/catch2/internal/catch_decomposer.cpp7
-rw-r--r--src/catch2/internal/catch_decomposer.hpp342
-rw-r--r--src/catch2/internal/catch_preprocessor.hpp4
-rw-r--r--src/catch2/internal/catch_test_macro_impl.hpp16
-rw-r--r--src/catch2/matchers/internal/catch_matchers_impl.hpp17
-rw-r--r--src/catch2/reporters/catch_reporter_automake.cpp9
-rw-r--r--src/catch2/reporters/catch_reporter_automake.hpp6
-rw-r--r--src/catch2/reporters/catch_reporter_compact.cpp7
-rw-r--r--src/catch2/reporters/catch_reporter_compact.hpp6
-rw-r--r--src/catch2/reporters/catch_reporter_console.cpp1
-rw-r--r--src/catch2/reporters/catch_reporter_helpers.cpp13
-rw-r--r--src/catch2/reporters/catch_reporter_helpers.hpp13
-rw-r--r--src/catch2/reporters/catch_reporter_json.cpp2
-rw-r--r--src/catch2/reporters/catch_reporter_junit.cpp4
-rw-r--r--src/catch2/reporters/catch_reporter_sonarqube.cpp10
-rw-r--r--src/catch2/reporters/catch_reporter_sonarqube.hpp9
-rw-r--r--src/catch2/reporters/catch_reporter_tap.cpp8
-rw-r--r--src/catch2/reporters/catch_reporter_tap.hpp6
-rw-r--r--src/catch2/reporters/catch_reporter_teamcity.cpp8
-rw-r--r--src/catch2/reporters/catch_reporter_teamcity.hpp8
-rw-r--r--src/catch2/reporters/catch_reporter_xml.cpp2
28 files changed, 311 insertions, 223 deletions
diff --git a/src/catch2/benchmark/catch_optimizer.hpp b/src/catch2/benchmark/catch_optimizer.hpp
index 5535b2a2..281256a3 100644
--- a/src/catch2/benchmark/catch_optimizer.hpp
+++ b/src/catch2/benchmark/catch_optimizer.hpp
@@ -46,7 +46,7 @@ namespace Catch {
*reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
}
// TODO equivalent keep_memory()
-#if defined(_MSVC_VER)
+#if defined(_MSC_VER)
#pragma optimize("", on)
#endif
diff --git a/src/catch2/catch_session.cpp b/src/catch2/catch_session.cpp
index 1c993ce1..34fd2809 100644
--- a/src/catch2/catch_session.cpp
+++ b/src/catch2/catch_session.cpp
@@ -458,7 +458,17 @@ namespace Catch {
getCurrentMutableContext().setConfig(m_config.get());
// Create reporter(s) so we can route listings through them
- auto reporter = prepareReporters(m_config.get());
+ IEventListenerPtr reporter;
+ CATCH_TRY {
+ auto reporter_ = prepareReporters( m_config.get() );
+ swap( reporter, reporter_ );
+ }
+#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
+ catch ( std::exception& ex ) {
+ Catch::cerr() << "Error when creating reporter: " << ex.what() << '\n' << std::flush;
+ return ReporterConstructionErrorExitCode;
+ }
+#endif
auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
if ( !invalidSpecs.empty() ) {
diff --git a/src/catch2/catch_session.hpp b/src/catch2/catch_session.hpp
index 23fc6f80..4da7c66f 100644
--- a/src/catch2/catch_session.hpp
+++ b/src/catch2/catch_session.hpp
@@ -22,6 +22,7 @@ namespace Catch {
constexpr int UnmatchedTestSpecExitCode = 3;
constexpr int AllTestsSkippedExitCode = 4;
constexpr int InvalidTestSpecExitCode = 5;
+ constexpr int ReporterConstructionErrorExitCode = 6;
constexpr int TestFailureExitCode = 42;
class Session : Detail::NonCopyable {
diff --git a/src/catch2/catch_version.cpp b/src/catch2/catch_version.cpp
index d0b44d72..cc332bc2 100644
--- a/src/catch2/catch_version.cpp
+++ b/src/catch2/catch_version.cpp
@@ -36,7 +36,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 3, 16, 0, "", 0 );
+ static Version version( 3, 16, 1, "", 0 );
return version;
}
diff --git a/src/catch2/catch_version_macros.hpp b/src/catch2/catch_version_macros.hpp
index 3219afb2..241928ab 100644
--- a/src/catch2/catch_version_macros.hpp
+++ b/src/catch2/catch_version_macros.hpp
@@ -10,6 +10,6 @@
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 16
-#define CATCH_VERSION_PATCH 0
+#define CATCH_VERSION_PATCH 1
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
diff --git a/src/catch2/internal/catch_assertion_handler.cpp b/src/catch2/internal/catch_assertion_handler.cpp
index 79d5dcd8..e028c371 100644
--- a/src/catch2/internal/catch_assertion_handler.cpp
+++ b/src/catch2/internal/catch_assertion_handler.cpp
@@ -61,7 +61,7 @@ namespace Catch {
}
}
- void AssertionHandler::handleUnexpectedInflightException() {
+ void AssertionHandler::handleUnexpectedInflightException() noexcept {
m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
}
diff --git a/src/catch2/internal/catch_assertion_handler.hpp b/src/catch2/internal/catch_assertion_handler.hpp
index 93a70b1a..4b7607ad 100644
--- a/src/catch2/internal/catch_assertion_handler.hpp
+++ b/src/catch2/internal/catch_assertion_handler.hpp
@@ -59,7 +59,20 @@ namespace Catch {
void handleUnexpectedExceptionNotThrown();
void handleExceptionNotThrownAsExpected();
void handleThrowingCallSkipped();
- void handleUnexpectedInflightException();
+
+ // Marking this as `noexcept` gives us measurable improvement
+ // in optimized compilation times. Making it `noexcept` changes
+ // what happens if the underlying code throws, **but** the only
+ // way this can throw is if the reporter itself throws from
+ // `assertionEnded`. However, in such case the process is going
+ // to abort anyway, because we will enter `assertionEnded` again
+ // from the (noexcept) destructor of `AssertionHandler` above.
+ // In the future, all reporter event handlers will be marked
+ // `noexcept` to make this limitation explicit.
+ void handleUnexpectedInflightException() noexcept;
+ // Ideally we could extend the logic above to more of the handle*
+ // function, but right now it would worsen the behaviour of
+ // preexisting custom reporters that throw from event handlers.
void complete();
diff --git a/src/catch2/internal/catch_decomposer.cpp b/src/catch2/internal/catch_decomposer.cpp
index 17a7bc95..e702c745 100644
--- a/src/catch2/internal/catch_decomposer.cpp
+++ b/src/catch2/internal/catch_decomposer.cpp
@@ -10,13 +10,6 @@
namespace Catch {
- void ITransientExpression::streamReconstructedExpression(
- std::ostream& os ) const {
- // We can't make this function pure virtual to keep ITransientExpression
- // constexpr, so we write error message instead
- os << "Some class derived from ITransientExpression without overriding streamReconstructedExpression";
- }
-
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
if( lhs.size() + rhs.size() < 40 &&
lhs.find('\n') == std::string::npos &&
diff --git a/src/catch2/internal/catch_decomposer.hpp b/src/catch2/internal/catch_decomposer.hpp
index ff628482..9c004b02 100644
--- a/src/catch2/internal/catch_decomposer.hpp
+++ b/src/catch2/internal/catch_decomposer.hpp
@@ -164,28 +164,27 @@ namespace Catch {
struct always_false : std::false_type {};
class ITransientExpression {
+ //! Type-erased streaming function for the derived expression
+ using StreamFn = void ( * )( void const*, std::ostream& );
+
+ StreamFn m_streamFn;
bool m_isBinaryExpression;
bool m_result;
- protected:
- ~ITransientExpression() = default;
-
public:
constexpr auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
constexpr auto getResult() const -> bool { return m_result; }
- //! This function **has** to be overridden by the derived class.
- virtual void streamReconstructedExpression( std::ostream& os ) const;
-
- constexpr ITransientExpression( bool isBinaryExpression, bool result )
- : m_isBinaryExpression( isBinaryExpression ),
- m_result( result )
- {}
- constexpr ITransientExpression( ITransientExpression const& ) = default;
- constexpr ITransientExpression& operator=( ITransientExpression const& ) = default;
+ constexpr ITransientExpression( StreamFn streamFn,
+ bool isBinaryExpression,
+ bool result ):
+ m_streamFn( streamFn ),
+ m_isBinaryExpression( isBinaryExpression ),
+ m_result( result ) {}
- friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) {
- expr.streamReconstructedExpression(out);
+ friend std::ostream& operator<<( std::ostream& out,
+ ITransientExpression const& expr ) {
+ expr.m_streamFn( &expr, out );
return out;
}
};
@@ -198,87 +197,67 @@ namespace Catch {
StringRef m_op;
RhsT m_rhs;
- void streamReconstructedExpression( std::ostream &os ) const override {
- formatReconstructedExpression
- ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
+ static void streamFn( void const* self, std::ostream& out ) {
+ auto const& expr = *static_cast<BinaryExpr const*>(
+ static_cast<ITransientExpression const*>( self ) );
+ formatReconstructedExpression(
+ out,
+ Catch::Detail::stringify( expr.m_lhs ),
+ expr.m_op,
+ Catch::Detail::stringify( expr.m_rhs ) );
}
public:
constexpr BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
- : ITransientExpression{ true, comparisonResult },
+ : ITransientExpression{ &streamFn, true, comparisonResult },
m_lhs( lhs ),
m_op( op ),
m_rhs( rhs )
{}
+ };
- template<typename T>
- auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
- static_assert(always_false<T>::value,
- "chained comparisons are not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
-
- template<typename T>
- auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
- static_assert(always_false<T>::value,
- "chained comparisons are not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
-
- template<typename T>
- auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
- static_assert(always_false<T>::value,
- "chained comparisons are not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
-
- template<typename T>
- auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
- static_assert(always_false<T>::value,
- "chained comparisons are not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
-
- template<typename T>
- auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
- static_assert(always_false<T>::value,
- "chained comparisons are not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
-
- template<typename T>
- auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
- static_assert(always_false<T>::value,
- "chained comparisons are not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
-
- template<typename T>
- auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
- static_assert(always_false<T>::value,
- "chained comparisons are not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
+#define CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( op ) \
+ template <typename LhsT, typename RhsT, typename T> \
+ auto operator op( BinaryExpr<LhsT, RhsT> const&, T ) \
+ ->BinaryExpr<LhsT, RhsT const&> const { \
+ static_assert( always_false<T>::value, \
+ "chained comparisons are not supported inside " \
+ "assertions, wrap the expression inside " \
+ "parentheses, or decompose it" ); \
+ }
- template<typename T>
- auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
- static_assert(always_false<T>::value,
- "chained comparisons are not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
- };
+ /*
+ * The operators are **intentionally** not hidden friends.
+ *
+ * If they were hidden friends, all of them would get stamped out when
+ * a `BinaryExpr` is instantiated with a new type. In practice, only
+ * few operators are used for each different `BinaryExpr<LhsT, RhsT>`,
+ * so this avoids bunch of wasted work.
+ */
+ CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( && )
+ CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( || )
+ CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( == )
+ CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( != )
+ CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( > )
+ CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( < )
+ CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( >= )
+ CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR( <= )
+
+#undef CATCH_INTERNAL_DEFINE_BINARY_EXPR_OPERATOR
template<typename LhsT>
class UnaryExpr final : public ITransientExpression {
LhsT m_lhs;
- void streamReconstructedExpression( std::ostream &os ) const override {
- os << Catch::Detail::stringify( m_lhs );
+ static void streamFn( void const* self, std::ostream& os ) {
+ auto const& expr = *static_cast<UnaryExpr const*>(
+ static_cast<ITransientExpression const*>( self ) );
+ os << Catch::Detail::stringify( expr.m_lhs );
}
public:
explicit constexpr UnaryExpr( LhsT lhs )
- : ITransientExpression{ false, static_cast<bool>(lhs) },
+ : ITransientExpression{ &streamFn, false, static_cast<bool>(lhs) },
m_lhs( lhs )
{}
};
@@ -290,153 +269,186 @@ namespace Catch {
public:
explicit constexpr ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
+ // We rely on reference collapsing if LhsT is already a reference.
+ // Used in the out-of-class decomposition operators
+ constexpr LhsT& getLhs() { return m_lhs; }
+
+ constexpr auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
+ return UnaryExpr<LhsT>{ m_lhs };
+ }
+ };
+
+/*
+ * The comparison operators are **intentionally** not hidden friends.
+ *
+ * If they were hidden friends, all of them would get stamped out when
+ * a `ExprLhs` is instantiated with a new type. In practice, only few
+ * operators are used for each different `ExprLhs<T>`, so this avoids
+ * a lot of wasted work.
+ */
#define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( id, op ) \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
- -> std::enable_if_t< \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT&& rhs ) \
+ ->std::enable_if_t< \
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
Detail::negation<capture_by_value< \
Detail::RemoveCVRef_t<RhsT>>>>::value, \
BinaryExpr<LhsT, RhsT const&>> { \
- return { \
- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
+ return { static_cast<bool>( lhs.getLhs() op rhs ), \
+ lhs.getLhs(), \
+ #op##_sr, \
+ rhs }; \
} \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
- -> std::enable_if_t< \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT rhs ) \
+ ->std::enable_if_t< \
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
capture_by_value<RhsT>>::value, \
BinaryExpr<LhsT, RhsT>> { \
- return { \
- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
+ return { static_cast<bool>( lhs.getLhs() op rhs ), \
+ lhs.getLhs(), \
+ #op##_sr, \
+ rhs }; \
} \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
- -> std::enable_if_t< \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT rhs ) \
+ ->std::enable_if_t< \
Detail::conjunction< \
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
- Detail::is_eq_0_comparable<LhsT>, \
- /* We allow long because we want `ptr op NULL` to be accepted */ \
+ Detail::is_eq_0_comparable<LhsT>, /* We allow long because we \
+ want `ptr op NULL` to be \
+ accepted */ \
Detail::disjunction<std::is_same<RhsT, int>, \
std::is_same<RhsT, long>>>::value, \
BinaryExpr<LhsT, RhsT>> { \
if ( rhs != 0 ) { throw_test_failure_exception(); } \
- return { \
- static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
+ return { static_cast<bool>( lhs.getLhs() op 0 ), \
+ lhs.getLhs(), \
+ #op##_sr, \
+ rhs }; \
} \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
- -> std::enable_if_t< \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT rhs ) \
+ ->std::enable_if_t< \
Detail::conjunction< \
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
- Detail::is_eq_0_comparable<RhsT>, \
- /* We allow long because we want `ptr op NULL` to be accepted */ \
+ Detail::is_eq_0_comparable<RhsT>, /* We allow long because we \
+ want `ptr op NULL` to be \
+ accepted */ \
Detail::disjunction<std::is_same<LhsT, int>, \
std::is_same<LhsT, long>>>::value, \
BinaryExpr<LhsT, RhsT>> { \
- if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
- return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
+ if ( lhs.getLhs() != 0 ) { throw_test_failure_exception(); } \
+ return { static_cast<bool>( 0 op rhs ), lhs.getLhs(), #op##_sr, rhs }; \
}
- CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == )
- CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != )
-
- #undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
+ CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == )
+ CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != )
+#undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
- -> std::enable_if_t< \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT&& rhs ) \
+ ->std::enable_if_t< \
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
Detail::negation<capture_by_value< \
Detail::RemoveCVRef_t<RhsT>>>>::value, \
BinaryExpr<LhsT, RhsT const&>> { \
- return { \
- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
+ return { static_cast<bool>( lhs.getLhs() op rhs ), \
+ lhs.getLhs(), \
+ #op##_sr, \
+ rhs }; \
} \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
- -> std::enable_if_t< \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT rhs ) \
+ ->std::enable_if_t< \
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
capture_by_value<RhsT>>::value, \
BinaryExpr<LhsT, RhsT>> { \
- return { \
- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
+ return { static_cast<bool>( lhs.getLhs() op rhs ), \
+ lhs.getLhs(), \
+ #op##_sr, \
+ rhs }; \
} \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
- -> std::enable_if_t< \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT rhs ) \
+ ->std::enable_if_t< \
Detail::conjunction< \
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
Detail::is_##id##_0_comparable<LhsT>, \
std::is_same<RhsT, int>>::value, \
BinaryExpr<LhsT, RhsT>> { \
if ( rhs != 0 ) { throw_test_failure_exception(); } \
- return { \
- static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
+ return { static_cast<bool>( lhs.getLhs() op 0 ), \
+ lhs.getLhs(), \
+ #op##_sr, \
+ rhs }; \
} \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
- -> std::enable_if_t< \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT rhs ) \
+ ->std::enable_if_t< \
Detail::conjunction< \
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
Detail::is_##id##_0_comparable<RhsT>, \
std::is_same<LhsT, int>>::value, \
BinaryExpr<LhsT, RhsT>> { \
- if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
- return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
+ if ( lhs.getLhs() != 0 ) { throw_test_failure_exception(); } \
+ return { static_cast<bool>( 0 op rhs ), lhs.getLhs(), #op##_sr, rhs }; \
}
- CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( lt, < )
- CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( le, <= )
- CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > )
- CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= )
-
- #undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR
-
-
-#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( op ) \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
- -> std::enable_if_t< \
- !capture_by_value<Detail::RemoveCVRef_t<RhsT>>::value, \
- BinaryExpr<LhsT, RhsT const&>> { \
- return { \
- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
- } \
- template <typename RhsT> \
- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
- -> std::enable_if_t<capture_by_value<RhsT>::value, \
- BinaryExpr<LhsT, RhsT>> { \
- return {