mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 12:17:11 +01:00 
			
		
		
		
	Fix decomposing in presence of universal ADL-found operators
Closes #2121
This commit is contained in:
		 AlCash07
					AlCash07
				
			
				
					committed by
					
						 Martin Hořeňovský
						Martin Hořeňovský
					
				
			
			
				
	
			
			
			 Martin Hořeňovský
						Martin Hořeňovský
					
				
			
						parent
						
							65c9a1d31a
						
					
				
				
					commit
					c77ba5314a
				
			| @@ -183,60 +183,53 @@ namespace Catch { | |||||||
|     public: |     public: | ||||||
|         explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} |         explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} | ||||||
|  |  | ||||||
|         template<typename RhsT> |         template<typename RhsT, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, int> = 0> | ||||||
|         auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |         friend auto operator == ( ExprLhs && lhs, RhsT && rhs ) -> BinaryExpr<LhsT, RhsT const&> { | ||||||
|             return { compareEqual( m_lhs, rhs ), m_lhs, "=="_sr, rhs }; |             return { compareEqual( lhs.m_lhs, rhs ), lhs.m_lhs, "=="_sr, rhs }; | ||||||
|         } |         } | ||||||
|         auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { |         template<typename RhsT, std::enable_if_t<std::is_arithmetic<RhsT>::value, int> = 0> | ||||||
|             return { m_lhs == rhs, m_lhs, "=="_sr, rhs }; |         friend auto operator == ( ExprLhs && lhs, RhsT rhs ) -> BinaryExpr<LhsT, RhsT> { | ||||||
|  |             return { compareEqual( lhs.m_lhs, rhs ), lhs.m_lhs, "=="_sr, rhs }; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         template<typename RhsT> |         template<typename RhsT, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, int> = 0> | ||||||
|         auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |         friend auto operator != ( ExprLhs && lhs, RhsT && rhs ) -> BinaryExpr<LhsT, RhsT const&> { | ||||||
|             return { compareNotEqual( m_lhs, rhs ), m_lhs, "!="_sr, rhs }; |             return { compareNotEqual( lhs.m_lhs, rhs ), lhs.m_lhs, "!="_sr, rhs }; | ||||||
|         } |         } | ||||||
|         auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { |         template<typename RhsT, std::enable_if_t<std::is_arithmetic<RhsT>::value, int> = 0> | ||||||
|             return { m_lhs != rhs, m_lhs, "!="_sr, rhs }; |         friend auto operator != ( ExprLhs && lhs, RhsT rhs ) -> BinaryExpr<LhsT, RhsT> { | ||||||
|  |             return { compareNotEqual( lhs.m_lhs, rhs ), lhs.m_lhs, "!="_sr, rhs }; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         template<typename RhsT> |     #define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(op) \ | ||||||
|         auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |         template<typename RhsT, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, int> = 0> \ | ||||||
|             return { static_cast<bool>(m_lhs > rhs), m_lhs, ">"_sr, rhs }; |         friend auto operator op ( ExprLhs && lhs, RhsT && rhs ) -> BinaryExpr<LhsT, RhsT const&> { \ | ||||||
|         } |             return { static_cast<bool>(lhs.m_lhs op rhs), lhs.m_lhs, #op##_sr, rhs }; \ | ||||||
|         template<typename RhsT> |         } \ | ||||||
|         auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |         template<typename RhsT, std::enable_if_t<std::is_arithmetic<RhsT>::value, int> = 0> \ | ||||||
|             return { static_cast<bool>(m_lhs < rhs), m_lhs, "<"_sr, rhs }; |         friend auto operator op ( ExprLhs && lhs, RhsT rhs ) -> BinaryExpr<LhsT, RhsT> { \ | ||||||
|         } |             return { static_cast<bool>(lhs.m_lhs op rhs), lhs.m_lhs, #op##_sr, rhs }; \ | ||||||
|         template<typename RhsT> |  | ||||||
|         auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |  | ||||||
|             return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">="_sr, rhs }; |  | ||||||
|         } |  | ||||||
|         template<typename RhsT> |  | ||||||
|         auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |  | ||||||
|             return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<="_sr, rhs }; |  | ||||||
|         } |  | ||||||
|         template <typename RhsT> |  | ||||||
|         auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |  | ||||||
|             return { static_cast<bool>(m_lhs | rhs), m_lhs, "|"_sr, rhs }; |  | ||||||
|         } |  | ||||||
|         template <typename RhsT> |  | ||||||
|         auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |  | ||||||
|             return { static_cast<bool>(m_lhs & rhs), m_lhs, "&"_sr, rhs }; |  | ||||||
|         } |  | ||||||
|         template <typename RhsT> |  | ||||||
|         auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |  | ||||||
|             return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^"_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(&) | ||||||
|  |         CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(^) | ||||||
|  |  | ||||||
|  |     #undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR | ||||||
|  |  | ||||||
|         template<typename RhsT> |         template<typename RhsT> | ||||||
|         auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { |         friend auto operator && ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> { | ||||||
|             static_assert(always_false<RhsT>::value, |             static_assert(always_false<RhsT>::value, | ||||||
|             "operator&& is not supported inside assertions, " |             "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> |         template<typename RhsT> | ||||||
|         auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { |         friend auto operator || ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> { | ||||||
|             static_assert(always_false<RhsT>::value, |             static_assert(always_false<RhsT>::value, | ||||||
|             "operator|| is not supported inside assertions, " |             "operator|| is not supported inside assertions, " | ||||||
|             "wrap the expression inside parentheses, or decompose it"); |             "wrap the expression inside parentheses, or decompose it"); | ||||||
| @@ -247,21 +240,15 @@ namespace Catch { | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     void handleExpression( ITransientExpression const& expr ); |  | ||||||
|  |  | ||||||
|     template<typename T> |  | ||||||
|     void handleExpression( ExprLhs<T> const& expr ) { |  | ||||||
|         handleExpression( expr.makeUnaryExpr() ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     struct Decomposer { |     struct Decomposer { | ||||||
|         template<typename T> |         template<typename T, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<T>>::value, int> = 0> | ||||||
|         auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { |         friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const&> { | ||||||
|             return ExprLhs<T const&>{ lhs }; |             return ExprLhs<const T&>{ lhs }; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         auto operator <=( bool value ) -> ExprLhs<bool> { |         template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0> | ||||||
|             return ExprLhs<bool>{ value }; |         friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> { | ||||||
|  |             return ExprLhs<T>{ value }; | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -277,3 +277,42 @@ namespace { | |||||||
| TEST_CASE("Immovable types are supported in basic assertions", "[compilation][.approvals]") { | TEST_CASE("Immovable types are supported in basic assertions", "[compilation][.approvals]") { | ||||||
|     REQUIRE(ImmovableType{} == ImmovableType{}); |     REQUIRE(ImmovableType{} == ImmovableType{}); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | namespace adl { | ||||||
|  |  | ||||||
|  | struct always_true { | ||||||
|  |     explicit operator bool() const { return true; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #define COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(op) \ | ||||||
|  | template <class T, class U> \ | ||||||
|  | auto operator op (T&&, U&&) { \ | ||||||
|  |     return always_true{}; \ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(==) | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(!=) | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(<) | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(>) | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(<=) | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(>=) | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(|) | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(&) | ||||||
|  | COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR(^) | ||||||
|  |  | ||||||
|  | #undef COMPILATION_TEST_DEFINE_UNIVERSAL_OPERATOR | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_CASE("ADL universal operators don't hijack expression deconstruction", "[compilation][.approvals]") { | ||||||
|  |     REQUIRE(adl::always_true{}); | ||||||
|  |     REQUIRE(0 == adl::always_true{}); | ||||||
|  |     REQUIRE(0 != adl::always_true{}); | ||||||
|  |     REQUIRE(0 < adl::always_true{}); | ||||||
|  |     REQUIRE(0 > adl::always_true{}); | ||||||
|  |     REQUIRE(0 <= adl::always_true{}); | ||||||
|  |     REQUIRE(0 >= adl::always_true{}); | ||||||
|  |     REQUIRE(0 | adl::always_true{}); | ||||||
|  |     REQUIRE(0 & adl::always_true{}); | ||||||
|  |     REQUIRE(0 ^ adl::always_true{}); | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user