Fix old GCC + types with ambiguous constructor from 0

Closes #2571
This commit is contained in:
Martin Hořeňovský 2022-11-20 11:06:45 +01:00
parent ae1644e7e9
commit 291c502f66
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
2 changed files with 78 additions and 51 deletions

View File

@ -13,6 +13,7 @@
#include <catch2/internal/catch_meta.hpp> #include <catch2/internal/catch_meta.hpp>
#include <catch2/internal/catch_compare_traits.hpp> #include <catch2/internal/catch_compare_traits.hpp>
#include <catch2/internal/catch_test_failure_exception.hpp> #include <catch2/internal/catch_test_failure_exception.hpp>
#include <catch2/internal/catch_logical_traits.hpp>
#include <type_traits> #include <type_traits>
#include <iosfwd> #include <iosfwd>
@ -168,19 +169,20 @@ namespace Catch {
template < \ template < \
typename RhsT, \ typename RhsT, \
std::enable_if_t< \ std::enable_if_t< \
Detail::is_##id##_comparable<LhsT, RhsT>::value && \ Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, \ Detail::negation<std::is_arithmetic< \
std::remove_reference_t<RhsT>>>>::value, \
int> = 0> \ int> = 0> \
friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \ friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
->BinaryExpr<LhsT, RhsT const&> { \ ->BinaryExpr<LhsT, RhsT const&> { \
return { \ return { \
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
} \ } \
template < \ template <typename RhsT, \
typename RhsT, \ std::enable_if_t<Detail::conjunction< \
std::enable_if_t<Detail::is_##id##_comparable<LhsT, RhsT>::value && \ Detail::is_##id##_comparable<LhsT, RhsT>, \
std::is_arithmetic<RhsT>::value, \ std::is_arithmetic<RhsT>>::value, \
int> = 0> \ int> = 0> \
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
->BinaryExpr<LhsT, RhsT> { \ ->BinaryExpr<LhsT, RhsT> { \
return { \ return { \
@ -188,59 +190,58 @@ namespace Catch {
} \ } \
template < \ template < \
typename RhsT, \ typename RhsT, \
std::enable_if_t<!Detail::is_##id##_comparable<LhsT, RhsT>::value && \ std::enable_if_t< \
Detail::is_eq_0_comparable<LhsT>:: \ Detail::conjunction< \
value && /* We allow long because we want \ Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
`ptr op NULL to be accepted */ \ Detail::is_eq_0_comparable<LhsT>, \
( std::is_same<RhsT, int>::value || \ Detail::disjunction<std::is_same<RhsT, int>, \
std::is_same<RhsT, long>::value ), \ /* On some platforms `NULL` is a long */ \
int> = 0> \ std::is_same<RhsT, long>>>::value, \
int> = 0> \
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
->BinaryExpr<LhsT, RhsT> { \ ->BinaryExpr<LhsT, RhsT> { \
if ( rhs != 0 ) { \ if ( rhs != 0 ) { throw_test_failure_exception(); } \
throw_test_failure_exception(); \
} \
return { \ return { \
static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \ static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
} \ } \
template < \ template < \
typename RhsT, \ typename RhsT, \
std::enable_if_t<!Detail::is_##id##_comparable<LhsT, RhsT>::value && \ std::enable_if_t< \
Detail::is_eq_0_comparable<RhsT>:: \ Detail::conjunction< \
value && /* We allow long because we want \ Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
`ptr op NULL` to be accepted */ \ Detail::is_eq_0_comparable<RhsT>, \
( std::is_same<LhsT, int>::value || \ Detail::disjunction<std::is_same<LhsT, int>, \
std::is_same<LhsT, long>::value ), \ /* On some platforms `NULL` is a long */ \
int> = 0> \ std::is_same<LhsT, long>>>::value, \
int> = 0> \
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
->BinaryExpr<LhsT, RhsT> { \ ->BinaryExpr<LhsT, RhsT> { \
if ( lhs.m_lhs != 0 ) { \ if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
throw_test_failure_exception(); \
} \
return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
} }
CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == ) CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == )
CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != ) CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != )
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR #undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \ #define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
template < \ template < \
typename RhsT, \ typename RhsT, \
std::enable_if_t< \ std::enable_if_t< \
Detail::is_##id##_comparable<LhsT, RhsT>::value && \ Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, \ Detail::negation<std::is_arithmetic< \
std::remove_reference_t<RhsT>>>>::value, \
int> = 0> \ int> = 0> \
friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \ friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
->BinaryExpr<LhsT, RhsT const&> { \ ->BinaryExpr<LhsT, RhsT const&> { \
return { \ return { \
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
} \ } \
template < \ template <typename RhsT, \
typename RhsT, \ std::enable_if_t<Detail::conjunction< \
std::enable_if_t<Detail::is_##id##_comparable<LhsT, RhsT>::value && \ Detail::is_##id##_comparable<LhsT, RhsT>, \
std::is_arithmetic<RhsT>::value, \ std::is_arithmetic<RhsT>>::value, \
int> = 0> \ int> = 0> \
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
->BinaryExpr<LhsT, RhsT> { \ ->BinaryExpr<LhsT, RhsT> { \
return { \ return { \
@ -248,29 +249,29 @@ namespace Catch {
} \ } \
template < \ template < \
typename RhsT, \ typename RhsT, \
std::enable_if_t<!Detail::is_##id##_comparable<LhsT, RhsT>::value && \ std::enable_if_t< \
Detail::is_##id##_0_comparable<LhsT>::value && \ Detail::conjunction< \
std::is_same<RhsT, int>::value, \ Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
int> = 0> \ Detail::is_##id##_0_comparable<LhsT>, \
std::is_same<RhsT, int>>::value, \
int> = 0> \
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
->BinaryExpr<LhsT, RhsT> { \ ->BinaryExpr<LhsT, RhsT> { \
if ( rhs != 0 ) { \ if ( rhs != 0 ) { throw_test_failure_exception(); } \
throw_test_failure_exception(); \
} \
return { \ return { \
static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \ static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
} \ } \
template < \ template < \
typename RhsT, \ typename RhsT, \
std::enable_if_t<!Detail::is_##id##_comparable<LhsT, RhsT>::value && \ std::enable_if_t< \
Detail::is_##id##_0_comparable<RhsT>::value && \ Detail::conjunction< \
std::is_same<LhsT, int>::value, \ Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
int> = 0> \ Detail::is_##id##_0_comparable<RhsT>, \
std::is_same<LhsT, int>>::value, \
int> = 0> \
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
->BinaryExpr<LhsT, RhsT> { \ ->BinaryExpr<LhsT, RhsT> { \
if ( lhs.m_lhs != 0 ) { \ if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
throw_test_failure_exception(); \
} \
return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
} }
@ -279,7 +280,7 @@ namespace Catch {
CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > ) CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > )
CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= ) CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= )
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR #undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR
#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(op) \ #define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(op) \

View File

@ -329,3 +329,29 @@ TEST_CASE( "#2555 - types that can only be compared with 0 literal (not int/long
REQUIRE( TypeWithLit0Comparisons{} != 0 ); REQUIRE( TypeWithLit0Comparisons{} != 0 );
REQUIRE_FALSE( 0 != TypeWithLit0Comparisons{} ); REQUIRE_FALSE( 0 != TypeWithLit0Comparisons{} );
} }
namespace {
struct MultipleImplicitConstructors {
MultipleImplicitConstructors( double ) {}
MultipleImplicitConstructors( int64_t ) {}
bool operator==( MultipleImplicitConstructors ) const { return true; }
bool operator!=( MultipleImplicitConstructors ) const { return true; }
bool operator<( MultipleImplicitConstructors ) const { return true; }
bool operator<=( MultipleImplicitConstructors ) const { return true; }
bool operator>( MultipleImplicitConstructors ) const { return true; }
bool operator>=( MultipleImplicitConstructors ) const { return true; }
};
}
TEST_CASE("#2571 - tests compile types that have multiple implicit constructors from lit 0",
"[compilation][approvals]") {
MultipleImplicitConstructors mic1( 0.0 );
MultipleImplicitConstructors mic2( 0.0 );
REQUIRE( mic1 == mic2 );
REQUIRE( mic1 != mic2 );
REQUIRE( mic1 < mic2 );
REQUIRE( mic1 <= mic2 );
REQUIRE( mic1 > mic2 );
REQUIRE( mic1 >= mic2 );
}