diff --git a/include/stdx/compiler.hpp b/include/stdx/compiler.hpp index a47159d..b9d63ff 100644 --- a/include/stdx/compiler.hpp +++ b/include/stdx/compiler.hpp @@ -67,10 +67,26 @@ #endif #define STDX_DO_PRAGMA(X) _Pragma(#X) -#ifdef __clang__ +#if defined(__clang__) #define STDX_PRAGMA(X) STDX_DO_PRAGMA(clang X) #else #define STDX_PRAGMA(X) STDX_DO_PRAGMA(GCC X) #endif +#ifndef STDX_DELETED +#if __cpp_deleted_function >= 202403L +#if defined(__clang__) +#define STDX_DELETED(R) \ + STDX_PRAGMA(diagnostic push) \ + STDX_PRAGMA(diagnostic ignored "-Wunknown-warning-option") \ + STDX_PRAGMA(diagnostic ignored "-Wc++26-extensions") = \ + delete (R)STDX_PRAGMA(diagnostic pop) +#else +#define STDX_DELETED(R) = delete (R) +#endif +#else +#define STDX_DELETED(R) = delete +#endif +#endif + // NOLINTEND(cppcoreguidelines-macro-usage) diff --git a/include/stdx/rollover.hpp b/include/stdx/rollover.hpp index 1f52c93..3f9886c 100644 --- a/include/stdx/rollover.hpp +++ b/include/stdx/rollover.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -77,10 +78,26 @@ template struct rollover_t { return not(lhs == rhs); } - friend constexpr auto operator<(rollover_t, rollover_t) -> bool = delete; - friend constexpr auto operator<=(rollover_t, rollover_t) -> bool = delete; - friend constexpr auto operator>(rollover_t, rollover_t) -> bool = delete; - friend constexpr auto operator>=(rollover_t, rollover_t) -> bool = delete; + friend constexpr auto operator<(rollover_t, rollover_t) + -> bool STDX_DELETED( + "Comparison operators on rollover_t are deleted because " + "they are non-transitive. If you know your data is safe, " + "you can use cmp_less(rollover_t, rollover_t)."); + friend constexpr auto operator<=(rollover_t, rollover_t) + -> bool STDX_DELETED( + "Comparison operators on rollover_t are deleted because " + "they are non-transitive. If you know your data is safe, " + "you can use cmp_less(rollover_t, rollover_t)."); + friend constexpr auto operator>(rollover_t, rollover_t) + -> bool STDX_DELETED( + "Comparison operators on rollover_t are deleted because " + "they are non-transitive. If you know your data is safe, " + "you can use cmp_less(rollover_t, rollover_t)."); + friend constexpr auto operator>=(rollover_t, rollover_t) + -> bool STDX_DELETED( + "Comparison operators on rollover_t are deleted because " + "they are non-transitive. If you know your data is safe, " + "you can use cmp_less(rollover_t, rollover_t)."); [[nodiscard]] friend constexpr auto cmp_less(rollover_t lhs, rollover_t rhs) -> bool { diff --git a/test/fail/CMakeLists.txt b/test/fail/CMakeLists.txt index 10026c8..15a8f08 100644 --- a/test/fail/CMakeLists.txt +++ b/test/fail/CMakeLists.txt @@ -27,36 +27,7 @@ add_fail_tests( template_for_each_not_list to_address_undefined_on_function) -function(add_formatted_error_tests) - add_fail_tests(ct_check) - add_fail_tests(static_assert) - add_fail_tests(static_assert_format) -endfunction() - -function(add_26_formatted_error_tests) - add_compile_fail_test("static_assert.cpp" NAME static_assert_26 LIBRARIES - stdx) - add_compile_fail_test("static_assert_format.cpp" NAME - static_assert_format_26 LIBRARIES stdx) - target_compile_features(EXPECT_FAIL.static_assert_26 PRIVATE cxx_std_26) - target_compile_features(EXPECT_FAIL.static_assert_format_26 - PRIVATE cxx_std_26) -endfunction() - if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 20) - if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" - AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 15) - add_formatted_error_tests() - endif() - if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION} - VERSION_GREATER_EQUAL 13.2) - add_formatted_error_tests() - endif() - - if("cxx_std_26" IN_LIST CMAKE_CXX_COMPILE_FEATURES) - add_26_formatted_error_tests() - endif() - add_fail_tests( atomic_bool_dec ct_format_mismatch @@ -69,3 +40,32 @@ if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 20) tuple_spaceship_with_element tuple_type_not_found) endif() + +function(add_test_by_compiler CPP_NAME CXX_VERSION COMPILER_ID COMPILER_VERSION) + if("cxx_std_${CXX_VERSION}" IN_LIST CMAKE_CXX_COMPILE_FEATURES) + if(${CMAKE_CXX_COMPILER_ID} STREQUAL "${COMPILER_ID}" + AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL + ${COMPILER_VERSION}) + set(TEST_NAME "${CPP_NAME}_${COMPILER_ID}_${COMPILER_VERSION}") + add_compile_fail_test("${CPP_NAME}.cpp" NAME ${TEST_NAME} LIBRARIES + stdx) + target_compile_features("EXPECT_FAIL.${TEST_NAME}" + PRIVATE "cxx_std_${CXX_VERSION}") + endif() + endif() +endfunction() + +add_test_by_compiler(ct_check 20 Clang 15) +add_test_by_compiler(ct_check 20 GNU 13.2) +add_test_by_compiler(static_assert 20 Clang 15) +add_test_by_compiler(static_assert 20 GNU 13.2) +add_test_by_compiler(static_assert_format 20 Clang 15) +add_test_by_compiler(static_assert_format 20 GNU 13.2) + +add_test_by_compiler(static_assert 26 Clang 17) +add_test_by_compiler(static_assert 26 GNU 14) +add_test_by_compiler(static_assert_format 26 Clang 17) +add_test_by_compiler(static_assert_format 26 GNU 14) + +add_test_by_compiler(rollover_less_than_26 26 Clang 19) +add_test_by_compiler(rollover_less_than_26 26 GNU 15) diff --git a/test/fail/rollover_less_than_26.cpp b/test/fail/rollover_less_than_26.cpp new file mode 100644 index 0000000..faa2153 --- /dev/null +++ b/test/fail/rollover_less_than_26.cpp @@ -0,0 +1,8 @@ +#include + +// EXPECT: deleted because they are non-transitive + +auto main() -> int { + using X = stdx::rollover_t; + [[maybe_unused]] auto cmp = X{} < X{1u}; +}