mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-25 23:06:10 +01:00
Fix decomposing in presence of universal ADL-found operators
Closes #2121
This commit is contained in:
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{});
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user