diff options
| author | Leitwolf | 2026-10-11 10:09:19 +0300 |
|---|---|---|
| committer | GitHub | 2026-10-11 10:09:19 +0300 |
| commit | ce6fa1996a8e358efdcff53a7628584077d9855c (patch) | |
| tree | d76f5945311828511e3ea55712487f21fbf8f70f /src/catch2/internal | |
| parent | 5633c5c98ec073ae938253bcfc72430d5d9aee89 (diff) | |
| parent | 1f78d8903c2fb18afea8c3055f8df83d8c60d9b5 (diff) | |
| download | catch3-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.cpp | 2 | ||||
| -rw-r--r-- | src/catch2/internal/catch_assertion_handler.hpp | 15 | ||||
| -rw-r--r-- | src/catch2/internal/catch_decomposer.cpp | 7 | ||||
| -rw-r--r-- | src/catch2/internal/catch_decomposer.hpp | 342 | ||||
| -rw-r--r-- | src/catch2/internal/catch_preprocessor.hpp | 4 | ||||
| -rw-r--r-- | src/catch2/internal/catch_test_macro_impl.hpp | 16 |
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, ... ) \ |