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

summaryrefslogtreecommitdiffhomepage
path: root/src/catch2/internal
diff options
context:
space:
mode:
authorLeitwolf2026-10-11 10:09:19 +0300
committerGitHub2026-10-11 10:09:19 +0300
commitce6fa1996a8e358efdcff53a7628584077d9855c (patch)
treed76f5945311828511e3ea55712487f21fbf8f70f /src/catch2/internal
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/internal')
-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
6 files changed, 208 insertions, 178 deletions
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 { \
- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #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 LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT&& rhs ) \
+ ->std::enable_if_t< \
+ !capture_by_value<Detail::RemoveCVRef_t<RhsT>>::value, \
+ BinaryExpr<LhsT, RhsT const&>> { \
+ return { static_cast<bool>( lhs.getLhs() op rhs ), \
+ lhs.getLhs(), \
+ #op##_sr, \
+ rhs }; \
+ } \
+ template <typename LhsT, typename RhsT> \
+ constexpr auto operator op( ExprLhs<LhsT>&& lhs, RhsT rhs ) \
+ ->std::enable_if_t<capture_by_value<RhsT>::value, \
+ BinaryExpr<LhsT, RhsT>> { \
+ return { static_cast<bool>( lhs.getLhs() op rhs ), \
+ lhs.getLhs(), \
+ #op##_sr, \
+ rhs }; \
}
- CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(|)
- CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(&)
- CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(^)
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( | )
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( & )
+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( ^)
- #undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR
+#undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR
- template<typename RhsT>
- friend auto operator && ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
- static_assert(always_false<RhsT>::value,
+ template <typename LhsT, typename RhsT>
+ auto operator&&( ExprLhs<LhsT>&&, RhsT&& )
+ -> BinaryExpr<LhsT, RhsT const&> {
+ static_assert(
+ always_false<RhsT>::value,
"operator&& is not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
+ "wrap the expression inside parentheses, or decompose it" );
+ }
- template<typename RhsT>
- friend auto operator || ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
- static_assert(always_false<RhsT>::value,
+ template <typename LhsT, typename RhsT>
+ auto operator||( ExprLhs<LhsT>&&, RhsT&& )
+ -> BinaryExpr<LhsT, RhsT const&> {
+ static_assert(
+ always_false<RhsT>::value,
"operator|| is not supported inside assertions, "
- "wrap the expression inside parentheses, or decompose it");
- }
+ "wrap the expression inside parentheses, or decompose it" );
+ }
- constexpr auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
- return UnaryExpr<LhsT>{ m_lhs };
- }
- };
struct Decomposer {
template <typename T,
diff --git a/src/catch2/internal/catch_preprocessor.hpp b/src/catch2/internal/catch_preprocessor.hpp
index b7336c47..82868640 100644
--- a/src/catch2/internal/catch_preprocessor.hpp
+++ b/src/catch2/internal/catch_preprocessor.hpp
@@ -218,7 +218,7 @@ namespace Catch {
template<typename... Ts>\
void reg_test(TypeList<Ts...>, Catch::NameAndTags nameAndTags)\
{\
- Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Ts...>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ Catch::AutoReg( &TestFunc<Ts...>, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
}
#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature, ...)
@@ -226,7 +226,7 @@ namespace Catch {
template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
{\
- Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
+ Catch::AutoReg( &TestFunc<__VA_ARGS__>, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
}
#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
diff --git a/src/catch2/internal/catch_test_macro_impl.hpp b/src/catch2/internal/catch_test_macro_impl.hpp
index f38ec606..6263e57d 100644
--- a/src/catch2/internal/catch_test_macro_impl.hpp
+++ b/src/catch2/internal/catch_test_macro_impl.hpp
@@ -44,6 +44,19 @@ namespace Catch {
#endif
+#if defined( CATCH_CONFIG_USE_BUILTIN_CONSTANT_P ) && \
+ !defined( CATCH_CONFIG_NO_USE_BUILTIN_CONSTANT_P )
+ // CATCH_INTERNAL_IGNORE_BUT_WARN already checks the expression on these
+ // compilers, so avoid checking it a third time in the loop condition.
+ #define INTERNAL_CATCH_TEST_LOOP_CONDITION( ... ) false
+#else
+ // * The double negation silences MSVC's C4800 warning.
+ // * We keep the expression to allow for warnings in the original context
+ // * The static_cast forces short-circuit evaluation if the type has overloaded &&.
+ #define INTERNAL_CATCH_TEST_LOOP_CONDITION( ... ) \
+ (void)0, (false) && static_cast<const bool&>( !!(__VA_ARGS__) )
+#endif
+
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
do { /* NOLINT(bugprone-infinite-loop) */ \
@@ -57,8 +70,7 @@ namespace Catch {
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
catchAssertionHandler.complete(); \
- } while( (void)0, (false) && static_cast<const bool&>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
- // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+ } while( INTERNAL_CATCH_TEST_LOOP_CONDITION( __VA_ARGS__ ) ) // the expression here is never evaluated at runtime, but is shown to some compilers
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \