Skip to content

Commit 291c502

Browse files
committed
Fix old GCC + types with ambiguous constructor from 0
Closes catchorg#2571
1 parent ae1644e commit 291c502

File tree

2 files changed

+78
-51
lines changed

2 files changed

+78
-51
lines changed

src/catch2/internal/catch_decomposer.hpp

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <catch2/internal/catch_meta.hpp>
1414
#include <catch2/internal/catch_compare_traits.hpp>
1515
#include <catch2/internal/catch_test_failure_exception.hpp>
16+
#include <catch2/internal/catch_logical_traits.hpp>
1617

1718
#include <type_traits>
1819
#include <iosfwd>
@@ -168,109 +169,109 @@ namespace Catch {
168169
template < \
169170
typename RhsT, \
170171
std::enable_if_t< \
171-
Detail::is_##id##_comparable<LhsT, RhsT>::value && \
172-
!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, \
172+
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
173+
Detail::negation<std::is_arithmetic< \
174+
std::remove_reference_t<RhsT>>>>::value, \
173175
int> = 0> \
174176
friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
175177
->BinaryExpr<LhsT, RhsT const&> { \
176178
return { \
177179
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
178180
} \
179-
template < \
180-
typename RhsT, \
181-
std::enable_if_t<Detail::is_##id##_comparable<LhsT, RhsT>::value && \
182-
std::is_arithmetic<RhsT>::value, \
183-
int> = 0> \
181+
template <typename RhsT, \
182+
std::enable_if_t<Detail::conjunction< \
183+
Detail::is_##id##_comparable<LhsT, RhsT>, \
184+
std::is_arithmetic<RhsT>>::value, \
185+
int> = 0> \
184186
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
185187
->BinaryExpr<LhsT, RhsT> { \
186188
return { \
187189
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
188190
} \
189191
template < \
190192
typename RhsT, \
191-
std::enable_if_t<!Detail::is_##id##_comparable<LhsT, RhsT>::value && \
192-
Detail::is_eq_0_comparable<LhsT>:: \
193-
value && /* We allow long because we want \
194-
`ptr op NULL to be accepted */ \
195-
( std::is_same<RhsT, int>::value || \
196-
std::is_same<RhsT, long>::value ), \
197-
int> = 0> \
193+
std::enable_if_t< \
194+
Detail::conjunction< \
195+
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
196+
Detail::is_eq_0_comparable<LhsT>, \
197+
Detail::disjunction<std::is_same<RhsT, int>, \
198+
/* On some platforms `NULL` is a long */ \
199+
std::is_same<RhsT, long>>>::value, \
200+
int> = 0> \
198201
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
199202
->BinaryExpr<LhsT, RhsT> { \
200-
if ( rhs != 0 ) { \
201-
throw_test_failure_exception(); \
202-
} \
203+
if ( rhs != 0 ) { throw_test_failure_exception(); } \
203204
return { \
204205
static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
205206
} \
206207
template < \
207208
typename RhsT, \
208-
std::enable_if_t<!Detail::is_##id##_comparable<LhsT, RhsT>::value && \
209-
Detail::is_eq_0_comparable<RhsT>:: \
210-
value && /* We allow long because we want \
211-
`ptr op NULL` to be accepted */ \
212-
( std::is_same<LhsT, int>::value || \
213-
std::is_same<LhsT, long>::value ), \
214-
int> = 0> \
209+
std::enable_if_t< \
210+
Detail::conjunction< \
211+
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
212+
Detail::is_eq_0_comparable<RhsT>, \
213+
Detail::disjunction<std::is_same<LhsT, int>, \
214+
/* On some platforms `NULL` is a long */ \
215+
std::is_same<LhsT, long>>>::value, \
216+
int> = 0> \
215217
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
216218
->BinaryExpr<LhsT, RhsT> { \
217-
if ( lhs.m_lhs != 0 ) { \
218-
throw_test_failure_exception(); \
219-
} \
219+
if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
220220
return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
221221
}
222222
CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == )
223223
CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != )
224224

225-
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
225+
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
226226

227-
#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
227+
#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
228228
template < \
229229
typename RhsT, \
230230
std::enable_if_t< \
231-
Detail::is_##id##_comparable<LhsT, RhsT>::value && \
232-
!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, \
231+
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
232+
Detail::negation<std::is_arithmetic< \
233+
std::remove_reference_t<RhsT>>>>::value, \
233234
int> = 0> \
234235
friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
235236
->BinaryExpr<LhsT, RhsT const&> { \
236237
return { \
237238
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
238239
} \
239-
template < \
240-
typename RhsT, \
241-
std::enable_if_t<Detail::is_##id##_comparable<LhsT, RhsT>::value && \
242-
std::is_arithmetic<RhsT>::value, \
243-
int> = 0> \
240+
template <typename RhsT, \
241+
std::enable_if_t<Detail::conjunction< \
242+
Detail::is_##id##_comparable<LhsT, RhsT>, \
243+
std::is_arithmetic<RhsT>>::value, \
244+
int> = 0> \
244245
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
245246
->BinaryExpr<LhsT, RhsT> { \
246247
return { \
247248
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
248249
} \
249250
template < \
250251
typename RhsT, \
251-
std::enable_if_t<!Detail::is_##id##_comparable<LhsT, RhsT>::value && \
252-
Detail::is_##id##_0_comparable<LhsT>::value && \
253-
std::is_same<RhsT, int>::value, \
254-
int> = 0> \
252+
std::enable_if_t< \
253+
Detail::conjunction< \
254+
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
255+
Detail::is_##id##_0_comparable<LhsT>, \
256+
std::is_same<RhsT, int>>::value, \
257+
int> = 0> \
255258
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
256259
->BinaryExpr<LhsT, RhsT> { \
257-
if ( rhs != 0 ) { \
258-
throw_test_failure_exception(); \
259-
} \
260+
if ( rhs != 0 ) { throw_test_failure_exception(); } \
260261
return { \
261262
static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
262263
} \
263264
template < \
264265
typename RhsT, \
265-
std::enable_if_t<!Detail::is_##id##_comparable<LhsT, RhsT>::value && \
266-
Detail::is_##id##_0_comparable<RhsT>::value && \
267-
std::is_same<LhsT, int>::value, \
268-
int> = 0> \
266+
std::enable_if_t< \
267+
Detail::conjunction< \
268+
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
269+
Detail::is_##id##_0_comparable<RhsT>, \
270+
std::is_same<LhsT, int>>::value, \
271+
int> = 0> \
269272
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
270273
->BinaryExpr<LhsT, RhsT> { \
271-
if ( lhs.m_lhs != 0 ) { \
272-
throw_test_failure_exception(); \
273-
} \
274+
if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
274275
return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
275276
}
276277

@@ -279,7 +280,7 @@ namespace Catch {
279280
CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > )
280281
CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= )
281282

282-
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR
283+
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR
283284

284285

285286
#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(op) \

tests/SelfTest/UsageTests/Compilation.tests.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,3 +329,29 @@ TEST_CASE( "#2555 - types that can only be compared with 0 literal (not int/long
329329
REQUIRE( TypeWithLit0Comparisons{} != 0 );
330330
REQUIRE_FALSE( 0 != TypeWithLit0Comparisons{} );
331331
}
332+
333+
namespace {
334+
struct MultipleImplicitConstructors {
335+
MultipleImplicitConstructors( double ) {}
336+
MultipleImplicitConstructors( int64_t ) {}
337+
338+
bool operator==( MultipleImplicitConstructors ) const { return true; }
339+
bool operator!=( MultipleImplicitConstructors ) const { return true; }
340+
bool operator<( MultipleImplicitConstructors ) const { return true; }
341+
bool operator<=( MultipleImplicitConstructors ) const { return true; }
342+
bool operator>( MultipleImplicitConstructors ) const { return true; }
343+
bool operator>=( MultipleImplicitConstructors ) const { return true; }
344+
};
345+
}
346+
347+
TEST_CASE("#2571 - tests compile types that have multiple implicit constructors from lit 0",
348+
"[compilation][approvals]") {
349+
MultipleImplicitConstructors mic1( 0.0 );
350+
MultipleImplicitConstructors mic2( 0.0 );
351+
REQUIRE( mic1 == mic2 );
352+
REQUIRE( mic1 != mic2 );
353+
REQUIRE( mic1 < mic2 );
354+
REQUIRE( mic1 <= mic2 );
355+
REQUIRE( mic1 > mic2 );
356+
REQUIRE( mic1 >= mic2 );
357+
}

0 commit comments

Comments
 (0)