From c1cbb41b428f15e53454682a45f03ea31f1da0a7 Mon Sep 17 00:00:00 2001 From: Tushar Maheshwari Date: Thu, 13 May 2021 23:22:09 +0530 Subject: [PATCH 01/24] Fix iPhone simulator CI (#981) * Run iOS simulator CI * Fix link errors - scope function linkage using anonymous namespace * Update noexcept test for consistency --- .github/workflows/ios.yml | 6 +-- tests/CMakeLists.txt | 73 +++++++++++------------------ tests/no_exception_ensure_tests.cpp | 7 +++ tests/notnull_tests.cpp | 7 ++- tests/strict_notnull_tests.cpp | 10 ++-- 5 files changed, 47 insertions(+), 56 deletions(-) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 9d29bbc..0ef9fa3 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -25,11 +25,11 @@ jobs: -GXcode \ -DCMAKE_SYSTEM_NAME=iOS \ "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=8 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=9 \ -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \ "-DMACOSX_BUNDLE_GUI_IDENTIFIER=GSL.\$(EXECUTABLE_NAME)" \ - -DMACOSX_BUNDLE_BUNDLE_VERSION=3.0.1 \ - -DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.0.1 \ + -DMACOSX_BUNDLE_BUNDLE_VERSION=3.1.0 \ + -DMACOSX_BUNDLE_SHORT_VERSION_STRING=3.1.0 \ .. - name: Build diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 368ce75..c05aaa7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ include(ExternalProject) set_property(GLOBAL PROPERTY USE_FOLDERS ON) if(IOS) - add_compile_definitions(GTEST_HAS_DEATH_TEST=1) + add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1) endif() pkg_search_module(GTestMain gtest_main) @@ -164,36 +164,27 @@ target_include_directories(gsl_tests_config SYSTEM INTERFACE googletest/googletest/include ) -set_property(TARGET PROPERTY FOLDER "GSL_tests") - -function(add_gsl_test name) - add_executable(${name} ${name}.cpp) - target_link_libraries(${name} - Microsoft.GSL::GSL - gsl_tests_config - ${GTestMain_LIBRARIES} - ) - add_test( - ${name} - ${name} - ) - # group all tests under GSL_tests - set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests") -endfunction() - -add_gsl_test(span_tests) -add_gsl_test(span_ext_tests) -add_gsl_test(span_compatibility_tests) -add_gsl_test(string_span_tests) -add_gsl_test(at_tests) -add_gsl_test(notnull_tests) -add_gsl_test(assertion_tests) -add_gsl_test(utils_tests) -add_gsl_test(owner_tests) -add_gsl_test(byte_tests) -add_gsl_test(algorithm_tests) -add_gsl_test(strict_notnull_tests) +add_executable(gsl_tests + algorithm_tests.cpp + assertion_tests.cpp + at_tests.cpp + byte_tests.cpp + notnull_tests.cpp + owner_tests.cpp + span_compatibility_tests.cpp + span_ext_tests.cpp + span_tests.cpp + strict_notnull_tests.cpp + string_span_tests.cpp + utils_tests.cpp +) +target_link_libraries(gsl_tests + Microsoft.GSL::GSL + gsl_tests_config + ${GTestMain_LIBRARIES} +) +add_test(gsl_tests gsl_tests) # No exception tests @@ -268,19 +259,9 @@ else() ) endif(MSVC) -function(add_gsl_test_noexcept name) - add_executable(${name} ${name}.cpp) - target_link_libraries(${name} - Microsoft.GSL::GSL - gsl_tests_config_noexcept - ${GTestMain_LIBRARIES} - ) - add_test( - ${name} - ${name} - ) - # group all tests under GSL_tests_noexcept - set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests_noexcept") -endfunction() - -add_gsl_test_noexcept(no_exception_ensure_tests) +add_executable(gsl_noexcept_tests no_exception_ensure_tests.cpp) +target_link_libraries(gsl_noexcept_tests + Microsoft.GSL::GSL + gsl_tests_config_noexcept +) +add_test(gsl_noexcept_tests gsl_noexcept_tests) diff --git a/tests/no_exception_ensure_tests.cpp b/tests/no_exception_ensure_tests.cpp index 2ec0ebb..5fde41c 100644 --- a/tests/no_exception_ensure_tests.cpp +++ b/tests/no_exception_ensure_tests.cpp @@ -14,8 +14,11 @@ // /////////////////////////////////////////////////////////////////////////////// +#include #include // for std::exit #include // for span +#include +#include int operator_subscript_no_throw() noexcept { @@ -42,6 +45,10 @@ void setup_termination_handler() noexcept int main() noexcept { + std::cout << "Running main() from " __FILE__ "\n"; +#if defined(IOS_PROCESS_DELAY_WORKAROUND) + std::this_thread::sleep_for(std::chrono::seconds(1)); +#endif setup_termination_handler(); operator_subscript_no_throw(); return -1; diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index b95bb01..d4258e8 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -29,8 +29,8 @@ using namespace gsl; namespace { -static constexpr char deathstring[] = "Expected Death"; -} //namespace +constexpr char deathstring[] = "Expected Death"; +} // namespace struct MyBase { @@ -118,12 +118,15 @@ struct NonCopyableNonMovable NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; }; +namespace +{ GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool helper(not_null p) { return *p == 12; } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool helper_const(not_null p) { return *p == 12; } int* return_pointer() { return nullptr; } +} // namespace TEST(notnull_tests, TestNotNullConstructors) { diff --git a/tests/strict_notnull_tests.cpp b/tests/strict_notnull_tests.cpp index 3cf6911..9de2760 100644 --- a/tests/strict_notnull_tests.cpp +++ b/tests/strict_notnull_tests.cpp @@ -17,13 +17,10 @@ #include #include // for not_null, operator<, operator<=, operator> -namespace gsl -{ -struct fail_fast; -} // namespace gsl - using namespace gsl; +namespace +{ GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool helper(not_null p) { return *p == 12; } @@ -36,8 +33,11 @@ bool strict_helper(strict_not_null p) { return *p == 12; } GSL_SUPPRESS(f.4) // NO-FORMAT: attribute bool strict_helper_const(strict_not_null p) { return *p == 12; } +#ifdef CONFIRM_COMPILATION_ERRORS int* return_pointer() { return nullptr; } const int* return_pointer_const() { return nullptr; } +#endif +} // namespace TEST(strict_notnull_tests, TestStrictNotNull) { From b26f6d5ec7b043f9d459c1dfdd6da4d930d4e9b4 Mon Sep 17 00:00:00 2001 From: "Jordan Maples [MSFT]" <49793787+JordanMaples@users.noreply.github.com> Date: Thu, 20 May 2021 18:18:08 -0700 Subject: [PATCH 02/24] gsl::at behavior change regarding gsl::span (#985) * move span specialization of 'at' to and update the parameter to be taken by reference * undid previous changes and acted upon decisions made in maintainer sync. Fixed tests failing in /kernel mode * ran clang-format on the include folder * ran clang-format on the test folder Co-authored-by: Jordan Maples --- include/gsl/assert | 1 + include/gsl/gsl_algorithm | 3 +- include/gsl/narrow | 2 +- include/gsl/pointers | 17 +- include/gsl/span | 15 +- include/gsl/span_ext | 23 +- include/gsl/util | 24 +- tests/algorithm_tests.cpp | 22 +- tests/assertion_tests.cpp | 13 +- tests/at_tests.cpp | 89 +- tests/byte_tests.cpp | 6 +- tests/deathTestCommon.h | 11 + tests/notnull_tests.cpp | 69 +- tests/owner_tests.cpp | 6 +- tests/span_compatibility_tests.cpp | 2 +- tests/span_ext_tests.cpp | 473 ++++---- tests/span_tests.cpp | 1608 ++++++++++++++-------------- tests/strict_notnull_tests.cpp | 29 +- tests/string_span_tests.cpp | 55 +- tests/utils_tests.cpp | 11 +- 20 files changed, 1304 insertions(+), 1175 deletions(-) create mode 100644 tests/deathTestCommon.h diff --git a/include/gsl/assert b/include/gsl/assert index 0cc54f6..a601204 100644 --- a/include/gsl/assert +++ b/include/gsl/assert @@ -22,6 +22,7 @@ // Currently terminate is a no-op in this mode, so we add termination behavior back // #if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)) +#define GSL_KERNEL_MODE #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND #include diff --git a/include/gsl/gsl_algorithm b/include/gsl/gsl_algorithm index 9f1dd50..303a5ae 100644 --- a/include/gsl/gsl_algorithm +++ b/include/gsl/gsl_algorithm @@ -1,3 +1,4 @@ #pragma once -#pragma message("This header will soon be removed. Use instead of ") +#pragma message( \ + "This header will soon be removed. Use instead of ") #include diff --git a/include/gsl/narrow b/include/gsl/narrow index d47d9fd..67aac05 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -30,7 +30,7 @@ template // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) -// clang-format on + // clang-format on constexpr T narrow(U u) noexcept(false) { constexpr const bool is_different_signedness = diff --git a/include/gsl/pointers b/include/gsl/pointers index 2f1b15f..e6b2348 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -34,12 +34,19 @@ namespace gsl namespace details { -template -struct is_comparable_to_nullptr : std::false_type {}; + template + struct is_comparable_to_nullptr : std::false_type + { + }; -template -struct is_comparable_to_nullptr() != nullptr), bool>::value>> : std::true_type {}; -} // namespace details + template + struct is_comparable_to_nullptr< + T, + std::enable_if_t() != nullptr), bool>::value>> + : std::true_type + { + }; +} // namespace details // // GSL.owner: ownership pointers diff --git a/include/gsl/span b/include/gsl/span index 506eb4c..cc8a7b9 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -21,10 +21,11 @@ #include // for byte #include // for narrow_cast -#include // for array -#include // for ptrdiff_t, size_t, nullptr_t -#include // for reverse_iterator, distance, random_access_... -#include // for enable_if_t, declval, is_convertible, inte... +#include // for array +#include // for ptrdiff_t, size_t, nullptr_t +#include // for span specialization of gsl::at and other span-related extensions +#include // for reverse_iterator, distance, random_access_... +#include // for enable_if_t, declval, is_convertible, inte... #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) @@ -60,12 +61,6 @@ namespace gsl { -// [views.constants], constants -constexpr const std::size_t dynamic_extent = narrow_cast(-1); - -template -class span; - // implementation details namespace details { diff --git a/include/gsl/span_ext b/include/gsl/span_ext index b7c12cf..5feb2b8 100644 --- a/include/gsl/span_ext +++ b/include/gsl/span_ext @@ -27,16 +27,29 @@ // /////////////////////////////////////////////////////////////////////////////// -#include // for span -#include // for narrow_cast, narrow +#include // GSL_KERNEL_MODE +#include // for narrow_cast, narrow -#include // for lexicographical_compare -#include // for ptrdiff_t, size_t +#include // for ptrdiff_t, size_t #include +#ifndef GSL_KERNEL_MODE +#include // for lexicographical_compare +#endif // GSL_KERNEL_MODE + namespace gsl { +// [span.views.constants], constants +constexpr const std::size_t dynamic_extent = narrow_cast(-1); + +template +class span; + +// std::equal and std::lexicographical_compare are not /kernel compatible +// so all comparison operators must be removed for kernel mode. +#ifndef GSL_KERNEL_MODE + // [span.comparison], span comparison operators template constexpr bool operator==(span l, span r) @@ -74,6 +87,8 @@ constexpr bool operator>=(span l, span return !(l < r); } +#endif // GSL_KERNEL_MODE + // // make_span() - Utility functions for creating spans // diff --git a/include/gsl/util b/include/gsl/util index 2d67b7f..db66aae 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -25,6 +25,10 @@ #include // for is_signed, integral_constant #include // for exchange, forward +#if defined(__cplusplus) && __cplusplus >= 202002L +#include +#endif // __cplusplus >= 202002L + #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) @@ -92,8 +96,8 @@ finally(F&& f) noexcept template // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute -// clang-format on -constexpr T narrow_cast(U&& u) noexcept + // clang-format on + constexpr T narrow_cast(U&& u) noexcept { return static_cast(std::forward(u)); } @@ -105,7 +109,7 @@ template // clang-format off GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute -// clang-format on + // clang-format on constexpr T& at(T (&arr)[N], const index i) { Expects(i >= 0 && i < narrow_cast(N)); @@ -116,7 +120,7 @@ template // clang-format off GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute -// clang-format on + // clang-format on constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) { Expects(i >= 0 && i < narrow_cast(cont.size())); @@ -127,13 +131,21 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute template // clang-format off GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute -// clang-format on -constexpr T at(const std::initializer_list cont, const index i) + // clang-format on + constexpr T at(const std::initializer_list cont, const index i) { Expects(i >= 0 && i < narrow_cast(cont.size())); return *(cont.begin() + i); } +#if defined(__cplusplus) && __cplusplus >= 202002L +template +constexpr auto at(std::span sp, const index i) +{ + Expects(i >= 0 && i < narrow_cast(sp.size())); + return sp[i]; +} +#endif // __cplusplus >= 202002L } // namespace gsl #if defined(_MSC_VER) && !defined(__clang__) diff --git a/tests/algorithm_tests.cpp b/tests/algorithm_tests.cpp index 0f209ac..16746b4 100644 --- a/tests/algorithm_tests.cpp +++ b/tests/algorithm_tests.cpp @@ -14,16 +14,13 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include // for array +#include // for size_t #include // for copy -#include // for span -#include // for array -#include // for size_t +#include // for span +#include -namespace -{ - static constexpr char deathstring[] = "Expected Death"; -} +#include "deathTestCommon.h" namespace gsl { @@ -204,10 +201,11 @@ TEST(algorithm_tests, incompatible_type) TEST(algorithm_tests, small_destination_span) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. small_destination_span"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); std::array src{1, 2, 3, 4}; std::array dst{}; @@ -217,9 +215,9 @@ TEST(algorithm_tests, small_destination_span) const span dst_span_dyn(dst); const span dst_span_static(dst); - EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), deathstring); - EXPECT_DEATH(copy(src_span_dyn, dst_span_static), deathstring); - EXPECT_DEATH(copy(src_span_static, dst_span_dyn), deathstring); + EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), expected); + EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected); + EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected); #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); diff --git a/tests/assertion_tests.cpp b/tests/assertion_tests.cpp index 6b5fb0b..dd3ca06 100644 --- a/tests/assertion_tests.cpp +++ b/tests/assertion_tests.cpp @@ -14,14 +14,14 @@ // /////////////////////////////////////////////////////////////////////////////// -#include +#include "deathTestCommon.h" #include // for fail_fast (ptr only), Ensures, Expects +#include using namespace gsl; namespace { -static constexpr char deathstring[] = "Expected Death"; int f(int i) { @@ -39,23 +39,22 @@ int g(int i) TEST(assertion_tests, expects) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. expects"; std::abort(); }); EXPECT_TRUE(f(2) == 2); - EXPECT_DEATH(f(10), deathstring); + EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler)); } - TEST(assertion_tests, ensures) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. ensures"; std::abort(); }); EXPECT_TRUE(g(2) == 3); - EXPECT_DEATH(g(9), deathstring); + EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler)); } diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index 1285139..92a8e4d 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -22,31 +22,33 @@ #include // for size_t #include // for initializer_list #include // for vector +#if defined(__cplusplus) && __cplusplus >= 202002L +#include +#endif // __cplusplus >= 202002L -namespace -{ - static constexpr char deathstring[] = "Expected Death"; -} +#include "deathTestCommon.h" TEST(at_tests, static_array) { int a[4] = {1, 2, 3, 4}; const int(&c_a)[4] = a; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { EXPECT_TRUE(&gsl::at(a, i) == &a[i]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. static_array"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); - EXPECT_DEATH(gsl::at(a, -1), deathstring); - EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); - EXPECT_DEATH(gsl::at(c_a, 4), deathstring); + EXPECT_DEATH(gsl::at(a, -1), expected); + EXPECT_DEATH(gsl::at(a, 4), expected); + EXPECT_DEATH(gsl::at(c_a, -1), expected); + EXPECT_DEATH(gsl::at(c_a, 4), expected); } TEST(at_tests, std_array) @@ -54,20 +56,22 @@ TEST(at_tests, std_array) std::array a = {1, 2, 3, 4}; const std::array& c_a = a; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast(i)]); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. std_array"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); - EXPECT_DEATH(gsl::at(a, -1), deathstring); - EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); - EXPECT_DEATH(gsl::at(c_a, 4), deathstring); + EXPECT_DEATH(gsl::at(a, -1), expected); + EXPECT_DEATH(gsl::at(a, 4), expected); + EXPECT_DEATH(gsl::at(c_a, -1), expected); + EXPECT_DEATH(gsl::at(c_a, 4), expected); } TEST(at_tests, std_vector) @@ -75,42 +79,68 @@ TEST(at_tests, std_vector) std::vector a = {1, 2, 3, 4}; const std::vector& c_a = a; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast(i)]); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. std_vector"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); - EXPECT_DEATH(gsl::at(a, -1), deathstring); - EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at(c_a, -1), deathstring); - EXPECT_DEATH(gsl::at(c_a, 4), deathstring); + EXPECT_DEATH(gsl::at(a, -1), expected); + EXPECT_DEATH(gsl::at(a, 4), expected); + EXPECT_DEATH(gsl::at(c_a, -1), expected); + EXPECT_DEATH(gsl::at(c_a, 4), expected); } TEST(at_tests, InitializerList) { const std::initializer_list a = {1, 2, 3, 4}; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { EXPECT_TRUE(gsl::at(a, i) == i + 1); EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. InitializerList"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); - EXPECT_DEATH(gsl::at(a, -1), deathstring); - EXPECT_DEATH(gsl::at(a, 4), deathstring); - EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring); - EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring); + EXPECT_DEATH(gsl::at(a, -1), expected); + EXPECT_DEATH(gsl::at(a, 4), expected); + EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected); + EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected); } +#if defined(__cplusplus) && __cplusplus >= 202002L +TEST(at_tests, std_span) +{ + std::vector vec{1, 2, 3, 4, 5}; + std::span sp{vec}; + + std::vector cvec{1, 2, 3, 4, 5}; + std::span csp{cvec}; + + for (size_t i = 0, i < vec.size(); ++i) + { + EXPECT_TRUE(&gsl::at(sp, i) == &vec[i]); + EXPECT_TRUE(&gsl::at(csp, i) == &cvec[i]); + } + + EXPECT_DEATH(gsl::at(sp, -1), expected); + EXPECT_DEATH(gsl::at(sp, sp.size()), expected); + EXPECT_DEATH(gsl::at(csp, -1), expected); + EXPECT_DEATH(gsl::at(csp, sp.size()), expected); +} +#endif // __cplusplus >= 202002L + #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 static constexpr bool test_constexpr() { @@ -119,7 +149,8 @@ static constexpr bool test_constexpr() std::array a2 = {1, 2, 3, 4}; const std::array& c_a2 = a2; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { if (&gsl::at(a1, i) != &a1[i]) return false; if (&gsl::at(c_a1, i) != &a1[i]) return false; // requires C++17: diff --git a/tests/byte_tests.cpp b/tests/byte_tests.cpp index 2a86cac..4432fc9 100644 --- a/tests/byte_tests.cpp +++ b/tests/byte_tests.cpp @@ -37,7 +37,9 @@ TEST(byte_tests, construction) EXPECT_TRUE(static_cast(b) == 4); } + // clang-format off GSL_SUPPRESS(es.49) + // clang-format on { const byte b = byte(12); EXPECT_TRUE(static_cast(b) == 12); @@ -55,7 +57,7 @@ TEST(byte_tests, construction) #if defined(__cplusplus) && (__cplusplus >= 201703L) { - const byte b { 14 }; + const byte b{14}; EXPECT_TRUE(static_cast(b) == 14); } #endif @@ -122,7 +124,7 @@ TEST(byte_tests, aliasing) EXPECT_TRUE(res == i); } -} +} // namespace #ifdef CONFIRM_COMPILATION_ERRORS copy(src_span_static, dst_span_static); diff --git a/tests/deathTestCommon.h b/tests/deathTestCommon.h new file mode 100644 index 0000000..7bf2423 --- /dev/null +++ b/tests/deathTestCommon.h @@ -0,0 +1,11 @@ +#pragma once +#include + +constexpr char deathstring[] = "Expected Death"; +constexpr char failed_set_terminate_deathstring[] = ".*"; + +// This prevents a failed call to set_terminate from failing the test suite. +constexpr const char* GetExpectedDeathString(std::terminate_handler handle) +{ + return handle ? deathstring : failed_set_terminate_deathstring; +} diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index d4258e8..db22c72 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -25,13 +25,9 @@ #include // for basic_string, operator==, string, operator<< #include // for type_info +#include "deathTestCommon.h" using namespace gsl; -namespace -{ -constexpr char deathstring[] = "Expected Death"; -} // namespace - struct MyBase { }; @@ -64,7 +60,9 @@ struct CustomPtr template std::string operator==(CustomPtr const& lhs, CustomPtr const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast(lhs.p_) == reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -72,7 +70,9 @@ std::string operator==(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator!=(CustomPtr const& lhs, CustomPtr const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast(lhs.p_) != reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -80,7 +80,9 @@ std::string operator!=(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator<(CustomPtr const& lhs, CustomPtr const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast(lhs.p_) < reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -88,7 +90,9 @@ std::string operator<(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator>(CustomPtr const& lhs, CustomPtr const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast(lhs.p_) > reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -96,7 +100,9 @@ std::string operator>(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator<=(CustomPtr const& lhs, CustomPtr const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast(lhs.p_) <= reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -104,7 +110,9 @@ std::string operator<=(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator>=(CustomPtr const& lhs, CustomPtr const& rhs) { + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on return reinterpret_cast(lhs.p_) >= reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -120,9 +128,13 @@ struct NonCopyableNonMovable namespace { -GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format off +GSL_SUPPRESS(f .4) // NO-FORMAT: attribute +// clang-format on bool helper(not_null p) { return *p == 12; } -GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format off +GSL_SUPPRESS(f .4) // NO-FORMAT: attribute +// clang-format on bool helper_const(not_null p) { return *p == 12; } int* return_pointer() { return nullptr; } @@ -145,10 +157,12 @@ TEST(notnull_tests, TestNotNullConstructors) #endif } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestNotNullConstructors"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + { // from shared pointer int i = 12; @@ -160,7 +174,7 @@ TEST(notnull_tests, TestNotNullConstructors) std::make_shared(10)); // shared_ptr is nullptr assignable int* pi = nullptr; - EXPECT_DEATH((not_null(pi)), deathstring); + EXPECT_DEATH((not_null(pi)), expected); } { @@ -217,8 +231,8 @@ TEST(notnull_tests, TestNotNullConstructors) { // from returned pointer - EXPECT_DEATH(helper(return_pointer()), deathstring); - EXPECT_DEATH(helper_const(return_pointer()), deathstring); + EXPECT_DEATH(helper(return_pointer()), expected); + EXPECT_DEATH(helper_const(return_pointer()), expected); } } @@ -278,17 +292,18 @@ TEST(notnull_tests, TestNotNullCasting) TEST(notnull_tests, TestNotNullAssignment) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestNotNullAssignmentd"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); int i = 12; not_null p(&i); EXPECT_TRUE(helper(p)); int* q = nullptr; - EXPECT_DEATH(p = not_null(q), deathstring); + EXPECT_DEATH(p = not_null(q), expected); } TEST(notnull_tests, TestNotNullRawPointerComparison) @@ -437,17 +452,18 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction) EXPECT_TRUE(*x == 42); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); { auto workaround_macro = []() { int* p1 = nullptr; const not_null x{p1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { @@ -455,14 +471,14 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction) const int* p1 = nullptr; const not_null x{p1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { int* p = nullptr; - EXPECT_DEATH(helper(not_null{p}), deathstring); - EXPECT_DEATH(helper_const(not_null{p}), deathstring); + EXPECT_DEATH(helper(not_null{p}), expected); + EXPECT_DEATH(helper_const(not_null{p}), expected); } #ifdef CONFIRM_COMPILATION_ERRORS @@ -498,10 +514,11 @@ TEST(notnull_tests, TestMakeNotNull) EXPECT_TRUE(*x == 42); } - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestMakeNotNull"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); { const auto workaround_macro = []() { @@ -509,7 +526,7 @@ TEST(notnull_tests, TestMakeNotNull) const auto x = make_not_null(p1); EXPECT_TRUE(*x == 42); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { @@ -518,21 +535,21 @@ TEST(notnull_tests, TestMakeNotNull) const auto x = make_not_null(p1); EXPECT_TRUE(*x == 42); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { int* p = nullptr; - EXPECT_DEATH(helper(make_not_null(p)), deathstring); - EXPECT_DEATH(helper_const(make_not_null(p)), deathstring); + EXPECT_DEATH(helper(make_not_null(p)), expected); + EXPECT_DEATH(helper_const(make_not_null(p)), expected); } #ifdef CONFIRM_COMPILATION_ERRORS { - EXPECT_DEATH(make_not_null(nullptr), deathstring); - EXPECT_DEATH(helper(make_not_null(nullptr)), deathstring); - EXPECT_DEATH(helper_const(make_not_null(nullptr)), deathstring); + EXPECT_DEATH(make_not_null(nullptr), expected); + EXPECT_DEATH(helper(make_not_null(nullptr)), expected); + EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected); } #endif } diff --git a/tests/owner_tests.cpp b/tests/owner_tests.cpp index ca8222f..87c7cec 100644 --- a/tests/owner_tests.cpp +++ b/tests/owner_tests.cpp @@ -20,7 +20,7 @@ using namespace gsl; -GSL_SUPPRESS(f.23) // NO-FORMAT: attribute +GSL_SUPPRESS(f .23) // NO-FORMAT: attribute void f(int* i) { *i += 1; } TEST(owner_tests, basic_test) @@ -34,10 +34,10 @@ TEST(owner_tests, basic_test) TEST(owner_tests, check_pointer_constraint) { - #ifdef CONFIRM_COMPILATION_ERRORS +#ifdef CONFIRM_COMPILATION_ERRORS { owner integerTest = 10; owner> sharedPtrTest(new int(10)); } - #endif +#endif } diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp index 361db84..56bd385 100644 --- a/tests/span_compatibility_tests.cpp +++ b/tests/span_compatibility_tests.cpp @@ -17,7 +17,7 @@ #include #include // for byte -#include // for span, span_iterator, operator==, operator!= +#include // for span, span_iterator, operator==, operator!= #include // for array #include // for ptrdiff_t diff --git a/tests/span_ext_tests.cpp b/tests/span_ext_tests.cpp index 4f07188..7ce4e51 100644 --- a/tests/span_ext_tests.cpp +++ b/tests/span_ext_tests.cpp @@ -16,27 +16,26 @@ #include +#include // for span and span_ext #include // for narrow_cast, at -#include // for operator==, operator!=, make_span -#include // for array -#include // for cerr -#include // for vector +#include // for array +#include // for cerr +#include // for vector using namespace std; using namespace gsl; -namespace -{ -static constexpr char deathstring[] = "Expected Death"; -} // namespace +#include "deathTestCommon.h" TEST(span_ext_test, make_span_from_pointer_length_constructor) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. from_pointer_length_constructor"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + int arr[4] = {1, 2, 3, 4}; { @@ -57,7 +56,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor) { int* p = nullptr; auto workaround_macro = [=]() { make_span(p, 2); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } } @@ -88,273 +87,275 @@ TEST(span_ext_test, make_span_from_pointer_pointer_construction) } TEST(span_ext_test, make_span_from_array_constructor) - { - int arr[5] = {1, 2, 3, 4, 5}; - int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; - int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; +{ + int arr[5] = {1, 2, 3, 4, 5}; + int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; + int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - { - const auto s = make_span(arr); - EXPECT_TRUE(s.size() == 5); - EXPECT_TRUE(s.data() == std::addressof(arr[0])); - } + { + const auto s = make_span(arr); + EXPECT_TRUE(s.size() == 5); + EXPECT_TRUE(s.data() == std::addressof(arr[0])); + } - { - const auto s = make_span(std::addressof(arr2d[0]), 1); - EXPECT_TRUE(s.size() == 1); - EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); - } + { + const auto s = make_span(std::addressof(arr2d[0]), 1); + EXPECT_TRUE(s.size() == 1); + EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); + } - { - const auto s = make_span(std::addressof(arr3d[0]), 1); - EXPECT_TRUE(s.size() == 1); - EXPECT_TRUE(s.data() == std::addressof(arr3d[0])); - } - } + { + const auto s = make_span(std::addressof(arr3d[0]), 1); + EXPECT_TRUE(s.size() == 1); + EXPECT_TRUE(s.data() == std::addressof(arr3d[0])); + } +} - TEST(span_ext_test, make_span_from_dynamic_array_constructor) - { - double(*arr)[3][4] = new double[100][3][4]; +TEST(span_ext_test, make_span_from_dynamic_array_constructor) +{ + double(*arr)[3][4] = new double[100][3][4]; - { - auto s = make_span(&arr[0][0][0], 10); - EXPECT_TRUE(s.size() == 10); - EXPECT_TRUE(s.data() == &arr[0][0][0]); - } + { + auto s = make_span(&arr[0][0][0], 10); + EXPECT_TRUE(s.size() == 10); + EXPECT_TRUE(s.data() == &arr[0][0][0]); + } - delete[] arr; - } + delete[] arr; +} - TEST(span_ext_test, make_span_from_std_array_constructor) - { - std::array arr = {1, 2, 3, 4}; +TEST(span_ext_test, make_span_from_std_array_constructor) +{ + std::array arr = {1, 2, 3, 4}; - { - auto s = make_span(arr); - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + auto s = make_span(arr); + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 - { - span s1 = make_span(arr); + // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 + { + span s1 = make_span(arr); - static span s2; - s2 = s1; + static span s2; + s2 = s1; - #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ - __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__) - // Known to be broken in gcc 6.4 and 6.5 with optimizations - // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116 - EXPECT_TRUE(s1.size() == 4); - EXPECT_TRUE(s2.size() == 0); - #else - EXPECT_TRUE(s1.size() == s2.size()); - #endif - } - } +#if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ + __GNUC_PATCHLEVEL__ == 0 && defined(__OPTIMIZE__) + // Known to be broken in gcc 6.4 and 6.5 with optimizations + // Issue in gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83116 + EXPECT_TRUE(s1.size() == 4); + EXPECT_TRUE(s2.size() == 0); +#else + EXPECT_TRUE(s1.size() == s2.size()); +#endif + } +} - TEST(span_ext_test, make_span_from_const_std_array_constructor) - { - const std::array arr = {1, 2, 3, 4}; +TEST(span_ext_test, make_span_from_const_std_array_constructor) +{ + const std::array arr = {1, 2, 3, 4}; - { - auto s = make_span(arr); - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } - } + { + auto s = make_span(arr); + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } +} - TEST(span_ext_test, make_span_from_std_array_const_constructor) - { - std::array arr = {1, 2, 3, 4}; +TEST(span_ext_test, make_span_from_std_array_const_constructor) +{ + std::array arr = {1, 2, 3, 4}; - { - auto s = make_span(arr); - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } - } + { + auto s = make_span(arr); + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } +} - TEST(span_ext_test, make_span_from_container_constructor) - { - std::vector v = {1, 2, 3}; - const std::vector cv = v; +TEST(span_ext_test, make_span_from_container_constructor) +{ + std::vector v = {1, 2, 3}; + const std::vector cv = v; - { - auto s = make_span(v); - EXPECT_TRUE(s.size() == v.size()); - EXPECT_TRUE(s.data() == v.data()); + { + auto s = make_span(v); + EXPECT_TRUE(s.size() == v.size()); + EXPECT_TRUE(s.data() == v.data()); - auto cs = make_span(cv); - EXPECT_TRUE(cs.size() == cv.size()); - EXPECT_TRUE(cs.data() == cv.data()); - } - } + auto cs = make_span(cv); + EXPECT_TRUE(cs.size() == cv.size()); + EXPECT_TRUE(cs.data() == cv.data()); + } +} - TEST(span_test, interop_with_gsl_at) - { - int arr[5] = {1, 2, 3, 4, 5}; - span s{arr}; - EXPECT_TRUE(at(s, 0) == 1); - EXPECT_TRUE(at(s, 1) == 2); - } +TEST(span_test, interop_with_gsl_at) +{ + int arr[5] = {1, 2, 3, 4, 5}; + span s{arr}; + EXPECT_TRUE(at(s, 0) == 1); + EXPECT_TRUE(at(s, 1) == 2); +} - TEST(span_ext_test, iterator_free_functions) - { - int a[] = {1, 2, 3, 4}; - span s{a}; +TEST(span_ext_test, iterator_free_functions) +{ + int a[] = {1, 2, 3, 4}; + span s{a}; - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); - EXPECT_TRUE(s.begin() == begin(s)); - EXPECT_TRUE(s.end() == end(s)); + EXPECT_TRUE(s.begin() == begin(s)); + EXPECT_TRUE(s.end() == end(s)); - EXPECT_TRUE(s.rbegin() == rbegin(s)); - EXPECT_TRUE(s.rend() == rend(s)); + EXPECT_TRUE(s.rbegin() == rbegin(s)); + EXPECT_TRUE(s.rend() == rend(s)); - EXPECT_TRUE(s.begin() == cbegin(s)); - EXPECT_TRUE(s.end() == cend(s)); + EXPECT_TRUE(s.begin() == cbegin(s)); + EXPECT_TRUE(s.end() == cend(s)); - EXPECT_TRUE(s.rbegin() == crbegin(s)); - EXPECT_TRUE(s.rend() == crend(s)); - } + EXPECT_TRUE(s.rbegin() == crbegin(s)); + EXPECT_TRUE(s.rend() == crend(s)); +} - TEST(span_ext_test, ssize_free_function) - { - int a[] = {1, 2, 3, 4}; - span s{a}; +TEST(span_ext_test, ssize_free_function) +{ + int a[] = {1, 2, 3, 4}; + span s{a}; - EXPECT_FALSE((std::is_same::value)); - EXPECT_TRUE(s.size() == static_cast(ssize(s))); - } + EXPECT_FALSE((std::is_same::value)); + EXPECT_TRUE(s.size() == static_cast(ssize(s))); +} - TEST(span_ext_test, comparison_operators) - { - { - span s1; - span s2; - EXPECT_TRUE(s1 == s2); - EXPECT_FALSE(s1 != s2); - EXPECT_FALSE(s1 < s2); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s1 >= s2); - EXPECT_TRUE(s2 == s1); - EXPECT_FALSE(s2 != s1); - EXPECT_FALSE(s2 != s1); - EXPECT_TRUE(s2 <= s1); - EXPECT_FALSE(s2 > s1); - EXPECT_TRUE(s2 >= s1); - } +#ifndef GSL_KERNEL_MODE +TEST(span_ext_test, comparison_operators) +{ + { + span s1; + span s2; + EXPECT_TRUE(s1 == s2); + EXPECT_FALSE(s1 != s2); + EXPECT_FALSE(s1 < s2); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s1 >= s2); + EXPECT_TRUE(s2 == s1); + EXPECT_FALSE(s2 != s1); + EXPECT_FALSE(s2 != s1); + EXPECT_TRUE(s2 <= s1); + EXPECT_FALSE(s2 > s1); + EXPECT_TRUE(s2 >= s1); + } - { - int arr[] = {2, 1}; - span s1 = arr; - span s2 = arr; + { + int arr[] = {2, 1}; + span s1 = arr; + span s2 = arr; - EXPECT_TRUE(s1 == s2); - EXPECT_FALSE(s1 != s2); - EXPECT_FALSE(s1 < s2); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s1 >= s2); - EXPECT_TRUE(s2 == s1); - EXPECT_FALSE(s2 != s1); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s2 <= s1); - EXPECT_FALSE(s2 > s1); - EXPECT_TRUE(s2 >= s1); - } + EXPECT_TRUE(s1 == s2); + EXPECT_FALSE(s1 != s2); + EXPECT_FALSE(s1 < s2); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s1 >= s2); + EXPECT_TRUE(s2 == s1); + EXPECT_FALSE(s2 != s1); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s2 <= s1); + EXPECT_FALSE(s2 > s1); + EXPECT_TRUE(s2 >= s1); + } - { - int arr[] = {2, 1}; // bigger + { + int arr[] = {2, 1}; // bigger - span s1; - span s2 = arr; + span s1; + span s2 = arr; - EXPECT_TRUE(s1 != s2); - EXPECT_TRUE(s2 != s1); - EXPECT_FALSE(s1 == s2); - EXPECT_FALSE(s2 == s1); - EXPECT_TRUE(s1 < s2); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s2 <= s1); - EXPECT_TRUE(s2 > s1); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s2 >= s1); - EXPECT_FALSE(s1 >= s2); - } + EXPECT_TRUE(s1 != s2); + EXPECT_TRUE(s2 != s1); + EXPECT_FALSE(s1 == s2); + EXPECT_FALSE(s2 == s1); + EXPECT_TRUE(s1 < s2); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s2 <= s1); + EXPECT_TRUE(s2 > s1); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s2 >= s1); + EXPECT_FALSE(s1 >= s2); + } - { - int arr1[] = {1, 2}; - int arr2[] = {1, 2}; - span s1 = arr1; - span s2 = arr2; + { + int arr1[] = {1, 2}; + int arr2[] = {1, 2}; + span s1 = arr1; + span s2 = arr2; - EXPECT_TRUE(s1 == s2); - EXPECT_FALSE(s1 != s2); - EXPECT_FALSE(s1 < s2); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s1 >= s2); - EXPECT_TRUE(s2 == s1); - EXPECT_FALSE(s2 != s1); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s2 <= s1); - EXPECT_FALSE(s2 > s1); - EXPECT_TRUE(s2 >= s1); - } + EXPECT_TRUE(s1 == s2); + EXPECT_FALSE(s1 != s2); + EXPECT_FALSE(s1 < s2); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s1 >= s2); + EXPECT_TRUE(s2 == s1); + EXPECT_FALSE(s2 != s1); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s2 <= s1); + EXPECT_FALSE(s2 > s1); + EXPECT_TRUE(s2 >= s1); + } - { - int arr[] = {1, 2, 3}; + { + int arr[] = {1, 2, 3}; - span s1 = {&arr[0], 2}; // shorter - span s2 = arr; // longer + span s1 = {&arr[0], 2}; // shorter + span s2 = arr; // longer - EXPECT_TRUE(s1 != s2); - EXPECT_TRUE(s2 != s1); - EXPECT_FALSE(s1 == s2); - EXPECT_FALSE(s2 == s1); - EXPECT_TRUE(s1 < s2); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s2 <= s1); - EXPECT_TRUE(s2 > s1); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s2 >= s1); - EXPECT_FALSE(s1 >= s2); - } + EXPECT_TRUE(s1 != s2); + EXPECT_TRUE(s2 != s1); + EXPECT_FALSE(s1 == s2); + EXPECT_FALSE(s2 == s1); + EXPECT_TRUE(s1 < s2); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s2 <= s1); + EXPECT_TRUE(s2 > s1); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s2 >= s1); + EXPECT_FALSE(s1 >= s2); + } - { - int arr1[] = {1, 2}; // smaller - int arr2[] = {2, 1}; // bigger + { + int arr1[] = {1, 2}; // smaller + int arr2[] = {2, 1}; // bigger - span s1 = arr1; - span s2 = arr2; + span s1 = arr1; + span s2 = arr2; - EXPECT_TRUE(s1 != s2); - EXPECT_TRUE(s2 != s1); - EXPECT_FALSE(s1 == s2); - EXPECT_FALSE(s2 == s1); - EXPECT_TRUE(s1 < s2); - EXPECT_FALSE(s2 < s1); - EXPECT_TRUE(s1 <= s2); - EXPECT_FALSE(s2 <= s1); - EXPECT_TRUE(s2 > s1); - EXPECT_FALSE(s1 > s2); - EXPECT_TRUE(s2 >= s1); - EXPECT_FALSE(s1 >= s2); - } - } + EXPECT_TRUE(s1 != s2); + EXPECT_TRUE(s2 != s1); + EXPECT_FALSE(s1 == s2); + EXPECT_FALSE(s2 == s1); + EXPECT_TRUE(s1 < s2); + EXPECT_FALSE(s2 < s1); + EXPECT_TRUE(s1 <= s2); + EXPECT_FALSE(s2 <= s1); + EXPECT_TRUE(s2 > s1); + EXPECT_FALSE(s1 > s2); + EXPECT_TRUE(s2 >= s1); + EXPECT_FALSE(s1 >= s2); + } +} +#endif // GSL_KERNEL_MODE diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index b845d07..1e0222e 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -17,19 +17,19 @@ #include #include // for byte +#include // for span, span_iterator, operator==, operator!= #include // for narrow_cast, at -#include // for span, span_iterator, operator==, operator!= #include // for array +#include // for ptrdiff_t #include // for ptrdiff_t #include // for reverse_iterator, operator-, operator== #include // for unique_ptr, shared_ptr, make_unique, allo... #include // for match_results, sub_match, match_results<>... -#include // for ptrdiff_t #include // for string #include // for integral_constant<>::value, is_default_co... -#include // for vector #include +#include // for vector // the string_view include and macro are used in the deduction guide verification #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) @@ -41,12 +41,13 @@ #endif // __has_include #endif // (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) +#include "deathTestCommon.h" + using namespace std; using namespace gsl; namespace { -static constexpr char deathstring[] = "Expected Death"; struct BaseClass { @@ -111,10 +112,12 @@ TEST(span_test, size_optimization) TEST(span_test, from_nullptr_size_constructor) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. from_nullptr_size_constructor"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + { span s{nullptr, narrow_cast::size_type>(0)}; EXPECT_TRUE(s.size() == 0); @@ -128,21 +131,21 @@ TEST(span_test, from_nullptr_size_constructor) auto workaround_macro = []() { const span s{nullptr, narrow_cast::size_type>(0)}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { auto workaround_macro = []() { const span s{nullptr, 1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); auto const_workaround_macro = []() { const span s{nullptr, 1}; }; - EXPECT_DEATH(const_workaround_macro(), deathstring); + EXPECT_DEATH(const_workaround_macro(), expected); } { auto workaround_macro = []() { const span s{nullptr, 1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); auto const_workaround_macro = []() { const span s{nullptr, 1}; }; - EXPECT_DEATH(const_workaround_macro(), deathstring); + EXPECT_DEATH(const_workaround_macro(), expected); } { span s{nullptr, narrow_cast::size_type>(0)}; @@ -157,10 +160,12 @@ TEST(span_test, from_nullptr_size_constructor) TEST(span_test, from_pointer_length_constructor) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. from_pointer_length_constructor"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + int arr[4] = {1, 2, 3, 4}; { @@ -171,8 +176,7 @@ TEST(span_test, from_pointer_length_constructor) EXPECT_TRUE(s.size() == narrow_cast(i)); EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.empty() == (i == 0)); - for (int j = 0; j < i; ++j) - EXPECT_TRUE(arr[j] == s[narrow_cast(j)]); + for (int j = 0; j < i; ++j) EXPECT_TRUE(arr[j] == s[narrow_cast(j)]); } { span s = {&arr[i], 4 - narrow_cast(i)}; @@ -204,7 +208,7 @@ TEST(span_test, from_pointer_length_constructor) { int* p = nullptr; auto workaround_macro = [=]() { const span s{p, 2}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } } @@ -242,14 +246,14 @@ TEST(span_test, from_pointer_pointer_construction) // this will fail the std::distance() precondition, which asserts on MSVC debug builds //{ // auto workaround_macro = [&]() { span s{&arr[1], &arr[0]}; }; - // EXPECT_DEATH(workaround_macro(), deathstring); + // EXPECT_DEATH(workaround_macro(), expected); //} // this will fail the std::distance() precondition, which asserts on MSVC debug builds //{ // int* p = nullptr; // auto workaround_macro = [&]() { span s{&arr[0], p}; }; - // EXPECT_DEATH(workaround_macro(), deathstring); + // EXPECT_DEATH(workaround_macro(), expected); //} { @@ -270,897 +274,912 @@ TEST(span_test, from_pointer_pointer_construction) //{ // int* p = nullptr; // auto workaround_macro = [&]() { span s{&arr[0], p}; }; - // EXPECT_DEATH(workaround_macro(), deathstring); + // EXPECT_DEATH(workaround_macro(), expected); //} } TEST(span_test, from_array_constructor) - { - int arr[5] = {1, 2, 3, 4, 5}; +{ + int arr[5] = {1, 2, 3, 4, 5}; - { - const span s{arr}; - EXPECT_TRUE(s.size() == 5); - EXPECT_TRUE(s.data() == &arr[0]); - } + { + const span s{arr}; + EXPECT_TRUE(s.size() == 5); + EXPECT_TRUE(s.data() == &arr[0]); + } - { - const span s{arr}; - EXPECT_TRUE(s.size() == 5); - EXPECT_TRUE(s.data() == &arr[0]); - } + { + const span s{arr}; + EXPECT_TRUE(s.size() == 5); + EXPECT_TRUE(s.data() == &arr[0]); + } - int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; + int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; - #ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr}; - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr}; + } - { - span s{arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == &arr[0]); - } + { + span s{arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == &arr[0]); + } - { - span s{arr2d}; - EXPECT_TRUE(s.size() == 6); - EXPECT_TRUE(s.data() == &arr2d[0][0]); - EXPECT_TRUE(s[0] == 1); - EXPECT_TRUE(s[5] == 6); - } + { + span s{arr2d}; + EXPECT_TRUE(s.size() == 6); + EXPECT_TRUE(s.data() == &arr2d[0][0]); + EXPECT_TRUE(s[0] == 1); + EXPECT_TRUE(s[5] == 6); + } - { - span s{arr2d}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == &arr2d[0][0]); - } + { + span s{arr2d}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == &arr2d[0][0]); + } - { - span s{arr2d}; - } - #endif - { - const span s{std::addressof(arr2d[0]), 1}; - EXPECT_TRUE(s.size() == 1); - EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); - } + { + span s{arr2d}; + } +#endif + { + const span s{std::addressof(arr2d[0]), 1}; + EXPECT_TRUE(s.size() == 1); + EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); + } - int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; - #ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr3d}; - EXPECT_TRUE(s.size() == 12); - EXPECT_TRUE(s.data() == &arr3d[0][0][0]); - EXPECT_TRUE(s[0] == 1); - EXPECT_TRUE(s[11] == 12); - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr3d}; + EXPECT_TRUE(s.size() == 12); + EXPECT_TRUE(s.data() == &arr3d[0][0][0]); + EXPECT_TRUE(s[0] == 1); + EXPECT_TRUE(s[11] == 12); + } - { - span s{arr3d}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == &arr3d[0][0][0]); - } + { + span s{arr3d}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == &arr3d[0][0][0]); + } - { - span s{arr3d}; - } + { + span s{arr3d}; + } - { - span s{arr3d}; - EXPECT_TRUE(s.size() == 12); - EXPECT_TRUE(s.data() == &arr3d[0][0][0]); - EXPECT_TRUE(s[0] == 1); - EXPECT_TRUE(s[5] == 6); - } - #endif - { - const span s{std::addressof(arr3d[0]), 1}; - EXPECT_TRUE(s.size() == 1); - } + { + span s{arr3d}; + EXPECT_TRUE(s.size() == 12); + EXPECT_TRUE(s.data() == &arr3d[0][0][0]); + EXPECT_TRUE(s[0] == 1); + EXPECT_TRUE(s[5] == 6); + } +#endif + { + const span s{std::addressof(arr3d[0]), 1}; + EXPECT_TRUE(s.size() == 1); + } - AddressOverloaded ao_arr[5] = {}; + AddressOverloaded ao_arr[5] = {}; - { - const span s{ao_arr}; - EXPECT_TRUE(s.size() == 5); - EXPECT_TRUE(s.data() == std::addressof(ao_arr[0])); - } - } + { + const span s{ao_arr}; + EXPECT_TRUE(s.size() == 5); + EXPECT_TRUE(s.data() == std::addressof(ao_arr[0])); + } +} - TEST(span_test, from_dynamic_array_constructor) - { - double(*arr)[3][4] = new double[100][3][4]; +TEST(span_test, from_dynamic_array_constructor) +{ + double(*arr)[3][4] = new double[100][3][4]; - { - span s(&arr[0][0][0], 10); - EXPECT_TRUE(s.size() == 10); - EXPECT_TRUE(s.data() == &arr[0][0][0]); - } + { + span s(&arr[0][0][0], 10); + EXPECT_TRUE(s.size() == 10); + EXPECT_TRUE(s.data() == &arr[0][0][0]); + } - delete[] arr; - } + delete[] arr; +} - TEST(span_test, from_std_array_constructor) - { - std::array arr = {1, 2, 3, 4}; +TEST(span_test, from_std_array_constructor) +{ + std::array arr = {1, 2, 3, 4}; - { - span s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); + { + span s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); - span cs{arr}; - EXPECT_TRUE(cs.size() == arr.size()); - EXPECT_TRUE(cs.data() == arr.data()); - } + span cs{arr}; + EXPECT_TRUE(cs.size() == arr.size()); + EXPECT_TRUE(cs.data() == arr.data()); + } - { - span s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); + { + span s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); - span cs{arr}; - EXPECT_TRUE(cs.size() == arr.size()); - EXPECT_TRUE(cs.data() == arr.data()); - } + span cs{arr}; + EXPECT_TRUE(cs.size() == arr.size()); + EXPECT_TRUE(cs.data() == arr.data()); + } - { - std::array empty_arr{}; - span s{empty_arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.empty()); - } + { + std::array empty_arr{}; + span s{empty_arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.empty()); + } - std::array ao_arr{}; + std::array ao_arr{}; - { - span fs{ao_arr}; - EXPECT_TRUE(fs.size() == ao_arr.size()); - EXPECT_TRUE(ao_arr.data() == fs.data()); - } + { + span fs{ao_arr}; + EXPECT_TRUE(fs.size() == ao_arr.size()); + EXPECT_TRUE(ao_arr.data() == fs.data()); + } - #ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr}; - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == arr.data()); +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr}; + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == arr.data()); - span cs{arr}; - EXPECT_TRUE(cs.size() == 2); - EXPECT_TRUE(cs.data() == arr.data()); - } + span cs{arr}; + EXPECT_TRUE(cs.size() == 2); + EXPECT_TRUE(cs.data() == arr.data()); + } - { - span s{arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == arr.data()); + { + span s{arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == arr.data()); - span cs{arr}; - EXPECT_TRUE(cs.size() == 0); - EXPECT_TRUE(cs.data() == arr.data()); - } + span cs{arr}; + EXPECT_TRUE(cs.size() == 0); + EXPECT_TRUE(cs.data() == arr.data()); + } - { - span s{arr}; - } + { + span s{arr}; + } - { - auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; - auto take_a_span = [](span s) { static_cast(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } - #endif + { + auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; + auto take_a_span = [](span s) { static_cast(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } +#endif - { - auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; - auto take_a_span = [](span s) { static_cast(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } - } + { + auto get_an_array = []() -> std::array { return {1, 2, 3, 4}; }; + auto take_a_span = [](span s) { static_cast(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } +} - TEST(span_test, from_const_std_array_constructor) - { - const std::array arr = {1, 2, 3, 4}; +TEST(span_test, from_const_std_array_constructor) +{ + const std::array arr = {1, 2, 3, 4}; - { - span s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - const std::array ao_arr{}; + const std::array ao_arr{}; - { - span s{ao_arr}; - EXPECT_TRUE(s.size() == ao_arr.size()); - EXPECT_TRUE(s.data() == ao_arr.data()); - } + { + span s{ao_arr}; + EXPECT_TRUE(s.size() == ao_arr.size()); + EXPECT_TRUE(s.data() == ao_arr.data()); + } - #ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr}; - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == arr.data()); - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr}; + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span s{arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span s{arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span s{arr}; - } - #endif + { + span s{arr}; + } +#endif - { - auto get_an_array = []() -> const std::array { return {1, 2, 3, 4}; }; - auto take_a_span = [](span s) { static_cast(s); }; - // try to take a temporary std::array - take_a_span(get_an_array()); - } - } + { + auto get_an_array = []() -> const std::array { return {1, 2, 3, 4}; }; + auto take_a_span = [](span s) { static_cast(s); }; + // try to take a temporary std::array + take_a_span(get_an_array()); + } +} - TEST(span_test, from_std_array_const_constructor) - { - std::array arr = {1, 2, 3, 4}; +TEST(span_test, from_std_array_const_constructor) +{ + std::array arr = {1, 2, 3, 4}; - { - span s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span s{arr}; - EXPECT_TRUE(s.size() == arr.size()); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span s{arr}; + EXPECT_TRUE(s.size() == arr.size()); + EXPECT_TRUE(s.data() == arr.data()); + } - #ifdef CONFIRM_COMPILATION_ERRORS - { - span s{arr}; - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == arr.data()); - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s{arr}; + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span s{arr}; - EXPECT_TRUE(s.size() == 0); - EXPECT_TRUE(s.data() == arr.data()); - } + { + span s{arr}; + EXPECT_TRUE(s.size() == 0); + EXPECT_TRUE(s.data() == arr.data()); + } - { - span s{arr}; - } + { + span s{arr}; + } - { - span s{arr}; - } - #endif - } + { + span s{arr}; + } +#endif +} - TEST(span_test, from_container_constructor) - { - std::vector v = {1, 2, 3}; - const std::vector cv = v; +TEST(span_test, from_container_constructor) +{ + std::vector v = {1, 2, 3}; + const std::vector cv = v; - { - span s{v}; - EXPECT_TRUE(s.size() == v.size()); - EXPECT_TRUE(s.data() == v.data()); + { + span s{v}; + EXPECT_TRUE(s.size() == v.size()); + EXPECT_TRUE(s.data() == v.data()); - span cs{v}; - EXPECT_TRUE(cs.size() == v.size()); - EXPECT_TRUE(cs.data() == v.data()); - } + span cs{v}; + EXPECT_TRUE(cs.size() == v.size()); + EXPECT_TRUE(cs.data() == v.data()); + } - std::string str = "hello"; - const std::string cstr = "hello"; + std::string str = "hello"; + const std::string cstr = "hello"; - { - #ifdef CONFIRM_COMPILATION_ERRORS - span s{str}; - EXPECT_TRUE(s.size() == str.size()); + { +#ifdef CONFIRM_COMPILATION_ERRORS + span s{str}; + EXPECT_TRUE(s.size() == str.size()); EXPECT_TRUE(s.data() == str.data())); - #endif +#endif span cs{str}; EXPECT_TRUE(cs.size() == str.size()); EXPECT_TRUE(cs.data() == str.data()); - } + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - span s{cstr}; - #endif - span cs{cstr}; - EXPECT_TRUE(cs.size() == cstr.size()); - EXPECT_TRUE(cs.data() == cstr.data()); - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + span s{cstr}; +#endif + span cs{cstr}; + EXPECT_TRUE(cs.size() == cstr.size()); + EXPECT_TRUE(cs.data() == cstr.data()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_vector = []() -> std::vector { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_vector()); - #endif - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_vector = []() -> std::vector { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_vector()); +#endif + } - { - auto get_temp_vector = []() -> std::vector { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_vector()); - } + { + auto get_temp_vector = []() -> std::vector { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_vector()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_string = []() -> std::string { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_string()); - #endif - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_string = []() -> std::string { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_string()); +#endif + } - { - auto get_temp_string = []() -> std::string { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_string()); - } + { + auto get_temp_string = []() -> std::string { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_string()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - auto get_temp_vector = []() -> const std::vector { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_vector()); - #endif - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + auto get_temp_vector = []() -> const std::vector { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_vector()); +#endif + } - { - auto get_temp_string = []() -> const std::string { return {}; }; - auto use_span = [](span s) { static_cast(s); }; - use_span(get_temp_string()); - } + { + auto get_temp_string = []() -> const std::string { return {}; }; + auto use_span = [](span s) { static_cast(s); }; + use_span(get_temp_string()); + } - { - #ifdef CONFIRM_COMPILATION_ERRORS - std::map m; - span s{m}; - #endif - } - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + std::map m; + span s{m}; +#endif + } +} - TEST(span_test, from_convertible_span_constructor){{span avd; - span avcd = avd; - static_cast(avcd); - } +TEST(span_test, from_convertible_span_constructor){{span avd; +span avcd = avd; +static_cast(avcd); +} - { - #ifdef CONFIRM_COMPILATION_ERRORS - span avd; - span avb = avd; - static_cast(avb); - #endif - } +{ +#ifdef CONFIRM_COMPILATION_ERRORS + span avd; + span avb = avd; + static_cast(avb); +#endif +} - #ifdef CONFIRM_COMPILATION_ERRORS - { - span s; - span s2 = s; - static_cast(s2); - } +#ifdef CONFIRM_COMPILATION_ERRORS +{ + span s; + span s2 = s; + static_cast(s2); +} - { - span s; - span s2 = s; - static_cast(s2); - } +{ + span s; + span s2 = s; + static_cast(s2); +} - { - span s; - span s2 = s; - static_cast(s2); - } - #endif - } +{ + span s; + span s2 = s; + static_cast(s2); +} +#endif +} - TEST(span_test, copy_move_and_assignment) - { - span s1; - EXPECT_TRUE(s1.empty()); +TEST(span_test, copy_move_and_assignment) +{ + span s1; + EXPECT_TRUE(s1.empty()); - int arr[] = {3, 4, 5}; + int arr[] = {3, 4, 5}; - span s2 = arr; - EXPECT_TRUE(s2.size() == 3); - EXPECT_TRUE(s2.data() == &arr[0]); + span s2 = arr; + EXPECT_TRUE(s2.size() == 3); + EXPECT_TRUE(s2.data() == &arr[0]); - s2 = s1; - EXPECT_TRUE(s2.empty()); + s2 = s1; + EXPECT_TRUE(s2.empty()); - auto get_temp_span = [&]() -> span { return {&arr[1], 2}; }; - auto use_span = [&](span s) { - EXPECT_TRUE(s.size() == 2); - EXPECT_TRUE(s.data() == &arr[1]); - }; use_span(get_temp_span()); + auto get_temp_span = [&]() -> span { return {&arr[1], 2}; }; + auto use_span = [&](span s) { + EXPECT_TRUE(s.size() == 2); + EXPECT_TRUE(s.data() == &arr[1]); + }; + use_span(get_temp_span()); - s1 = get_temp_span(); - EXPECT_TRUE(s1.size() == 2); - EXPECT_TRUE(s1.data() == &arr[1]); - } + s1 = get_temp_span(); + EXPECT_TRUE(s1.size() == 2); + EXPECT_TRUE(s1.data() == &arr[1]); +} - TEST(span_test, first) - { - std::set_terminate([] { +TEST(span_test, first) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. first"; std::abort(); }); - int arr[5] = {1, 2, 3, 4, 5}; + const auto expected = GetExpectedDeathString(terminateHandler); - { - span av = arr; - EXPECT_TRUE(av.first<2>().size() == 2); - EXPECT_TRUE(av.first(2).size() == 2); - } + int arr[5] = {1, 2, 3, 4, 5}; - { - span av = arr; - EXPECT_TRUE(av.first<0>().size() == 0); - EXPECT_TRUE(av.first(0).size() == 0); - } + { + span av = arr; + EXPECT_TRUE(av.first<2>().size() == 2); + EXPECT_TRUE(av.first(2).size() == 2); + } - { - span av = arr; - EXPECT_TRUE(av.first<5>().size() == 5); - EXPECT_TRUE(av.first(5).size() == 5); - } + { + span av = arr; + EXPECT_TRUE(av.first<0>().size() == 0); + EXPECT_TRUE(av.first(0).size() == 0); + } - { - span av = arr; - #ifdef CONFIRM_COMPILATION_ERRORS - EXPECT_TRUE(av.first<6>().size() == 6); - EXPECT_TRUE(av.first<-1>().size() == -1); - #endif - EXPECT_DEATH(av.first(6).size(), deathstring); - } + { + span av = arr; + EXPECT_TRUE(av.first<5>().size() == 5); + EXPECT_TRUE(av.first(5).size() == 5); + } - { - span av; - EXPECT_TRUE(av.first<0>().size() == 0); - EXPECT_TRUE(av.first(0).size() == 0); - } - } + { + span av = arr; +#ifdef CONFIRM_COMPILATION_ERRORS + EXPECT_TRUE(av.first<6>().size() == 6); + EXPECT_TRUE(av.first<-1>().size() == -1); +#endif + EXPECT_DEATH(av.first(6).size(), expected); + } - TEST(span_test, last) - { - std::set_terminate([] { + { + span av; + EXPECT_TRUE(av.first<0>().size() == 0); + EXPECT_TRUE(av.first(0).size() == 0); + } +} + +TEST(span_test, last) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. last"; std::abort(); }); - int arr[5] = {1, 2, 3, 4, 5}; + const auto expected = GetExpectedDeathString(terminateHandler); - { - span av = arr; - EXPECT_TRUE(av.last<2>().size() == 2); - EXPECT_TRUE(av.last(2).size() == 2); - } + int arr[5] = {1, 2, 3, 4, 5}; - { - span av = arr; - EXPECT_TRUE(av.last<0>().size() == 0); - EXPECT_TRUE(av.last(0).size() == 0); - } + { + span av = arr; + EXPECT_TRUE(av.last<2>().size() == 2); + EXPECT_TRUE(av.last(2).size() == 2); + } - { - span av = arr; - EXPECT_TRUE(av.last<5>().size() == 5); - EXPECT_TRUE(av.last(5).size() == 5); - } + { + span av = arr; + EXPECT_TRUE(av.last<0>().size() == 0); + EXPECT_TRUE(av.last(0).size() == 0); + } - { - span av = arr; - #ifdef CONFIRM_COMPILATION_ERRORS - EXPECT_TRUE(av.last<6>().size() == 6); - #endif - EXPECT_DEATH(av.last(6).size(), deathstring); - } + { + span av = arr; + EXPECT_TRUE(av.last<5>().size() == 5); + EXPECT_TRUE(av.last(5).size() == 5); + } - { - span av; - EXPECT_TRUE(av.last<0>().size() == 0); - EXPECT_TRUE(av.last(0).size() == 0); - } - } + { + span av = arr; +#ifdef CONFIRM_COMPILATION_ERRORS + EXPECT_TRUE(av.last<6>().size() == 6); +#endif + EXPECT_DEATH(av.last(6).size(), expected); + } - TEST(span_test, subspan) - { - std::set_terminate([] { + { + span av; + EXPECT_TRUE(av.last<0>().size() == 0); + EXPECT_TRUE(av.last(0).size() == 0); + } +} + +TEST(span_test, subspan) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. subspan"; std::abort(); }); - int arr[5] = {1, 2, 3, 4, 5}; + const auto expected = GetExpectedDeathString(terminateHandler); - { - span av = arr; - EXPECT_TRUE((av.subspan<2, 2>().size()) == 2); - EXPECT_TRUE(decltype(av.subspan<2, 2>())::extent == 2); - EXPECT_TRUE(av.subspan(2, 2).size() == 2); - EXPECT_TRUE(av.subspan(2, 3).size() == 3); - } + int arr[5] = {1, 2, 3, 4, 5}; - { - span av = arr; - EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); - EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); - EXPECT_TRUE(av.subspan(0, 0).size() == 0); - } + { + span av = arr; + EXPECT_TRUE((av.subspan<2, 2>().size()) == 2); + EXPECT_TRUE(decltype(av.subspan<2, 2>())::extent == 2); + EXPECT_TRUE(av.subspan(2, 2).size() == 2); + EXPECT_TRUE(av.subspan(2, 3).size() == 3); + } - { - span av = arr; - EXPECT_TRUE((av.subspan<0, 5>().size()) == 5); - EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5); - EXPECT_TRUE(av.subspan(0, 5).size() == 5); + { + span av = arr; + EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); + EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); + EXPECT_TRUE(av.subspan(0, 0).size() == 0); + } - EXPECT_DEATH(av.subspan(0, 6).size(), deathstring); - EXPECT_DEATH(av.subspan(1, 5).size(), deathstring); - } + { + span av = arr; + EXPECT_TRUE((av.subspan<0, 5>().size()) == 5); + EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5); + EXPECT_TRUE(av.subspan(0, 5).size() == 5); - { - span av = arr; - EXPECT_TRUE((av.subspan<4, 0>().size()) == 0); - EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0); - EXPECT_TRUE(av.subspan(4, 0).size() == 0); - EXPECT_TRUE(av.subspan(5, 0).size() == 0); - EXPECT_DEATH(av.subspan(6, 0).size(), deathstring); - } + EXPECT_DEATH(av.subspan(0, 6).size(), expected); + EXPECT_DEATH(av.subspan(1, 5).size(), expected); + } - { - span av = arr; - EXPECT_TRUE(av.subspan<1>().size() == 4); - EXPECT_TRUE(decltype(av.subspan<1>())::extent == 4); - } + { + span av = arr; + EXPECT_TRUE((av.subspan<4, 0>().size()) == 0); + EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0); + EXPECT_TRUE(av.subspan(4, 0).size() == 0); + EXPECT_TRUE(av.subspan(5, 0).size() == 0); + EXPECT_DEATH(av.subspan(6, 0).size(), expected); + } - { - span av; - EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); - EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); - EXPECT_TRUE(av.subspan(0, 0).size() == 0); - EXPECT_DEATH((av.subspan<1, 0>().size()), deathstring); - } + { + span av = arr; + EXPECT_TRUE(av.subspan<1>().size() == 4); + EXPECT_TRUE(decltype(av.subspan<1>())::extent == 4); + } - { - span av; - EXPECT_TRUE(av.subspan(0).size() == 0); - EXPECT_DEATH(av.subspan(1).size(), deathstring); - } + { + span av; + EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); + EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); + EXPECT_TRUE(av.subspan(0, 0).size() == 0); + EXPECT_DEATH((av.subspan<1, 0>().size()), expected); + } - { - span av = arr; - EXPECT_TRUE(av.subspan(0).size() == 5); - EXPECT_TRUE(av.subspan(1).size() == 4); - EXPECT_TRUE(av.subspan(4).size() == 1); - EXPECT_TRUE(av.subspan(5).size() == 0); - EXPECT_DEATH(av.subspan(6).size(), deathstring); - const auto av2 = av.subspan(1); - for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast(i) + 2); - } + { + span av; + EXPECT_TRUE(av.subspan(0).size() == 0); + EXPECT_DEATH(av.subspan(1).size(), expected); + } - { - span av = arr; - EXPECT_TRUE(av.subspan(0).size() == 5); - EXPECT_TRUE(av.subspan(1).size() == 4); - EXPECT_TRUE(av.subspan(4).size() == 1); - EXPECT_TRUE(av.subspan(5).size() == 0); - EXPECT_DEATH(av.subspan(6).size(), deathstring); - const auto av2 = av.subspan(1); - for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast(i) + 2); - } - } + { + span av = arr; + EXPECT_TRUE(av.subspan(0).size() == 5); + EXPECT_TRUE(av.subspan(1).size() == 4); + EXPECT_TRUE(av.subspan(4).size() == 1); + EXPECT_TRUE(av.subspan(5).size() == 0); + EXPECT_DEATH(av.subspan(6).size(), expected); + const auto av2 = av.subspan(1); + for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast(i) + 2); + } - TEST(span_test, iterator_default_init) - { - span::iterator it1; - span::iterator it2; - EXPECT_TRUE(it1 == it2); - } + { + span av = arr; + EXPECT_TRUE(av.subspan(0).size() == 5); + EXPECT_TRUE(av.subspan(1).size() == 4); + EXPECT_TRUE(av.subspan(4).size() == 1); + EXPECT_TRUE(av.subspan(5).size() == 0); + EXPECT_DEATH(av.subspan(6).size(), expected); + const auto av2 = av.subspan(1); + for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast(i) + 2); + } +} - TEST(span_test, iterator_comparisons) - { - int a[] = {1, 2, 3, 4}; - { - span s = a; - span::iterator it = s.begin(); - auto it2 = it + 1; +TEST(span_test, iterator_default_init) +{ + span::iterator it1; + span::iterator it2; + EXPECT_TRUE(it1 == it2); +} - EXPECT_TRUE(it == it); - EXPECT_TRUE(it == s.begin()); - EXPECT_TRUE(s.begin() == it); +TEST(span_test, iterator_comparisons) +{ + int a[] = {1, 2, 3, 4}; + { + span s = a; + span::iterator it = s.begin(); + auto it2 = it + 1; - EXPECT_TRUE(it != it2); - EXPECT_TRUE(it2 != it); - EXPECT_TRUE(it != s.end()); - EXPECT_TRUE(it2 != s.end()); - EXPECT_TRUE(s.end() != it); + EXPECT_TRUE(it == it); + EXPECT_TRUE(it == s.begin()); + EXPECT_TRUE(s.begin() == it); - EXPECT_TRUE(it < it2); - EXPECT_TRUE(it <= it2); - EXPECT_TRUE(it2 <= s.end()); - EXPECT_TRUE(it < s.end()); + EXPECT_TRUE(it != it2); + EXPECT_TRUE(it2 != it); + EXPECT_TRUE(it != s.end()); + EXPECT_TRUE(it2 != s.end()); + EXPECT_TRUE(s.end() != it); - EXPECT_TRUE(it2 > it); - EXPECT_TRUE(it2 >= it); - EXPECT_TRUE(s.end() > it2); - EXPECT_TRUE(s.end() >= it2); - } - } + EXPECT_TRUE(it < it2); + EXPECT_TRUE(it <= it2); + EXPECT_TRUE(it2 <= s.end()); + EXPECT_TRUE(it < s.end()); - TEST(span_test, incomparable_iterators) - { - std::set_terminate([] { - std::cerr << "Expected Death. incomparable_iterators"; - std::abort(); - }); + EXPECT_TRUE(it2 > it); + EXPECT_TRUE(it2 >= it); + EXPECT_TRUE(s.end() > it2); + EXPECT_TRUE(s.end() >= it2); + } +} - int a[] = {1, 2, 3, 4}; - int b[] = {1, 2, 3, 4}; - { - span s = a; - span s2 = b; +TEST(span_test, incomparable_iterators) +{ + const auto terminateHandler = std::set_terminate([] { + std::cerr << "Expected Death. incomparable_iterators"; + std::abort(); + }); + const auto expected = GetExpectedDeathString(terminateHandler); + + int a[] = {1, 2, 3, 4}; + int b[] = {1, 2, 3, 4}; + { + span s = a; + span s2 = b; #if (__cplusplus > 201402L) - EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() == s2.begin()), deathstring); - EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), deathstring); + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() == s2.begin()), expected); + EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), expected); #else - EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); - EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); + EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), expected); + EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), expected); #endif - } - } + } +} - TEST(span_test, begin_end) - { - std::set_terminate([] { +TEST(span_test, begin_end) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. begin_end"; std::abort(); }); - { - int a[] = {1, 2, 3, 4}; - span s = a; + const auto expected = GetExpectedDeathString(terminateHandler); - span::iterator it = s.begin(); - span::iterator it2 = std::begin(s); - EXPECT_TRUE(it == it2); + { + int a[] = {1, 2, 3, 4}; + span s = a; - it = s.end(); - it2 = std::end(s); - EXPECT_TRUE(it == it2); - } + span::iterator it = s.begin(); + span::iterator it2 = std::begin(s); + EXPECT_TRUE(it == it2); - { - int a[] = {1, 2, 3, 4}; - span s = a; + it = s.end(); + it2 = std::end(s); + EXPECT_TRUE(it == it2); + } - auto it = s.begin(); - auto first = it; - EXPECT_TRUE(it == first); - EXPECT_TRUE(*it == 1); + { + int a[] = {1, 2, 3, 4}; + span s = a; - auto beyond = s.end(); - EXPECT_TRUE(it != beyond); - EXPECT_DEATH(*beyond, deathstring); + auto it = s.begin(); + auto first = it; + EXPECT_TRUE(it == first); + EXPECT_TRUE(*it == 1); - EXPECT_TRUE(beyond - first == 4); - EXPECT_TRUE(first - first == 0); - EXPECT_TRUE(beyond - beyond == 0); + auto beyond = s.end(); + EXPECT_TRUE(it != beyond); + EXPECT_DEATH(*beyond, expected); - ++it; - EXPECT_TRUE(it - first == 1); - EXPECT_TRUE(*it == 2); - *it = 22; - EXPECT_TRUE(*it == 22); - EXPECT_TRUE(beyond - it == 3); + EXPECT_TRUE(beyond - first == 4); + EXPECT_TRUE(first - first == 0); + EXPECT_TRUE(beyond - beyond == 0); - it = first; - EXPECT_TRUE(it == first); - while (it != s.end()) - { - *it = 5; - ++it; - } + ++it; + EXPECT_TRUE(it - first == 1); + EXPECT_TRUE(*it == 2); + *it = 22; + EXPECT_TRUE(*it == 22); + EXPECT_TRUE(beyond - it == 3); - EXPECT_TRUE(it == beyond); - EXPECT_TRUE(it - beyond == 0); + it = first; + EXPECT_TRUE(it == first); + while (it != s.end()) + { + *it = 5; + ++it; + } - for (const auto& n : s) { EXPECT_TRUE(n == 5); } - } - } + EXPECT_TRUE(it == beyond); + EXPECT_TRUE(it - beyond == 0); - TEST(span_test, rbegin_rend) - { - std::set_terminate([] { + for (const auto& n : s) { EXPECT_TRUE(n == 5); } + } +} + +TEST(span_test, rbegin_rend) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. rbegin_rend"; std::abort(); }); - { - int a[] = {1, 2, 3, 4}; - span s = a; + const auto expected = GetExpectedDeathString(terminateHandler); - auto it = s.rbegin(); - auto first = it; - EXPECT_TRUE(it == first); - EXPECT_TRUE(*it == 4); + { + int a[] = {1, 2, 3, 4}; + span s = a; - auto beyond = s.rend(); - EXPECT_TRUE(it != beyond); + auto it = s.rbegin(); + auto first = it; + EXPECT_TRUE(it == first); + EXPECT_TRUE(*it == 4); + + auto beyond = s.rend(); + EXPECT_TRUE(it != beyond); #if (__cplusplus > 201402L) - EXPECT_DEATH([[maybe_unused]] auto _ = *beyond , deathstring); + EXPECT_DEATH([[maybe_unused]] auto _ = *beyond, expected); #else - EXPECT_DEATH(auto _ = *beyond , deathstring); + EXPECT_DEATH(auto _ = *beyond, expected); #endif - EXPECT_TRUE(beyond - first == 4); - EXPECT_TRUE(first - first == 0); - EXPECT_TRUE(beyond - beyond == 0); + EXPECT_TRUE(beyond - first == 4); + EXPECT_TRUE(first - first == 0); + EXPECT_TRUE(beyond - beyond == 0); - ++it; - EXPECT_TRUE(it - s.rbegin() == 1); - EXPECT_TRUE(*it == 3); - *it = 22; - EXPECT_TRUE(*it == 22); - EXPECT_TRUE(beyond - it == 3); + ++it; + EXPECT_TRUE(it - s.rbegin() == 1); + EXPECT_TRUE(*it == 3); + *it = 22; + EXPECT_TRUE(*it == 22); + EXPECT_TRUE(beyond - it == 3); - it = first; - EXPECT_TRUE(it == first); - while (it != s.rend()) - { - *it = 5; - ++it; - } + it = first; + EXPECT_TRUE(it == first); + while (it != s.rend()) + { + *it = 5; + ++it; + } - EXPECT_TRUE(it == beyond); - EXPECT_TRUE(it - beyond == 0); + EXPECT_TRUE(it == beyond); + EXPECT_TRUE(it - beyond == 0); - for (const auto& n : s) { EXPECT_TRUE(n == 5); } - } - } + for (const auto& n : s) { EXPECT_TRUE(n == 5); } + } +} - TEST(span_test, as_bytes) - { - std::set_terminate([] { - std::cerr << "Expected Death. as_bytes"; - std::abort(); - }); +TEST(span_test, as_bytes) +{ + const auto terminateHandler = std::set_terminate([] { + std::cerr << "Expected Death. as_bytes"; + std::abort(); + }); + const auto expected = GetExpectedDeathString(terminateHandler); - int a[] = {1, 2, 3, 4}; - { - const span s = a; - EXPECT_TRUE(s.size() == 4); - const span bs = as_bytes(s); - EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); - EXPECT_TRUE(bs.size() == s.size_bytes()); - } + int a[] = {1, 2, 3, 4}; + { + const span s = a; + EXPECT_TRUE(s.size() == 4); + const span bs = as_bytes(s); + EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); + EXPECT_TRUE(bs.size() == s.size_bytes()); + } - { - span s; - const auto bs = as_bytes(s); - EXPECT_TRUE(bs.size() == s.size()); - EXPECT_TRUE(bs.size() == 0); - EXPECT_TRUE(bs.size_bytes() == 0); - EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); - EXPECT_TRUE(bs.data() == nullptr); - } + { + span s; + const auto bs = as_bytes(s); + EXPECT_TRUE(bs.size() == s.size()); + EXPECT_TRUE(bs.size() == 0); + EXPECT_TRUE(bs.size_bytes() == 0); + EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); + EXPECT_TRUE(bs.data() == nullptr); + } - { - span s = a; - const auto bs = as_bytes(s); - EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); - EXPECT_TRUE(bs.size() == s.size_bytes()); - } + { + span s = a; + const auto bs = as_bytes(s); + EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); + EXPECT_TRUE(bs.size() == s.size_bytes()); + } - int b[5] = {1, 2, 3, 4, 5}; - { - span sp(begin(b), static_cast(-2)); - EXPECT_DEATH((void) sp.size_bytes(), deathstring); - } - } + int b[5] = {1, 2, 3, 4, 5}; + { + span sp(begin(b), static_cast(-2)); + EXPECT_DEATH((void) sp.size_bytes(), expected); + } +} - TEST(span_test, as_writable_bytes) - { - int a[] = {1, 2, 3, 4}; +TEST(span_test, as_writable_bytes) +{ + int a[] = {1, 2, 3, 4}; - { - #ifdef CONFIRM_COMPILATION_ERRORS - // you should not be able to get writeable bytes for const objects - span s = a; - EXPECT_TRUE(s.size() == 4); - span bs = as_writable_bytes(s); - EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); - EXPECT_TRUE(bs.size() == s.size_bytes()); - #endif - } + { +#ifdef CONFIRM_COMPILATION_ERRORS + // you should not be able to get writeable bytes for const objects + span s = a; + EXPECT_TRUE(s.size() == 4); + span bs = as_writable_bytes(s); + EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); + EXPECT_TRUE(bs.size() == s.size_bytes()); +#endif + } - { - span s; - const auto bs = as_writable_bytes(s); - EXPECT_TRUE(bs.size() == s.size()); - EXPECT_TRUE(bs.size() == 0); - EXPECT_TRUE(bs.size_bytes() == 0); - EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); - EXPECT_TRUE(bs.data() == nullptr); - } + { + span s; + const auto bs = as_writable_bytes(s); + EXPECT_TRUE(bs.size() == s.size()); + EXPECT_TRUE(bs.size() == 0); + EXPECT_TRUE(bs.size_bytes() == 0); + EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); + EXPECT_TRUE(bs.data() == nullptr); + } - { - span s = a; - const auto bs = as_writable_bytes(s); - EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); - EXPECT_TRUE(bs.size() == s.size_bytes()); - } - } + { + span s = a; + const auto bs = as_writable_bytes(s); + EXPECT_TRUE(static_cast(bs.data()) == static_cast(s.data())); + EXPECT_TRUE(bs.size() == s.size_bytes()); + } +} - TEST(span_test, fixed_size_conversions) - { - std::set_terminate([] { +TEST(span_test, fixed_size_conversions) +{ + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. fixed_size_conversions"; std::abort(); }); - int arr[] = {1, 2, 3, 4}; + const auto expected = GetExpectedDeathString(terminateHandler); - // converting to an span from an equal size array is ok - span s4 = arr; - EXPECT_TRUE(s4.size() == 4); + int arr[] = {1, 2, 3, 4}; - // converting to dynamic_range is always ok - { - span s = s4; - EXPECT_TRUE(s.size() == s4.size()); - static_cast(s); - } + // converting to an span from an equal size array is ok + span s4 = arr; + EXPECT_TRUE(s4.size() == 4); - // initialization or assignment to static span that REDUCES size is NOT ok - #ifdef CONFIRM_COMPILATION_ERRORS - { - span s = arr; - } - { - span s2 = s4; - static_cast(s2); - } - #endif + // converting to dynamic_range is always ok + { + span s = s4; + EXPECT_TRUE(s.size() == s4.size()); + static_cast(s); + } - // even when done dynamically - { - /* - // this now results in a compile-time error, rather than runtime. - // There is no suitable conversion from dynamic span to fixed span. - span s = arr; - auto f = [&]() { - const span s2 = s; - static_cast(s2); - }; - EXPECT_DEATH(f(), deathstring); - */ - } +// initialization or assignment to static span that REDUCES size is NOT ok +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s = arr; + } + { + span s2 = s4; + static_cast(s2); + } +#endif - // but doing so explicitly is ok + // even when done dynamically + { + /* + // this now results in a compile-time error, rather than runtime. + // There is no suitable conversion from dynamic span to fixed span. + span s = arr; + auto f = [&]() { + const span s2 = s; + static_cast(s2); + }; + EXPECT_DEATH(f(), expected); + */ + } - // you can convert statically - { - const span s2{&arr[0], 2}; - static_cast(s2); - } - { - const span s1 = s4.first<1>(); - static_cast(s1); - } + // but doing so explicitly is ok + + // you can convert statically + { + const span s2{&arr[0], 2}; + static_cast(s2); + } + { + const span s1 = s4.first<1>(); + static_cast(s1); + } /* // this is not a legal operation in std::span, so we are no longer supporting it @@ -1176,73 +1195,74 @@ TEST(span_test, from_array_constructor) } */ - // initialization or assignment to static span that requires size INCREASE is not ok. - int arr2[2] = {1, 2}; + // initialization or assignment to static span that requires size INCREASE is not ok. + int arr2[2] = {1, 2}; - #ifdef CONFIRM_COMPILATION_ERRORS - { - span s3 = arr2; - } - { - span s2 = arr2; - span s4a = s2; - } - #endif - { - auto f = [&]() { - const span _s4{arr2, 2}; - static_cast(_s4); - }; - EXPECT_DEATH(f(), deathstring); - } +#ifdef CONFIRM_COMPILATION_ERRORS + { + span s3 = arr2; + } + { + span s2 = arr2; + span s4a = s2; + } +#endif + { + auto f = [&]() { + const span _s4{arr2, 2}; + static_cast(_s4); + }; + EXPECT_DEATH(f(), expected); + } /* - // This no longer compiles. There is no suitable conversion from dynamic span to a fixed size span. + // This no longer compiles. There is no suitable conversion from dynamic span to a fixed size + span. // this should fail - we are trying to assign a small dynamic span to a fixed_size larger one span av = arr2; auto f = [&]() { const span _s4 = av; static_cast(_s4); }; - EXPECT_DEATH(f(), deathstring); + EXPECT_DEATH(f(), expected); */ - } +} - TEST(span_test, interop_with_std_regex) - { - char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'}; - span s = lat; - const auto f_it = s.begin() + 7; +TEST(span_test, interop_with_std_regex) +{ + char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'}; + span s = lat; + const auto f_it = s.begin() + 7; - std::match_results::iterator> match; + std::match_results::iterator> match; - std::regex_match(s.begin(), s.end(), match, std::regex(".*")); - EXPECT_TRUE(match.ready()); - EXPECT_FALSE(match.empty()); - EXPECT_TRUE(match[0].matched); - EXPECT_TRUE(match[0].first == s.begin()); - EXPECT_TRUE(match[0].second == s.end()); + std::regex_match(s.begin(), s.end(), match, std::regex(".*")); + EXPECT_TRUE(match.ready()); + EXPECT_FALSE(match.empty()); + EXPECT_TRUE(match[0].matched); + EXPECT_TRUE(match[0].first == s.begin()); + EXPECT_TRUE(match[0].second == s.end()); - std::regex_search(s.begin(), s.end(), match, std::regex("F")); - EXPECT_TRUE(match.ready()); - EXPECT_FALSE(match.empty()); - EXPECT_TRUE(match[0].matched); - EXPECT_TRUE(match[0].first == f_it); - EXPECT_TRUE(match[0].second == (f_it + 1)); - } + std::regex_search(s.begin(), s.end(), match, std::regex("F")); + EXPECT_TRUE(match.ready()); + EXPECT_FALSE(match.empty()); + EXPECT_TRUE(match[0].matched); + EXPECT_TRUE(match[0].first == f_it); + EXPECT_TRUE(match[0].second == (f_it + 1)); +} - TEST(span_test, default_constructible) - { - EXPECT_TRUE((std::is_default_constructible>::value)); - EXPECT_TRUE((std::is_default_constructible>::value)); - EXPECT_FALSE((std::is_default_constructible>::value)); - } +TEST(span_test, default_constructible) +{ + EXPECT_TRUE((std::is_default_constructible>::value)); + EXPECT_TRUE((std::is_default_constructible>::value)); + EXPECT_FALSE((std::is_default_constructible>::value)); +} - TEST(span_test, std_container_ctad) - { +TEST(span_test, std_container_ctad) +{ #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) // this test is just to verify that these compile { - std::vector v{1,2,3,4}; + std::vector v{1, 2, 3, 4}; gsl::span sp{v}; static_assert(std::is_same>::value); } @@ -1259,20 +1279,22 @@ TEST(span_test, from_array_constructor) } #endif #endif - } +} - TEST(span_test, front_back) - { - int arr[5] = {1,2,3,4,5}; +TEST(span_test, front_back) +{ + int arr[5] = {1, 2, 3, 4, 5}; span s{arr}; EXPECT_TRUE(s.front() == 1); EXPECT_TRUE(s.back() == 5); - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. front_back"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); + span s2; - EXPECT_DEATH(s2.front(), deathstring); - EXPECT_DEATH(s2.back(), deathstring); - } + EXPECT_DEATH(s2.front(), expected); + EXPECT_DEATH(s2.back(), expected); +} diff --git a/tests/strict_notnull_tests.cpp b/tests/strict_notnull_tests.cpp index 9de2760..7edef43 100644 --- a/tests/strict_notnull_tests.cpp +++ b/tests/strict_notnull_tests.cpp @@ -14,23 +14,33 @@ // /////////////////////////////////////////////////////////////////////////////// +#include // for not_null, operator<, operator<=, operator> #include -#include // for not_null, operator<, operator<=, operator> + +#include "deathTestCommon.h" using namespace gsl; namespace { -GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format off +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format on bool helper(not_null p) { return *p == 12; } +// clang-format off GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format on bool helper_const(not_null p) { return *p == 12; } +// clang-format off GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format on bool strict_helper(strict_not_null p) { return *p == 12; } +// clang-format off GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +// clang-format on bool strict_helper_const(strict_not_null p) { return *p == 12; } #ifdef CONFIRM_COMPILATION_ERRORS @@ -123,17 +133,14 @@ TEST(strict_notnull_tests, TestStrictNotNull) } #if defined(__cplusplus) && (__cplusplus >= 201703L) -namespace -{ -static constexpr char deathstring[] = "Expected Death"; -} TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); { int i = 42; @@ -161,7 +168,7 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) int* p1 = nullptr; const strict_not_null x{p1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { @@ -169,14 +176,14 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) const int* p1 = nullptr; const strict_not_null x{p1}; }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } { int* p = nullptr; - EXPECT_DEATH(helper(strict_not_null{p}), deathstring); - EXPECT_DEATH(helper_const(strict_not_null{p}), deathstring); + EXPECT_DEATH(helper(strict_not_null{p}), expected); + EXPECT_DEATH(helper_const(strict_not_null{p}), expected); } #ifdef CONFIRM_COMPILATION_ERRORS diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index 3c919d0..8cc45c6 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -16,7 +16,7 @@ #include -#include // for Expects, fail_fast (ptr only) +#include // for Expects, fail_fast (ptr only) #include // for owner #include // for span, dynamic_extent #include // for basic_string_span, operator==, ensure_z @@ -28,13 +28,11 @@ #include // for remove_reference<>::type #include // for vector, allocator +#include "deathTestCommon.h" + using namespace std; using namespace gsl; -namespace -{ -static constexpr char deathstring[] = "Expected Death"; -} // Generic string functions namespace generic @@ -76,8 +74,7 @@ T create() template void use(basic_string_span) -{ -} +{} #endif czstring_span<> CreateTempName(string_span<> span) @@ -85,7 +82,8 @@ czstring_span<> CreateTempName(string_span<> span) Expects(span.size() > 1); std::size_t last = 0; - if (span.size() > 4) { + if (span.size() > 4) + { span[0] = 't'; span[1] = 'm'; span[2] = 'p'; @@ -102,7 +100,8 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span) Expects(span.size() > 1); std::size_t last = 0; - if (span.size() > 4) { + if (span.size() > 4) + { span[0] = L't'; span[1] = L'm'; span[2] = L'p'; @@ -119,7 +118,8 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span) Expects(span.size() > 1); std::size_t last = 0; - if (span.size() > 4) { + if (span.size() > 4) + { span[0] = u't'; span[1] = u'm'; span[2] = u'p'; @@ -136,7 +136,8 @@ cu32zstring_span<> CreateTempNameU32(u32string_span<> span) Expects(span.size() > 1); std::size_t last = 0; - if (span.size() > 4) { + if (span.size() > 4) + { span[0] = U't'; span[1] = U'm'; span[2] = U'p'; @@ -950,10 +951,11 @@ TEST(string_span_tests, Conversion) TEST(string_span_tests, zstring) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. zstring"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); // create zspan from zero terminated string { @@ -973,7 +975,7 @@ TEST(string_span_tests, zstring) buf[0] = 'a'; auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } // usage scenario: create zero-terminated temp file name and pass to a legacy API @@ -981,7 +983,8 @@ TEST(string_span_tests, zstring) char buf[10]; auto name = CreateTempName({buf, 10}); - if (!name.empty()) { + if (!name.empty()) + { czstring<> str = name.assume_z(); EXPECT_TRUE(generic::strlen(str) == 3); EXPECT_TRUE(*(str + 3) == '\0'); @@ -991,10 +994,11 @@ TEST(string_span_tests, zstring) TEST(string_span_tests, wzstring) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. wzstring"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); // create zspan from zero terminated string { @@ -1014,7 +1018,7 @@ TEST(string_span_tests, wzstring) buf[0] = L'a'; const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } // usage scenario: create zero-terminated temp file name and pass to a legacy API @@ -1022,7 +1026,8 @@ TEST(string_span_tests, wzstring) wchar_t buf[10]; const auto name = CreateTempNameW({buf, 10}); - if (!name.empty()) { + if (!name.empty()) + { cwzstring<> str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); @@ -1032,10 +1037,11 @@ TEST(string_span_tests, wzstring) TEST(string_span_tests, u16zstring) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. u16zstring"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); // create zspan from zero terminated string { @@ -1055,7 +1061,7 @@ TEST(string_span_tests, u16zstring) buf[0] = u'a'; const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } // usage scenario: create zero-terminated temp file name and pass to a legacy API @@ -1063,7 +1069,8 @@ TEST(string_span_tests, u16zstring) char16_t buf[10]; const auto name = CreateTempNameU16({buf, 10}); - if (!name.empty()) { + if (!name.empty()) + { cu16zstring<> str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); @@ -1073,10 +1080,11 @@ TEST(string_span_tests, u16zstring) TEST(string_span_tests, u32zstring) { - std::set_terminate([] { + const auto terminateHandler = std::set_terminate([] { std::cerr << "Expected Death. u31zstring"; std::abort(); }); + const auto expected = GetExpectedDeathString(terminateHandler); // create zspan from zero terminated string { @@ -1096,7 +1104,7 @@ TEST(string_span_tests, u32zstring) buf[0] = u'a'; const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); }; - EXPECT_DEATH(workaround_macro(), deathstring); + EXPECT_DEATH(workaround_macro(), expected); } // usage scenario: create zero-terminated temp file name and pass to a legacy API @@ -1104,7 +1112,8 @@ TEST(string_span_tests, u32zstring) char32_t buf[10]; const auto name = CreateTempNameU32({buf, 10}); - if (!name.empty()) { + if (!name.empty()) + { cu32zstring<> str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index 74dc990..0585c79 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -16,14 +16,14 @@ #include -#include // finally, narrow_cast -#include // for narrow, narrowing_error #include // for move +#include // for std::ptrdiff_t #include // for reference_wrapper, _Bind_helper<>::type +#include // for narrow, narrowing_error +#include // finally, narrow_cast #include // for numeric_limits #include // for uint32_t, int32_t #include // for is_same -#include // for std::ptrdiff_t using namespace gsl; @@ -32,8 +32,7 @@ namespace void f(int& i) { i += 1; } static int j = 0; void g() { j += 1; } -} - +} // namespace TEST(utils_tests, sanity_check_for_gsl_index_typedef) { @@ -123,6 +122,7 @@ TEST(utils_tests, narrow_cast) EXPECT_TRUE(uc == 44); } +#ifndef GSL_KERNEL_MODE TEST(utils_tests, narrow) { int n = 120; @@ -145,3 +145,4 @@ TEST(utils_tests, narrow) n = -42; EXPECT_THROW(narrow(n), narrowing_error); } +#endif // GSL_KERNEL_MODE From 8a4b9ed0bf643726ce625678a17b1fc40d90870c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Wed, 23 Jun 2021 18:28:45 -0400 Subject: [PATCH 03/24] feat: narrow for non totally ordered types (#986) --- include/gsl/narrow | 19 ++++++++++++++++++- tests/utils_tests.cpp | 5 +++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/gsl/narrow b/include/gsl/narrow index 67aac05..40016d1 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -26,7 +26,7 @@ struct narrowing_error : public std::exception }; // narrow() : a checked version of narrow_cast() that throws if the cast changed the value -template +template ::value>::type* = nullptr> // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) @@ -45,5 +45,22 @@ GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recogn return t; } + +template ::value>::type* = nullptr> +// clang-format off +GSL_SUPPRESS(type.1) // NO-FORMAT: attribute +GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) + // clang-format on + constexpr T narrow(U u) noexcept(false) +{ + const T t = narrow_cast(u); + + if (static_cast(t) != u) + { + throw narrowing_error{}; + } + + return t; +} } // namespace gsl #endif // GSL_NARROW_H diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index 0585c79..39b4ca2 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -17,6 +17,7 @@ #include #include // for move +#include #include // for std::ptrdiff_t #include // for reference_wrapper, _Bind_helper<>::type #include // for narrow, narrowing_error @@ -144,5 +145,9 @@ TEST(utils_tests, narrow) n = -42; EXPECT_THROW(narrow(n), narrowing_error); + + EXPECT_TRUE( + narrow>(std::complex(4, 2)) == std::complex(4, 2)); + EXPECT_THROW(narrow>(std::complex(4.2)), narrowing_error); } #endif // GSL_KERNEL_MODE From f09b24970dfed112c57c3d21cf3b90273c9f7ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Thu, 16 Sep 2021 00:12:11 +0200 Subject: [PATCH 04/24] Fix gsl/util for c++20 compilers without (#993) For instance, clang 10 sets __cplusplus >= 202002L yet does not have span, which causes build errors: https://gcc.godbolt.org/z/Yq345zGea --- include/gsl/util | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/gsl/util b/include/gsl/util index db66aae..330b996 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -25,9 +25,12 @@ #include // for is_signed, integral_constant #include // for exchange, forward -#if defined(__cplusplus) && __cplusplus >= 202002L +#if defined(__has_include) && __has_include() +#include +#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L #include -#endif // __cplusplus >= 202002L +#endif // __cpp_lib_span >= 202002L +#endif //__has_include() #if defined(_MSC_VER) && !defined(__clang__) @@ -138,14 +141,14 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute return *(cont.begin() + i); } -#if defined(__cplusplus) && __cplusplus >= 202002L +#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L template constexpr auto at(std::span sp, const index i) { Expects(i >= 0 && i < narrow_cast(sp.size())); return sp[i]; } -#endif // __cplusplus >= 202002L +#endif // __cpp_lib_span >= 202002L } // namespace gsl #if defined(_MSC_VER) && !defined(__clang__) From da80ce15d87463cd9dd507b004d3d4e92c8e84f0 Mon Sep 17 00:00:00 2001 From: Werner Henze <34543625+beinhaerter@users.noreply.github.com> Date: Wed, 27 Oct 2021 01:50:58 +0200 Subject: [PATCH 05/24] make zstring family don't require empty angle brackets any more (#998) Co-authored-by: Werner Henze --- README.md | 16 ++++++++-------- include/gsl/string_span | 24 ++++++++---------------- tests/string_span_tests.cpp | 8 ++++---- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index e396057..073517e 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,14 @@ not_null | ☑ | restricts a pointer / smart po span | ☑ | a view over a contiguous sequence of memory. Based on the standardized verison of `std::span`, however `gsl::span` enforces bounds checking. See the [wiki](https://github.com/microsoft/GSL/wiki/gsl::span-and-std::span) for additional information. span_p | ☐ | spans a range starting from a pointer to the first place for which the predicate is true basic_zstring | ☑ | A pointer to a C-string (zero-terminated array) with a templated char type -zstring | ☑ | An alias to `basic_zstring` with a char type of char -czstring | ☑ | An alias to `basic_zstring` with a char type of const char -wzstring | ☑ | An alias to `basic_zstring` with a char type of wchar_t -cwzstring | ☑ | An alias to `basic_zstring` with a char type of const wchar_t -u16zstring | ☑ | An alias to `basic_zstring` with a char type of char16_t -cu16zstring | ☑ | An alias to `basic_zstring` with a char type of const char16_t -u32zstring | ☑ | An alias to `basic_zstring` with a char type of char32_t -cu32zstring | ☑ | An alias to `basic_zstring` with a char type of const char32_t +zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of char +czstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of const char +wzstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of wchar_t +cwzstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of const wchar_t +u16zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of char16_t +cu16zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of const char16_t +u32zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of char32_t +cu32zstring | ☑ | An alias to `basic_zstring` with dynamic extent and a char type of const char32_t [**2. Owners**][cg-owners] | | unique_ptr | ☑ | an alias to `std::unique_ptr` shared_ptr | ☑ | an alias to `std::shared_ptr` diff --git a/include/gsl/string_span b/include/gsl/string_span index a76236d..bcc672a 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -59,29 +59,21 @@ namespace gsl template using basic_zstring = CharT*; -template -using czstring = basic_zstring; +using czstring = basic_zstring; -template -using cwzstring = basic_zstring; +using cwzstring = basic_zstring; -template -using cu16zstring = basic_zstring; +using cu16zstring = basic_zstring; -template -using cu32zstring = basic_zstring; +using cu32zstring = basic_zstring; -template -using zstring = basic_zstring; +using zstring = basic_zstring; -template -using wzstring = basic_zstring; +using wzstring = basic_zstring; -template -using u16zstring = basic_zstring; +using u16zstring = basic_zstring; -template -using u32zstring = basic_zstring; +using u32zstring = basic_zstring; namespace details { diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index 8cc45c6..ed42b38 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -985,7 +985,7 @@ TEST(string_span_tests, zstring) auto name = CreateTempName({buf, 10}); if (!name.empty()) { - czstring<> str = name.assume_z(); + czstring str = name.assume_z(); EXPECT_TRUE(generic::strlen(str) == 3); EXPECT_TRUE(*(str + 3) == '\0'); } @@ -1028,7 +1028,7 @@ TEST(string_span_tests, wzstring) const auto name = CreateTempNameW({buf, 10}); if (!name.empty()) { - cwzstring<> str = name.assume_z(); + cwzstring str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); } @@ -1071,7 +1071,7 @@ TEST(string_span_tests, u16zstring) const auto name = CreateTempNameU16({buf, 10}); if (!name.empty()) { - cu16zstring<> str = name.assume_z(); + cu16zstring str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); } @@ -1114,7 +1114,7 @@ TEST(string_span_tests, u32zstring) const auto name = CreateTempNameU32({buf, 10}); if (!name.empty()) { - cu32zstring<> str = name.assume_z(); + cu32zstring str = name.assume_z(); EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(*(str + 3) == L'\0'); } From c31a9ad5e8e99da8567237a7ba51a7d8f419e5bf Mon Sep 17 00:00:00 2001 From: Jordan Maples <4483361+SloppyJaconda@users.noreply.github.com> Date: Tue, 26 Oct 2021 16:52:07 -0700 Subject: [PATCH 06/24] Delete .travis.yml (#995) --- .travis.yml | 337 ---------------------------------------------------- 1 file changed, 337 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a57955c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,337 +0,0 @@ - -language: cpp -notifications: - email: false - -# Use Linux unless specified otherwise -os: linux -dist: bionic - -cache: - directories: - - ${TRAVIS_BUILD_DIR}/deps - -stages: - - name: Latest # Compiler with the latest major version - - name: Previous # Compilers with the major version Latest - 1 - - name: Validation # run other jobs - -jobs: - include: - - ########################################################################## - # Validate CMake configuration - ########################################################################## - - - name: CMake 3.1.3 - latest - stage: Validation - env: &CMAKE_VERSION_LIST - - CMAKE_VERSION: '"3.17.0 3.16.5 3.15.7 3.14.7 3.13.5 3.12.4 3.11.4 3.10.3 3.9.6 3.8.2 3.7.2 3.6.3 3.5.2 3.4.3 3.3.2 3.2.3 3.1.3"' - - GSL_CXX_STANDARD: 14 - addons: # Get latest release (candidate) - apt: - sources: - - sourceline: 'deb https://apt.kitware.com/ubuntu/ bionic main' - key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' - - sourceline: 'deb https://apt.kitware.com/ubuntu/ bionic-rc main' - packages: - - cmake - script: - - | - cd ./build - ( set -eu - for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done - export CXX=clang++ - for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done - ) - - - name: CMake 3.2.3 - 3.17.0 - stage: Validation - os: osx - osx_image: xcode11.3 - env: - - CMAKE_VERSION: '"3.17.0 3.16.5 3.15.7 3.14.7 3.13.5 3.12.4 3.11.4 3.10.3 3.9.6 3.8.2 3.7.2 3.6.3 3.5.2 3.4.3 3.3.2 3.2.3"' - script: - - | - cd ./build - ( set -eu - for CMAKE in ${CMAKE_path[@]}; do test_CMake_generate $CMAKE; done - ) - - ########################################################################## - # AppleClang on OSX - ########################################################################## - - - - # Xcode 10.3 - - name: AppleClang Xcode-10.3 C++14 Debug - stage: Previous - env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - os: osx - osx_image: xcode10.3 # AppleClang 10.0.1 same compiler as Xcode 10.2 - - name: AppleClang Xcode-10.3 C++14 Release - env: BUILD_TYPE=Release GSL_CXX_STANDARD=14 - os: osx - osx_image: xcode10.3 - - name: AppleClang Xcode-10.3 C++17 Debug - env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - os: osx - osx_image: xcode10.3 - - name: AppleClang Xcode-10.3 C++17 Release - env: BUILD_TYPE=Release GSL_CXX_STANDARD=17 - os: osx - osx_image: xcode10.3 - - - # Xcode 11.4 - - name: AppleClang Xcode-11.4 C++17 Debug - stage: Latest - env: BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - os: osx - osx_image: xcode11.4 - - name: AppleClang Xcode-11.4 C++17 Release - env: BUILD_TYPE=Release GSL_CXX_STANDARD=17 - os: osx - osx_image: xcode11.4 - - name: AppleClang Xcode-11.4 C++14 Debug - env: BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - os: osx - osx_image: xcode11.4 - - name: AppleClang Xcode-11.4 C++14 Release - env: BUILD_TYPE=Release GSL_CXX_STANDARD=14 - os: osx - osx_image: xcode11.4 - - ########################################################################## - # Clang on Linux - ########################################################################## - - # Clang 9 - - name: Clang-9 C++14 Debug - stage: Previous - env: CXX=clang++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - addons: &clang9 - apt: - sources: - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' - key_url: https://apt.llvm.org/llvm-snapshot.gpg.key - packages: - - clang-9 - - name: Clang-9 C++14 Release - env: CXX=clang++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=14 - addons: *clang9 - - name: Clang-9 C++17 Debug - env: CXX=clang++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - addons: *clang9 - - name: Clang-9 C++17 Release - env: CXX=clang++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=17 - addons: *clang9 - - # Clang 10 - - name: Clang-10 C++14 Debug - stage: Latest - env: CXX=clang++-10 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - addons: &clang10 - apt: - sources: - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' - key_url: https://apt.llvm.org/llvm-snapshot.gpg.key - packages: - - clang-10 - - name: Clang-10 C++14 Release - env: CXX=clang++-10 BUILD_TYPE=Release GSL_CXX_STANDARD=14 - addons: *clang10 - - name: Clang-10 C++17 Debug - env: CXX=clang++-10 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - addons: *clang10 - - name: Clang-10 C++17 Release - env: CXX=clang++-10 BUILD_TYPE=Release GSL_CXX_STANDARD=17 - addons: *clang10 - - ########################################################################## - # GCC on Linux - ########################################################################## - - # GCC 8 - - name: GCC-8 C++14 Debug - stage: Previous - env: CXX=g++-8 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - addons: &gcc8 - apt: - packages: g++-8 - - name: GCC-8 C++14 Release - env: CXX=g++-8 BUILD_TYPE=Release GSL_CXX_STANDARD=14 - addons: *gcc8 - - name: GCC-8 C++17 Debug - env: CXX=g++-8 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - addons: *gcc8 - - name: GCC-8 C++17 Release - env: CXX=g++-8 BUILD_TYPE=Release GSL_CXX_STANDARD=17 - addons: *gcc8 - - # GCC 9 - - name: GCC-9 C++14 Debug - stage: Latest - env: CXX=g++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=14 - addons: &gcc9 - apt: - sources: - - sourceline: ppa:ubuntu-toolchain-r/test - packages: - - g++-9 - - name: GCC-9 C++14 Release - env: CXX=g++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=14 - addons: *gcc9 - - name: GCC-9 C++17 Debug - env: CXX=g++-9 BUILD_TYPE=Debug GSL_CXX_STANDARD=17 - addons: *gcc9 - - name: GCC-9 C++17 Release - env: CXX=g++-9 BUILD_TYPE=Release GSL_CXX_STANDARD=17 - addons: *gcc9 - -before_install: - - | - # Configuration - JOBS=2 # Travis machines have 2 cores - # Dependencies required by the CI (cached directory) - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" - - | - # Setup - mkdir -p "${DEPS_DIR:?}" && cd "${DEPS_DIR:?}" - mkdir -p ~/tools && cd ~/tools - if [[ ${TRAVIS_OS_NAME:?} == "osx" ]]; then - export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH" - fi - - | - # Helper functions - # usage: if [[ $(check_url '') ]]; then ... - function check_url {( set +e - if [[ "$1" =~ 'github.com' ]]; then # check for first byte - if curl --fail --silent --output /dev/null --connect-timeout 12 --range 0-0 "$1" - then echo true; fi - else # request head - if curl --fail --silent --output /dev/null --connect-timeout 12 --head "$1" - then echo true; fi - fi - return - )} - -install: - ############################################################################ - # Install a different CMake version (or several) - ############################################################################ - - | - # Install CMake versions - ( set -euo pipefail - if [[ ${CMAKE_VERSION:-} ]]; then - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then - OS="Linux"; EXT="sh" - if [[ ! ("${CMAKE_VERSION:-}" =~ .+[' '].+) ]]; then - # Single entry -> default CMake version - CMAKE_DEFAULT_DIR="/usr/local" - fi - elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then OS="Darwin"; EXT="tar.gz" - else echo "CMake install not supported for this OS."; exit 1 - fi - CMAKE_INSTALLER="install-cmake.${EXT}" - fi - for VERSION in ${CMAKE_VERSION:-}; do - CMAKE_URL="https://github.com/Kitware/CMake/releases/download/v${VERSION}/cmake-${VERSION}-${OS}-x86_64.${EXT}" - if [[ $(check_url "$CMAKE_URL") ]]; then - curl -sSL ${CMAKE_URL} -o ${CMAKE_INSTALLER} - CMAKE_DIR="${CMAKE_DEFAULT_DIR:-"${HOME}/tools/cmake-${VERSION}"}" - mkdir -p ${CMAKE_DIR} - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then - chmod +x ${CMAKE_INSTALLER} - sudo ./${CMAKE_INSTALLER} --prefix=${CMAKE_DIR} --skip-license - else # OSX - mkdir -p ./CMake_tmp - tar --extract --gzip --file=${CMAKE_INSTALLER} --directory=./CMake_tmp - mv ./CMake_tmp/*/CMake.app/Contents/* ${CMAKE_DIR} - fi - rm --recursive --force ./CMake_tmp ${CMAKE_INSTALLER} - else echo 'Invalid url!'; echo "Version: ${VERSION}" - fi - done - ) - if [[ ${CMAKE_VERSION:-} && "${TRAVIS_OS_NAME:?}" == "osx" && ! ("${CMAKE_VERSION:-}" =~ .+[' '].+) ]] - then # Single entry -> default CMake version - export PATH=${HOME}/tools/cmake-${CMAKE_VERSION:?}/bin:$PATH - fi - CMAKE_path=("cmake") # start with installed CMake version - for VERSION in ${CMAKE_VERSION:-}; do - tmp_path="$HOME/tools/cmake-${VERSION:?}/bin/cmake" - if [[ -x "$(command -v ${tmp_path:?})" ]]; then CMAKE_path+=("${tmp_path:?}"); fi - done - function test_CMake_generate { - # $1: cmake or full path to cmake - shopt -s extglob - if [[ "$1" == "cmake" || -x "$(command -v $1)" && "$1" =~ .*cmake$ ]]; then - echo "----------------" - $1 --version - echo "Configuration = ${BUILD_TYPE:-Debug}" - $1 -DCMAKE_BUILD_TYPE=${BUILD_TYPE:-Debug} ${CMAKE_GEN_FLAGS[@]:?} .. - rm -rf !(tests/googletest-*) - if [[ ! ${BUILD_TYPE:-} ]]; then echo "" && echo "Configuration = Release" - $1 -DCMAKE_BUILD_TYPE=Release ${CMAKE_GEN_FLAGS[@]:?} .. - rm -rf !(tests/googletest-*) - fi - else echo "Non existing command: $1" - fi - } - - | - # CMake wrapper (Trusty, Xenial & Bionic); restore default behaviour. - if [[ "${TRAVIS_OS_NAME:?}" == "linux" && - "$(lsb_release --codename)" =~ (trusty|xenial|bionic)$ ]] - then - if [[ -x $(command -v /usr/local/bin/cmake) ]]; then - function cmake { command /usr/local/bin/cmake $@; } - elif [[ -x $(command -v /usr/bin/cmake) ]]; then - function cmake { command /usr/bin/cmake $@; } - fi - fi - - ############################################################################ - # [linux]: Install the right version of libc++ - # Based on https://github.com/ldionne/hana/blob/master/.travis.yml - ############################################################################ - - | - LLVM_INSTALL=${DEPS_DIR:?}/llvm/install - # if in linux and compiler clang and llvm not installed - if [[ "${TRAVIS_OS_NAME:?}" == "linux" && "${CXX%%+*}" == "clang" && -n "$(ls -A ${LLVM_INSTALL:?})" ]]; then - if [[ "${CXX}" == "clang++-3.6" ]]; then LLVM_VERSION="3.6.2"; - elif [[ "${CXX}" == "clang++-3.7" ]]; then LLVM_VERSION="3.7.1"; - elif [[ "${CXX}" == "clang++-3.8" ]]; then LLVM_VERSION="3.8.1"; - elif [[ "${CXX}" == "clang++-3.9" ]]; then LLVM_VERSION="3.9.1"; - fi - LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz" - LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz" - LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz" - mkdir -p llvm llvm/build llvm/projects/libcxx llvm/projects/libcxxabi - travis_retry wget -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C llvm - travis_retry wget -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxx - travis_retry wget -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C llvm/projects/libcxxabi - (cd llvm/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_INSTALL}) - (cd llvm/build/projects/libcxx && make install -j2) - (cd llvm/build/projects/libcxxabi && make install -j2) - export CXXFLAGS="-isystem ${LLVM_INSTALL}/include/c++/v1" - export LDFLAGS="-L ${LLVM_INSTALL}/lib -l c++ -l c++abi" - export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_INSTALL}/lib" - fi - -before_script: - - | - cd "${TRAVIS_BUILD_DIR:?}" - mkdir build && cd build - if [[ ${GSL_CXX_STANDARD:-} ]]; then - CMAKE_GEN_FLAGS=("-DGSL_CXX_STANDARD=$GSL_CXX_STANDARD") - fi - CMAKE_GEN_FLAGS+=("-Wdev -Werror=dev --warn-uninitialized") - -script: - # generate build files - - cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE:?} ${CMAKE_GEN_FLAGS[@]:?} - # build and run tests - - cmake --build . -- -j${JOBS} - - ctest --output-on-failure -j${JOBS} From e0880931ae5885eb988d1a8a57acf8bc2b8dacda Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Wed, 17 Nov 2021 12:24:40 -0800 Subject: [PATCH 07/24] Fix googletest build failure with gcc 11.1+ (#1015) --- tests/CMakeLists.txt.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt.in b/tests/CMakeLists.txt.in index 1b10044..2535f8f 100644 --- a/tests/CMakeLists.txt.in +++ b/tests/CMakeLists.txt.in @@ -4,7 +4,7 @@ project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG 389cb68b87193358358ae87cc56d257fd0d80189 + GIT_TAG 1b18723e874b256c1e39378c6774a90701d70f7a SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" From bcf008ae5578fab638e6d30b7ca000f306b14d3b Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Thu, 9 Dec 2021 14:54:06 -0800 Subject: [PATCH 08/24] Fix/implement C++2020 compilation, tests, and CI (#1017) * Fix C++20 bugs and tests * Rework CI for C++2020 tests * Update readme compiler versions --- README.md | 12 +++++----- azure-pipelines.yml | 6 +++++ include/gsl/util | 6 ++--- pipelines/jobs.yml | 35 ++++++++++++----------------- pipelines/steps.yml | 6 ++++- tests/CMakeLists.txt | 11 ++++++++- tests/algorithm_tests.cpp | 5 ++--- tests/at_tests.cpp | 20 +++++++++++------ tests/span_compatibility_tests.cpp | 6 ++--- tests/span_ext_tests.cpp | 36 +++++++++++++++--------------- tests/span_tests.cpp | 3 +-- tests/string_span_tests.cpp | 1 - 12 files changed, 80 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 073517e..34f87f0 100644 --- a/README.md +++ b/README.md @@ -86,16 +86,14 @@ This is based on [CppCoreGuidelines semi-specification](https://github.com/isocp # Quick Start ## Supported Compilers -The GSL officially supports the current and previous major release of MSVC, GCC, Clang, and XCode's Apple-Clang. -See our latest test results for the most up-to-date list of supported configurations. +The GSL officially supports the following versions of MSVC, GCC, Clang, and XCode's Apple-Clang. Compiler |Toolset Versions Currently Tested :------- |--: - XCode |11.4 & 10.3 - GCC |9 & 8 - Clang |11 & 10 - Visual Studio with MSVC | VS2017 (15.9) & VS2019 (16.4) - Visual Studio with LLVM | VS2017 (Clang 9) & VS2019 (Clang 10) + XCode | 12.4 & 11.3 + GCC | 9.3.0 & 7.5.0 + Clang | 11.0.0 & 9.0.0 + Visual Studio with MSVC | VS2017 (15.9.21) & VS2019 (16.11.2) --- If you successfully port GSL to another platform, we would love to hear from you! diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0d1219a..8ab761e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,10 +18,12 @@ stages: parameters: jobName: 'Validate GCC latest' imageName: ubuntu-20.04 + CXXVersions: [ 14, 17 ] - template: ./pipelines/jobs.yml parameters: jobName: 'Validate GCC Previous' imageName: ubuntu-18.04 + CXXVersions: [ 14, 17 ] # Clang - stage: Clang @@ -40,6 +42,7 @@ stages: parameters: jobName: 'Validate Clang Previous' imageName: ubuntu-18.04 + CXXVersions: [ 14, 17 ] # MSVC - stage: MSVC @@ -53,6 +56,7 @@ stages: parameters: jobName: 'Validate MSVC Previous' imageName: vs2017-win2016 + CXXVersions: [ 14, 17 ] # Apple-Clang - stage: Apple_Clang @@ -62,7 +66,9 @@ stages: parameters: jobName: 'Validate Apple-Clang latest' imageName: macos-10.15 + CXXVersions: [ 14, 17 ] - template: ./pipelines/jobs.yml parameters: jobName: 'Validate Apple-Clang Previous' imageName: macos-10.14 + CXXVersions: [ 14, 17 ] diff --git a/include/gsl/util b/include/gsl/util index 330b996..a215bad 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -143,10 +143,10 @@ GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L template -constexpr auto at(std::span sp, const index i) +constexpr auto at(std::span sp, const index i) -> decltype(sp[sp.size()]) { - Expects(i >= 0 && i < narrow_cast(sp.size())); - return sp[i]; + Expects(i >= 0 && i < narrow_cast(sp.size())); + return sp[gsl::narrow_cast(i)]; } #endif // __cpp_lib_span >= 202002L } // namespace gsl diff --git a/pipelines/jobs.yml b/pipelines/jobs.yml index dad2414..783c46d 100644 --- a/pipelines/jobs.yml +++ b/pipelines/jobs.yml @@ -1,26 +1,19 @@ parameters: jobName: '' imageName: '' + CXXVersions: [ 14, 17, 20 ] + buildTypes: [ 'Debug', 'Release' ] jobs: -- job: - displayName: ${{ parameters.imageName }} - pool: - vmImage: ${{ parameters.imageName }} - strategy: - matrix: - 14_debug: - GSL_CXX_STANDARD: '14' - BUILD_TYPE: 'Debug' - 14_release: - GSL_CXX_STANDARD: '14' - BUILD_TYPE: 'Release' - 17_debug: - GSL_CXX_STANDARD: '17' - BUILD_TYPE: 'Debug' - 17_release: - GSL_CXX_STANDARD: '17' - BUILD_TYPE: 'Release' - continueOnError: false - steps: - - template: ./steps.yml +- ${{ each CXXVersion in parameters.CXXVersions }}: + - ${{ each buildType in parameters.buildTypes }}: + - job: + displayName: ${{ format('{0} {1} C++{2}', parameters.imageName, buildType, CXXVersion) }} + pool: + vmImage: ${{ parameters.imageName }} + continueOnError: false + steps: + - template: ./steps.yml + parameters: + buildType: ${{ buildType }} + CXXVersion: ${{ CXXVersion }} diff --git a/pipelines/steps.yml b/pipelines/steps.yml index 41a7fca..2e80713 100644 --- a/pipelines/steps.yml +++ b/pipelines/steps.yml @@ -1,9 +1,13 @@ +parameters: + buildType: '' + CXXVersion: '' + steps: - task: CMake@1 name: Configure inputs: workingDirectory: build - cmakeArgs: '-DCMAKE_CXX_STANDARD=$(GSL_CXX_STANDARD) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -Werror=dev .. ' + cmakeArgs: '-DGSL_CXX_STANDARD=${{ parameters.CXXVersion }} -DCMAKE_BUILD_TYPE=${{ parameters.buildType }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev .. ' - task: CMake@1 name: Build diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c05aaa7..dd71105 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,10 @@ include(ExternalProject) # will make visual studio generated project group files set_property(GLOBAL PROPERTY USE_FOLDERS ON) +if(CI_TESTING AND GSL_CXX_STANDARD EQUAL 20) + add_compile_definitions(FORCE_STD_SPAN_TESTS=1) +endif() + if(IOS) add_compile_definitions(GTEST_HAS_DEATH_TEST=1 IOS_PROCESS_DELAY_WORKAROUND=1) endif() @@ -54,7 +58,7 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) find_package(Microsoft.GSL REQUIRED) endif() -if (MSVC AND (GSL_CXX_STANDARD EQUAL 17)) +if (MSVC AND (GSL_CXX_STANDARD GREATER_EQUAL 17)) set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-) endif() @@ -135,6 +139,11 @@ else() $<$,4.99>,$,6>>: $<$:-Wno-undefined-func-template> > + $<$,$>: + -Wno-zero-as-null-pointer-constant # failing Clang Ubuntu 20.04 tests, seems to be a bug with clang 11.0.0 + # (operator< is being re-written by the compiler as operator<=> and + # raising the warning) + > > $<$: $<$,9.1>,$,10>>: diff --git a/tests/algorithm_tests.cpp b/tests/algorithm_tests.cpp index 16746b4..e369be0 100644 --- a/tests/algorithm_tests.cpp +++ b/tests/algorithm_tests.cpp @@ -27,7 +27,6 @@ namespace gsl struct fail_fast; } // namespace gsl -using namespace std; using namespace gsl; TEST(algorithm_tests, same_type) @@ -73,8 +72,8 @@ TEST(algorithm_tests, same_type) std::array src{1, 2, 3, 4, 5}; std::array dst{}; - const span src_span(src); - const span dst_span(dst); + const gsl::span src_span(src); + const gsl::span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index 92a8e4d..93e6b7b 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -119,7 +119,7 @@ TEST(at_tests, InitializerList) EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected); } -#if defined(__cplusplus) && __cplusplus >= 202002L +#if defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L TEST(at_tests, std_span) { std::vector vec{1, 2, 3, 4, 5}; @@ -128,18 +128,24 @@ TEST(at_tests, std_span) std::vector cvec{1, 2, 3, 4, 5}; std::span csp{cvec}; - for (size_t i = 0, i < vec.size(); ++i) + for (gsl::index i = 0; i < gsl::narrow_cast(vec.size()); ++i) { - EXPECT_TRUE(&gsl::at(sp, i) == &vec[i]); - EXPECT_TRUE(&gsl::at(csp, i) == &cvec[i]); + EXPECT_TRUE(&gsl::at(sp, i) == &vec[gsl::narrow_cast(i)]); + EXPECT_TRUE(&gsl::at(csp, i) == &cvec[gsl::narrow_cast(i)]); } + const auto terminateHandler = std::set_terminate([] { + std::cerr << "Expected Death. std_span"; + std::abort(); + }); + const auto expected = GetExpectedDeathString(terminateHandler); + EXPECT_DEATH(gsl::at(sp, -1), expected); - EXPECT_DEATH(gsl::at(sp, sp.size()), expected); + EXPECT_DEATH(gsl::at(sp, gsl::narrow_cast(sp.size())), expected); EXPECT_DEATH(gsl::at(csp, -1), expected); - EXPECT_DEATH(gsl::at(csp, sp.size()), expected); + EXPECT_DEATH(gsl::at(csp, gsl::narrow_cast(sp.size())), expected); } -#endif // __cplusplus >= 202002L +#endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 static constexpr bool test_constexpr() diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp index 56bd385..95d8223 100644 --- a/tests/span_compatibility_tests.cpp +++ b/tests/span_compatibility_tests.cpp @@ -55,14 +55,14 @@ void ArrayConvertibilityCheck() EXPECT_TRUE(sp_const_nullptr_1.data() == stl_nullptr.data()); EXPECT_TRUE(sp_const_nullptr_1.size() == 3); - span sp_const_nullptr_2{std::as_const(stl_nullptr)}; + gsl::span sp_const_nullptr_2{std::as_const(stl_nullptr)}; EXPECT_TRUE(sp_const_nullptr_2.data() == stl_nullptr.data()); EXPECT_TRUE(sp_const_nullptr_2.size() == 3); - static_assert(std::is_same>::value, + static_assert(std::is_same>::value, "std::is_same< decltype(span{stl_nullptr}), span>::value"); static_assert( - std::is_same>::value, + std::is_same>::value, "std::is_same< decltype(span{std::as_const(stl_nullptr)}), span>::value"); } diff --git a/tests/span_ext_tests.cpp b/tests/span_ext_tests.cpp index 7ce4e51..3d35f8f 100644 --- a/tests/span_ext_tests.cpp +++ b/tests/span_ext_tests.cpp @@ -48,7 +48,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor) { int* p = nullptr; - auto s = make_span(p, narrow_cast::size_type>(0)); + auto s = make_span(p, narrow_cast::size_type>(0)); EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.data() == nullptr); } @@ -136,9 +136,9 @@ TEST(span_ext_test, make_span_from_std_array_constructor) // This test checks for the bug found in gcc 6.1, 6.2, 6.3, 6.4, 6.5 7.1, 7.2, 7.3 - issue #590 { - span s1 = make_span(arr); + gsl::span s1 = make_span(arr); - static span s2; + static gsl::span s2; s2 = s1; #if defined(__GNUC__) && __GNUC__ == 6 && (__GNUC_MINOR__ == 4 || __GNUC_MINOR__ == 5) && \ @@ -194,7 +194,7 @@ TEST(span_ext_test, make_span_from_container_constructor) TEST(span_test, interop_with_gsl_at) { int arr[5] = {1, 2, 3, 4, 5}; - span s{arr}; + gsl::span s{arr}; EXPECT_TRUE(at(s, 0) == 1); EXPECT_TRUE(at(s, 1) == 2); } @@ -202,7 +202,7 @@ TEST(span_test, interop_with_gsl_at) TEST(span_ext_test, iterator_free_functions) { int a[] = {1, 2, 3, 4}; - span s{a}; + gsl::span s{a}; EXPECT_TRUE((std::is_same::value)); EXPECT_TRUE((std::is_same::value)); @@ -232,7 +232,7 @@ TEST(span_ext_test, iterator_free_functions) TEST(span_ext_test, ssize_free_function) { int a[] = {1, 2, 3, 4}; - span s{a}; + gsl::span s{a}; EXPECT_FALSE((std::is_same::value)); EXPECT_TRUE(s.size() == static_cast(ssize(s))); @@ -242,8 +242,8 @@ TEST(span_ext_test, ssize_free_function) TEST(span_ext_test, comparison_operators) { { - span s1; - span s2; + gsl::span s1; + gsl::span s2; EXPECT_TRUE(s1 == s2); EXPECT_FALSE(s1 != s2); EXPECT_FALSE(s1 < s2); @@ -260,8 +260,8 @@ TEST(span_ext_test, comparison_operators) { int arr[] = {2, 1}; - span s1 = arr; - span s2 = arr; + gsl::span s1 = arr; + gsl::span s2 = arr; EXPECT_TRUE(s1 == s2); EXPECT_FALSE(s1 != s2); @@ -280,8 +280,8 @@ TEST(span_ext_test, comparison_operators) { int arr[] = {2, 1}; // bigger - span s1; - span s2 = arr; + gsl::span s1; + gsl::span s2 = arr; EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s2 != s1); @@ -300,8 +300,8 @@ TEST(span_ext_test, comparison_operators) { int arr1[] = {1, 2}; int arr2[] = {1, 2}; - span s1 = arr1; - span s2 = arr2; + gsl::span s1 = arr1; + gsl::span s2 = arr2; EXPECT_TRUE(s1 == s2); EXPECT_FALSE(s1 != s2); @@ -320,8 +320,8 @@ TEST(span_ext_test, comparison_operators) { int arr[] = {1, 2, 3}; - span s1 = {&arr[0], 2}; // shorter - span s2 = arr; // longer + gsl::span s1 = {&arr[0], 2}; // shorter + gsl::span s2 = arr; // longer EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s2 != s1); @@ -341,8 +341,8 @@ TEST(span_ext_test, comparison_operators) int arr1[] = {1, 2}; // smaller int arr2[] = {2, 1}; // bigger - span s1 = arr1; - span s2 = arr2; + gsl::span s1 = arr1; + gsl::span s2 = arr2; EXPECT_TRUE(s1 != s2); EXPECT_TRUE(s2 != s1); diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 1e0222e..33ccf56 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -43,7 +43,6 @@ #include "deathTestCommon.h" -using namespace std; using namespace gsl; namespace @@ -1085,7 +1084,7 @@ TEST(span_test, as_bytes) int b[5] = {1, 2, 3, 4, 5}; { - span sp(begin(b), static_cast(-2)); + span sp(std::begin(b), static_cast(-2)); EXPECT_DEATH((void) sp.size_bytes(), expected); } } diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index ed42b38..45a67d9 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -30,7 +30,6 @@ #include "deathTestCommon.h" -using namespace std; using namespace gsl; // Generic string functions From c412deb31e73c9b824abeb6619e11511b279222f Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Fri, 10 Dec 2021 11:17:47 -0800 Subject: [PATCH 09/24] Update compiler support (#1019) --- README.md | 18 ++++++--- azure-pipelines.yml | 85 +++++++++++++++++++-------------------- pipelines/jobs.yml | 52 +++++++++++++++++------- pipelines/setup_apple.yml | 9 +++++ pipelines/setup_clang.yml | 13 ++++++ pipelines/setup_gcc.yml | 14 +++++++ pipelines/steps.yml | 21 ---------- tests/CMakeLists.txt | 8 ++-- 8 files changed, 131 insertions(+), 89 deletions(-) create mode 100644 pipelines/setup_apple.yml create mode 100644 pipelines/setup_clang.yml create mode 100644 pipelines/setup_gcc.yml diff --git a/README.md b/README.md index 34f87f0..f0367eb 100644 --- a/README.md +++ b/README.md @@ -85,15 +85,21 @@ This is based on [CppCoreGuidelines semi-specification](https://github.com/isocp [cg-concepts]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gslconcept-concepts # Quick Start -## Supported Compilers -The GSL officially supports the following versions of MSVC, GCC, Clang, and XCode's Apple-Clang. +## Supported Compilers / Toolsets +The GSL officially supports the latest and previous major versions of VS with MSVC & LLVM, GCC, Clang, and XCode with Apple-Clang. +Within these two major versions, we try to target the latest minor updates / revisions (although this may be affected by +delays between a toolchain's release and when it becomes widely available for use). +Below is a table showing the versions currently being tested. Compiler |Toolset Versions Currently Tested :------- |--: - XCode | 12.4 & 11.3 - GCC | 9.3.0 & 7.5.0 - Clang | 11.0.0 & 9.0.0 - Visual Studio with MSVC | VS2017 (15.9.21) & VS2019 (16.11.2) + XCode | 13.1 & 12.5.1 + GCC | 11.1.0 & 10.3.0 + Clang | 11.0.0 & 10.0.0 + Visual Studio with MSVC | VS2019 (16.11) & VS2022 (17.0) + Visual Studio with LLVM | VS2019 (16.11) + +- Support for Visual Studio 2022 with LLVM will be added in the near future --- If you successfully port GSL to another platform, we would love to hear from you! diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8ab761e..a82e3c4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,71 +4,68 @@ trigger: pr: autoCancel: true -# GCC stages: - stage: GCC dependsOn: [] - variables: - - name: CC - value: gcc - - name: CXX - value: g++ jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate GCC latest' - imageName: ubuntu-20.04 - CXXVersions: [ 14, 17 ] - - template: ./pipelines/jobs.yml - parameters: - jobName: 'Validate GCC Previous' - imageName: ubuntu-18.04 - CXXVersions: [ 14, 17 ] + compiler: gcc + image: ubuntu-20.04 + compilerVersions: [ 11, 10 ] + setupfile: 'setup_gcc.yml' -# Clang - stage: Clang dependsOn: [] - variables: - - name: CC - value: clang - - name: CXX - value: clang++ jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate Clang latest' - imageName: ubuntu-20.04 - - template: ./pipelines/jobs.yml - parameters: - jobName: 'Validate Clang Previous' - imageName: ubuntu-18.04 - CXXVersions: [ 14, 17 ] + compiler: clang + image: ubuntu-20.04 + compilerVersions: [ 11, 10 ] + setupfile: 'setup_clang.yml' -# MSVC -- stage: MSVC +- stage: Xcode dependsOn: [] jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate MSVC latest' - imageName: windows-latest - - template: ./pipelines/jobs.yml - parameters: - jobName: 'Validate MSVC Previous' - imageName: vs2017-win2016 - CXXVersions: [ 14, 17 ] + compiler: 'Xcode' + image: macOS-11 + compilerVersions: [ '12.5.1', '13.1' ] + setupfile: 'setup_apple.yml' -# Apple-Clang -- stage: Apple_Clang +- stage: VS_MSVC dependsOn: [] jobs: - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate Apple-Clang latest' - imageName: macos-10.15 - CXXVersions: [ 14, 17 ] + compiler: 'VS2019 (16.11)' + compilerVersions: [ 'MSVC' ] + image: windows-2019 - template: ./pipelines/jobs.yml parameters: - jobName: 'Validate Apple-Clang Previous' - imageName: macos-10.14 - CXXVersions: [ 14, 17 ] + compiler: 'VS2022 (17.0)' + compilerVersions: [ 'MSVC' ] + image: windows-2022 + +- stage: VS_LLVM + dependsOn: [] + jobs: + - template: ./pipelines/jobs.yml + parameters: + compiler: 'VS2019 (16.11)' + compilerVersions: [ 'LLVM' ] + image: windows-2019 + extraCmakeArgs: '-T ClangCL' + +# The *same* config as with 2019 but on 2022 yields an error. +# Tracking issue: https://github.com/actions/virtual-environments/issues/4716 +# - template: ./pipelines/jobs.yml +# parameters: +# compiler: 'VS2022 LLVM' +# compilerVersions: [ '17.0' ] +# image: windows-2022 +# extraCmakeArgs: '-T ClangCL' +# CXXVersions: [ 14 ] +# buildTypes: [ Release ] diff --git a/pipelines/jobs.yml b/pipelines/jobs.yml index 783c46d..aabd3db 100644 --- a/pipelines/jobs.yml +++ b/pipelines/jobs.yml @@ -1,19 +1,43 @@ parameters: - jobName: '' - imageName: '' CXXVersions: [ 14, 17, 20 ] buildTypes: [ 'Debug', 'Release' ] + image: '' + + compiler: '' + compilerVersions: ["default"] # if default value, simply uses whatever version is on the machine. + # the text of this default value doesn't actually matter. + setupfile: '' + extraCmakeArgs: '' jobs: -- ${{ each CXXVersion in parameters.CXXVersions }}: - - ${{ each buildType in parameters.buildTypes }}: - - job: - displayName: ${{ format('{0} {1} C++{2}', parameters.imageName, buildType, CXXVersion) }} - pool: - vmImage: ${{ parameters.imageName }} - continueOnError: false - steps: - - template: ./steps.yml - parameters: - buildType: ${{ buildType }} - CXXVersion: ${{ CXXVersion }} +- ${{ each compilerVersion in parameters.compilerVersions }}: + - ${{ each CXXVersion in parameters.CXXVersions }}: + - ${{ each buildType in parameters.buildTypes }}: + - job: + displayName: ${{ format('{0} {1} C++{2} {3}', parameters.compiler, compilerVersion, CXXVersion, buildType) }} + pool: + vmImage: ${{ parameters.image }} + continueOnError: false + + steps: + - ${{ if not(eq(parameters.setupfile, '')) }}: + - template: ${{ parameters.setupfile }} + parameters: + version: ${{ compilerVersion }} + + - task: CMake@1 + name: Configure + inputs: + workingDirectory: build + cmakeArgs: '-DGSL_CXX_STANDARD=${{ CXXVersion }} -DCMAKE_BUILD_TYPE=${{ buildType }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev ${{ parameters.extraCmakeArgs }} .. ' + + - task: CMake@1 + name: Build + inputs: + workingDirectory: build + cmakeArgs: '--build . ' + + - script: ctest . --output-on-failure --no-compress-output + name: CTest + workingDirectory: build + failOnStderr: true diff --git a/pipelines/setup_apple.yml b/pipelines/setup_apple.yml new file mode 100644 index 0000000..a424efa --- /dev/null +++ b/pipelines/setup_apple.yml @@ -0,0 +1,9 @@ +parameters: + version: 0 + +steps: + - script: | + if [ "${{ parameters.version }}" = "12.5.1" ]; then sudo xcode-select -switch /Applications/Xcode_12.5.1.app; fi + + displayName: "Setup Xcode Version" + failOnStderr: true diff --git a/pipelines/setup_clang.yml b/pipelines/setup_clang.yml new file mode 100644 index 0000000..58403b4 --- /dev/null +++ b/pipelines/setup_clang.yml @@ -0,0 +1,13 @@ +parameters: + version: 0 + +steps: + - script: | + echo "##vso[task.setvariable variable=CXX;]${CXX}" + echo "##vso[task.setvariable variable=CC;]${CC}" + + displayName: "Setup Clang Version" + failOnStderr: true + env: + CC: clang-${{ parameters.version }} + CXX: clang++-${{ parameters.version }} diff --git a/pipelines/setup_gcc.yml b/pipelines/setup_gcc.yml new file mode 100644 index 0000000..6480f67 --- /dev/null +++ b/pipelines/setup_gcc.yml @@ -0,0 +1,14 @@ +parameters: + version: 0 + +steps: + - script: | + echo "##vso[task.setvariable variable=CXX;]${CXX}" + echo "##vso[task.setvariable variable=CC;]${CC}" + if [ "${{ parameters.version }}" = "11" ]; then sudo apt-get install $CXX; fi + + displayName: "Setup GCC Version" + failOnStderr: true + env: + CC: gcc-${{ parameters.version }} + CXX: g++-${{ parameters.version }} diff --git a/pipelines/steps.yml b/pipelines/steps.yml index 2e80713..e69de29 100644 --- a/pipelines/steps.yml +++ b/pipelines/steps.yml @@ -1,21 +0,0 @@ -parameters: - buildType: '' - CXXVersion: '' - -steps: - - task: CMake@1 - name: Configure - inputs: - workingDirectory: build - cmakeArgs: '-DGSL_CXX_STANDARD=${{ parameters.CXXVersion }} -DCMAKE_BUILD_TYPE=${{ parameters.buildType }} -DCI_TESTING:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -Werror=dev .. ' - - - task: CMake@1 - name: Build - inputs: - workingDirectory: build - cmakeArgs: '--build . ' - - - script: ctest . --output-on-failure --no-compress-output - name: CTest - workingDirectory: build - failOnStderr: true diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dd71105..cab4e56 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -139,10 +139,10 @@ else() $<$,4.99>,$,6>>: $<$:-Wno-undefined-func-template> > - $<$,$>: - -Wno-zero-as-null-pointer-constant # failing Clang Ubuntu 20.04 tests, seems to be a bug with clang 11.0.0 - # (operator< is being re-written by the compiler as operator<=> and - # raising the warning) + $<$,$,$>>: + -Wno-zero-as-null-pointer-constant # failing Clang Ubuntu 20.04 tests, seems to be a bug with clang 10.0.0 + # and clang 11.0.0. (operator< is being re-written by the compiler + # as operator<=> and raising the warning) > > $<$: From ebf0498363c53f0d3c403b0548212c147e3747fe Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Thu, 6 Jan 2022 10:17:21 -0800 Subject: [PATCH 10/24] Update compiler support (#1021) Bump clang and Xcode supported versions and add support for VS with LLVM --- README.md | 16 ++++++++++------ azure-pipelines.yml | 33 ++++++++++++++------------------- pipelines/setup_apple.yml | 2 +- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index f0367eb..a0c44f3 100644 --- a/README.md +++ b/README.md @@ -93,13 +93,17 @@ Below is a table showing the versions currently being tested. Compiler |Toolset Versions Currently Tested :------- |--: - XCode | 13.1 & 12.5.1 - GCC | 11.1.0 & 10.3.0 - Clang | 11.0.0 & 10.0.0 - Visual Studio with MSVC | VS2019 (16.11) & VS2022 (17.0) - Visual Studio with LLVM | VS2019 (16.11) + XCode | 13.2.1 & 12.5.1 + GCC | 11[^1] & 10[^2] + Clang | 12[^2] & 11[^2] + Visual Studio with MSVC | VS2022[^3] & VS2019[^4] + Visual Studio with LLVM | VS2022[^3] & VS2019[^4] -- Support for Visual Studio 2022 with LLVM will be added in the near future + +[^1]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). +[^2]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md#language-and-runtime). +[^3]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022). +[^4]: Precise version may be found in the [latest CI results](https://dev.azure.com/cppstat/GSL/_build?definitionId=1&branchFilter=26). Should be the version specified [here](https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019). --- If you successfully port GSL to another platform, we would love to hear from you! diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a82e3c4..ba16ee9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ stages: parameters: compiler: clang image: ubuntu-20.04 - compilerVersions: [ 11, 10 ] + compilerVersions: [ 12, 11 ] setupfile: 'setup_clang.yml' - stage: Xcode @@ -32,7 +32,7 @@ stages: parameters: compiler: 'Xcode' image: macOS-11 - compilerVersions: [ '12.5.1', '13.1' ] + compilerVersions: [ '12.5.1', '13.2.1' ] setupfile: 'setup_apple.yml' - stage: VS_MSVC @@ -40,13 +40,13 @@ stages: jobs: - template: ./pipelines/jobs.yml parameters: - compiler: 'VS2019 (16.11)' - compilerVersions: [ 'MSVC' ] + compiler: 'VS2019 (MSVC)' + compilerVersions: [ 'default' ] image: windows-2019 - template: ./pipelines/jobs.yml parameters: - compiler: 'VS2022 (17.0)' - compilerVersions: [ 'MSVC' ] + compiler: 'VS2022 (MSVC)' + compilerVersions: [ 'default' ] image: windows-2022 - stage: VS_LLVM @@ -54,18 +54,13 @@ stages: jobs: - template: ./pipelines/jobs.yml parameters: - compiler: 'VS2019 (16.11)' - compilerVersions: [ 'LLVM' ] + compiler: 'VS2019 (LLVM)' + compilerVersions: [ 'default' ] image: windows-2019 extraCmakeArgs: '-T ClangCL' - -# The *same* config as with 2019 but on 2022 yields an error. -# Tracking issue: https://github.com/actions/virtual-environments/issues/4716 -# - template: ./pipelines/jobs.yml -# parameters: -# compiler: 'VS2022 LLVM' -# compilerVersions: [ '17.0' ] -# image: windows-2022 -# extraCmakeArgs: '-T ClangCL' -# CXXVersions: [ 14 ] -# buildTypes: [ Release ] + - template: ./pipelines/jobs.yml + parameters: + compiler: 'VS2022 (LLVM)' + compilerVersions: [ 'default' ] + image: windows-2022 + extraCmakeArgs: '-T ClangCL' diff --git a/pipelines/setup_apple.yml b/pipelines/setup_apple.yml index a424efa..6a256a5 100644 --- a/pipelines/setup_apple.yml +++ b/pipelines/setup_apple.yml @@ -3,7 +3,7 @@ parameters: steps: - script: | - if [ "${{ parameters.version }}" = "12.5.1" ]; then sudo xcode-select -switch /Applications/Xcode_12.5.1.app; fi + if [ "${{ parameters.version }}" != "default" ]; then sudo xcode-select -switch /Applications/Xcode_${{ parameters.version }}.app; fi displayName: "Setup Xcode Version" failOnStderr: true From 99a29ce797c8337b8923f2688ba1489be6f65bc4 Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Wed, 26 Jan 2022 16:44:07 -0800 Subject: [PATCH 11/24] Document safe usage of undefined behavior in gsl::narrow (#1024) --- include/gsl/narrow | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/gsl/narrow b/include/gsl/narrow index 40016d1..bec30d1 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -36,7 +36,12 @@ GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recogn constexpr const bool is_different_signedness = (std::is_signed::value != std::is_signed::value); - const T t = narrow_cast(u); +GSL_SUPPRESS(es.103) // NO-FORMAT: attribute // don't overflow +GSL_SUPPRESS(es.104) // NO-FORMAT: attribute // don't underflow +GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior + const T t = narrow_cast(u); // While this is technically undefined behavior in some cases (i.e., if the source value is of floating-point type + // and cannot fit into the destination integral type), the resultant behavior is benign on the platforms + // that we target (i.e., no hardware trap representations are hit). if (static_cast(t) != u || (is_different_signedness && ((t < T{}) != (u < U{})))) { From a3534567187d2edc428efd3f13466ff75fe5805c Mon Sep 17 00:00:00 2001 From: Vitaly Zaitsev Date: Sat, 29 Jan 2022 00:22:59 +0100 Subject: [PATCH 12/24] Fixed wrong version number in exported CMake configs. (#1027) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b59ec7a..5e0d9c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") include(guidelineSupportLibrary) project(GSL - VERSION 3.1.0 + VERSION 4.0.0 LANGUAGES CXX ) From 4377f6e603c64a86c934f1546aa9db482f2e1a4e Mon Sep 17 00:00:00 2001 From: Werner Henze <34543625+beinhaerter@users.noreply.github.com> Date: Mon, 31 Jan 2022 22:06:42 +0100 Subject: [PATCH 13/24] quoted form of #include when GSL includes GSL files (#1030) [SF.12: Prefer the quoted form of #include for files relative to the including file and the angle bracket form everywhere else](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rs-incform) Additionally changed #include order in `span` so that all `span_ext` is in the GSL include block and not in the STL include block. Fixes issues #1025. Co-authored-by: Werner Henze --- include/gsl/algorithm | 4 ++-- include/gsl/gsl | 16 ++++++++-------- include/gsl/gsl_algorithm | 2 +- include/gsl/gsl_assert | 2 +- include/gsl/gsl_byte | 2 +- include/gsl/gsl_narrow | 2 +- include/gsl/gsl_util | 2 +- include/gsl/narrow | 4 ++-- include/gsl/pointers | 2 +- include/gsl/span | 16 ++++++++-------- include/gsl/span_ext | 4 ++-- include/gsl/string_span | 6 +++--- include/gsl/util | 2 +- 13 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/gsl/algorithm b/include/gsl/algorithm index b27475d..584f5cd 100644 --- a/include/gsl/algorithm +++ b/include/gsl/algorithm @@ -17,8 +17,8 @@ #ifndef GSL_ALGORITHM_H #define GSL_ALGORITHM_H -#include // for Expects -#include // for dynamic_extent, span +#include "assert" // for Expects +#include "span" // for dynamic_extent, span #include // for copy_n #include // for ptrdiff_t diff --git a/include/gsl/gsl b/include/gsl/gsl index adadc40..3d9e288 100644 --- a/include/gsl/gsl +++ b/include/gsl/gsl @@ -17,16 +17,16 @@ #ifndef GSL_GSL_H #define GSL_GSL_H -#include // copy -#include // Ensures/Expects -#include // byte -#include // owner, not_null -#include // span -#include // zstring, string_span, zstring_builder... -#include // finally()/narrow_cast()... +#include "algorithm" // copy +#include "assert" // Ensures/Expects +#include "byte" // byte +#include "pointers" // owner, not_null +#include "span" // span +#include "string_span" // zstring, string_span, zstring_builder... +#include "util" // finally()/narrow_cast()... #ifdef __cpp_exceptions -#include // narrow() +#include "narrow" // narrow() #endif #endif // GSL_GSL_H diff --git a/include/gsl/gsl_algorithm b/include/gsl/gsl_algorithm index 303a5ae..951679a 100644 --- a/include/gsl/gsl_algorithm +++ b/include/gsl/gsl_algorithm @@ -1,4 +1,4 @@ #pragma once #pragma message( \ "This header will soon be removed. Use instead of ") -#include +#include "algorithm" diff --git a/include/gsl/gsl_assert b/include/gsl/gsl_assert index b83a772..222ce30 100644 --- a/include/gsl/gsl_assert +++ b/include/gsl/gsl_assert @@ -1,3 +1,3 @@ #pragma once #pragma message("This header will soon be removed. Use instead of ") -#include +#include "assert" diff --git a/include/gsl/gsl_byte b/include/gsl/gsl_byte index 4f198ce..831bb2d 100644 --- a/include/gsl/gsl_byte +++ b/include/gsl/gsl_byte @@ -1,3 +1,3 @@ #pragma once #pragma message("This header will soon be removed. Use instead of ") -#include +#include "byte" diff --git a/include/gsl/gsl_narrow b/include/gsl/gsl_narrow index 6c2cd10..3e3e8cf 100644 --- a/include/gsl/gsl_narrow +++ b/include/gsl/gsl_narrow @@ -1,3 +1,3 @@ #pragma once #pragma message("This header will soon be removed. Use instead of ") -#include +#include "narrow" diff --git a/include/gsl/gsl_util b/include/gsl/gsl_util index 6a6d77e..a7ed739 100644 --- a/include/gsl/gsl_util +++ b/include/gsl/gsl_util @@ -1,3 +1,3 @@ #pragma once #pragma message("This header will soon be removed. Use instead of ") -#include +#include "util" diff --git a/include/gsl/narrow b/include/gsl/narrow index bec30d1..bad581c 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -16,8 +16,8 @@ #ifndef GSL_NARROW_H #define GSL_NARROW_H -#include // for Expects -#include // for narrow_cast +#include "assert" // for Expects +#include "util" // for narrow_cast namespace gsl { struct narrowing_error : public std::exception diff --git a/include/gsl/pointers b/include/gsl/pointers index e6b2348..a0a77ac 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -17,7 +17,7 @@ #ifndef GSL_POINTERS_H #define GSL_POINTERS_H -#include // for Ensures, Expects +#include "assert" // for Ensures, Expects #include // for forward #include // for ptrdiff_t, nullptr_t, size_t diff --git a/include/gsl/span b/include/gsl/span index cc8a7b9..5488f52 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -17,15 +17,15 @@ #ifndef GSL_SPAN_H #define GSL_SPAN_H -#include // for Expects -#include // for byte -#include // for narrow_cast +#include "assert" // for Expects +#include "byte" // for byte +#include "span_ext" // for span specialization of gsl::at and other span-related extensions +#include "util" // for narrow_cast -#include // for array -#include // for ptrdiff_t, size_t, nullptr_t -#include // for span specialization of gsl::at and other span-related extensions -#include // for reverse_iterator, distance, random_access_... -#include // for enable_if_t, declval, is_convertible, inte... +#include // for array +#include // for ptrdiff_t, size_t, nullptr_t +#include // for reverse_iterator, distance, random_access_... +#include // for enable_if_t, declval, is_convertible, inte... #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) diff --git a/include/gsl/span_ext b/include/gsl/span_ext index 5feb2b8..d86f736 100644 --- a/include/gsl/span_ext +++ b/include/gsl/span_ext @@ -27,8 +27,8 @@ // /////////////////////////////////////////////////////////////////////////////// -#include // GSL_KERNEL_MODE -#include // for narrow_cast, narrow +#include "assert" // GSL_KERNEL_MODE +#include "util" // for narrow_cast, narrow #include // for ptrdiff_t, size_t #include diff --git a/include/gsl/string_span b/include/gsl/string_span index bcc672a..397c561 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -17,9 +17,9 @@ #ifndef GSL_STRING_SPAN_H #define GSL_STRING_SPAN_H -#include // for Ensures, Expects -#include // for operator!=, operator==, dynamic_extent -#include // for narrow_cast +#include "assert" // for Ensures, Expects +#include "span_ext" // for operator!=, operator==, dynamic_extent +#include "util" // for narrow_cast #include // for equal, lexicographical_compare #include // for array diff --git a/include/gsl/util b/include/gsl/util index a215bad..b6dbd18 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -17,7 +17,7 @@ #ifndef GSL_UTIL_H #define GSL_UTIL_H -#include // for Expects +#include "assert" // for Expects #include #include // for ptrdiff_t, size_t From f22f524aa2d5e5ad334bcf88c69ffdb5636deed9 Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Tue, 22 Mar 2022 12:24:23 -0700 Subject: [PATCH 14/24] Suppress reserved identifier warning (#1041) The following reserved identifiers are being used specifically to target certain MSVC constructs, so suppress the warning in VS 2022 (LLVM) "... is reserved because it starts with '_' followed by a capital letter": - _Unchecked_type - _Verify_range - _Verify_offset - _Unwrapped - _Unwrap_when_unverified - _Seek_to - _Unchecked_begin - _Unchecked_end --- tests/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cab4e56..891569b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -62,6 +62,7 @@ if (MSVC AND (GSL_CXX_STANDARD GREATER_EQUAL 17)) set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-) endif() +include(CheckCXXCompilerFlag) # this interface adds compile options to how the tests are run # please try to keep entries ordered =) add_library(gsl_tests_config INTERFACE) @@ -105,6 +106,10 @@ if(MSVC) # MSVC or simulating MSVC > > ) + check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID) + if (WARN_RESERVED_ID) + target_compile_options(gsl_tests_config INTERFACE "-Wno-reserved-identifier") + endif() else() target_compile_options(gsl_tests_config INTERFACE -fno-strict-aliasing @@ -228,6 +233,10 @@ if(MSVC) # MSVC or simulating MSVC -Wno-unknown-attributes > ) + check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID) + if (WARN_RESERVED_ID) + target_compile_options(gsl_tests_config_noexcept INTERFACE "-Wno-reserved-identifier") + endif() else() target_compile_options(gsl_tests_config_noexcept INTERFACE -fno-exceptions From 383723676cd548d615159701ac3d050f8dd1e128 Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Tue, 22 Mar 2022 13:20:54 -0700 Subject: [PATCH 15/24] Make gsl::span's iterators use the contiguous_iterator concept (#1035) Resolves #1016 Co-authored-by: Casey Carter --- include/gsl/span | 26 +++++++++++++++++++++++++- tests/span_tests.cpp | 20 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/include/gsl/span b/include/gsl/span index 5488f52..4413a4d 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -25,8 +25,13 @@ #include // for array #include // for ptrdiff_t, size_t, nullptr_t #include // for reverse_iterator, distance, random_access_... +#include // for pointer_traits #include // for enable_if_t, declval, is_convertible, inte... +#if defined(__has_include) && __has_include() +#include +#endif + #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) @@ -110,6 +115,9 @@ namespace details class span_iterator { public: +#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts)) + using iterator_concept = std::contiguous_iterator_tag; +#endif // __cpp_lib_ranges using iterator_category = std::random_access_iterator_tag; using value_type = std::remove_cv_t; using difference_type = std::ptrdiff_t; @@ -329,8 +337,24 @@ namespace details pointer begin_ = nullptr; pointer end_ = nullptr; pointer current_ = nullptr; - }; + template + friend struct std::pointer_traits; + }; +}} // namespace gsl::details + +template +struct std::pointer_traits<::gsl::details::span_iterator> { + using pointer = ::gsl::details::span_iterator; + using element_type = Type; + using difference_type = ptrdiff_t; + + static constexpr element_type* to_address(const pointer i) noexcept { + return i.current_; + } +}; + +namespace gsl { namespace details { template class extent_type { diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 33ccf56..41ac3ae 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -40,6 +40,9 @@ #endif // __has_include() #endif // __has_include #endif // (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) +#if defined(__cplusplus) && __cplusplus >= 202002L +#include +#endif // __cplusplus >= 202002L #include "deathTestCommon.h" @@ -1297,3 +1300,20 @@ TEST(span_test, front_back) EXPECT_DEATH(s2.front(), expected); EXPECT_DEATH(s2.back(), expected); } + +#if defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L +TEST(span_test, std_span) +{ + // make sure std::span can be constructed from gsl::span + int arr[5] = {1, 2, 3, 4, 5}; + gsl::span gsl_span{arr}; +#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts)) + EXPECT_TRUE(std::to_address(gsl_span.begin()) == gsl_span.data()); + EXPECT_TRUE(std::to_address(gsl_span.end()) == gsl_span.data() + gsl_span.size()); +#endif // __cpp_lib_ranges + + std::span std_span = gsl_span; + EXPECT_TRUE(std_span.data() == gsl_span.data()); + EXPECT_TRUE(std_span.size() == gsl_span.size()); +} +#endif // defined(FORCE_STD_SPAN_TESTS) || defined(__cpp_lib_span) && __cpp_lib_span >= 202002L From 2bfd4950802a223dde37a08a205812b6dfdfeb61 Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Thu, 14 Apr 2022 11:08:28 -0700 Subject: [PATCH 16/24] Suppress -Wfloat-equal warning in implementation of gsl::narrow (#1043) In the implementation of gsl::narrow, there is a comparison `static_cast(t) != u` which may be comparing two floats. The comparison here is done purposefully to categorize ill effects of narrowing conversion, since the values being compared *should* be the same when compared with `operator==`. Note, using #pragma GCC will suppress this warning for both GCC and Clang. --- include/gsl/narrow | 7 +++++++ tests/CMakeLists.txt | 4 ++++ tests/utils_tests.cpp | 2 ++ 3 files changed, 13 insertions(+) diff --git a/include/gsl/narrow b/include/gsl/narrow index bad581c..2c3c518 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -43,10 +43,17 @@ GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior // and cannot fit into the destination integral type), the resultant behavior is benign on the platforms // that we target (i.e., no hardware trap representations are hit). +#if defined(__clang__) || defined(__GNUC__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif if (static_cast(t) != u || (is_different_signedness && ((t < T{}) != (u < U{})))) { throw narrowing_error{}; } +#if defined(__clang__) || defined(__GNUC__) + #pragma GCC diagnostic pop +#endif return t; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 891569b..68e18ec 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -89,6 +89,7 @@ if(MSVC) # MSVC or simulating MSVC > $<$: -Weverything + -Wfloat-equal -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-covered-switch-default # GTest @@ -122,6 +123,7 @@ else() -Wpedantic -Wshadow -Wsign-conversion + -Wfloat-equal -Wno-deprecated-declarations # Allow tests for [[deprecated]] elements $<$,$>: -Weverything @@ -227,6 +229,7 @@ if(MSVC) # MSVC or simulating MSVC > $<$: -Weverything + -Wfloat-equal -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-prototypes @@ -250,6 +253,7 @@ else() -Wpedantic -Wshadow -Wsign-conversion + -Wfloat-equal $<$,$>: -Weverything -Wno-c++98-compat diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index 39b4ca2..715073f 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -149,5 +149,7 @@ TEST(utils_tests, narrow) EXPECT_TRUE( narrow>(std::complex(4, 2)) == std::complex(4, 2)); EXPECT_THROW(narrow>(std::complex(4.2)), narrowing_error); + + EXPECT_TRUE(narrow(float(1)) == 1); } #endif // GSL_KERNEL_MODE From f21f29d210939d4025069576e5891665b001f402 Mon Sep 17 00:00:00 2001 From: Juan Carlos Arevalo Baeza Date: Tue, 26 Apr 2022 14:41:10 -0700 Subject: [PATCH 17/24] gsl/narrow should include (#1044) This file uses std::exception, so it should include the appropriate header. Normally it gets the STL's header included via the gsl/assert file, but this is skipped with _HAS_EXCEPTIONS=0. I understand _HAS_EXCEPTIONS is undocumented and unsupported, but regardless, the appropriate header should be included here. Alternatively, gsl/narrow should be modified to support _HAS_EXCEPTIONS=0, like gsl/assert was. But I'm not proposing that change. does define std::exception even with _HAS_EXCEPTIONS=0. --- include/gsl/narrow | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/gsl/narrow b/include/gsl/narrow index 2c3c518..6cb1781 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -16,8 +16,9 @@ #ifndef GSL_NARROW_H #define GSL_NARROW_H -#include "assert" // for Expects -#include "util" // for narrow_cast +#include "assert" // for Expects +#include "util" // for narrow_cast +#include // for std::exception namespace gsl { struct narrowing_error : public std::exception From 7fefaaf2c857782a70f6a0ba743cd93dba72f6c8 Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Thu, 28 Apr 2022 09:49:10 -0700 Subject: [PATCH 18/24] Fix reason for including assert inside gsl/narrow (#1045) --- include/gsl/narrow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/narrow b/include/gsl/narrow index 6cb1781..32d271e 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -16,7 +16,7 @@ #ifndef GSL_NARROW_H #define GSL_NARROW_H -#include "assert" // for Expects +#include "assert" // for GSL_SUPPRESS #include "util" // for narrow_cast #include // for std::exception namespace gsl From d8c493c89fef3b1928803cf0af5a21630344ea7e Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Thu, 28 Apr 2022 09:49:38 -0700 Subject: [PATCH 19/24] Suppress es.46 warning in implementation of gsl::narrow (#1046) As per the CoreGuidelines, gsl::narrow is defined in terms of static_cast. Suppress es.46, which suggests converting the static_cast into gsl::narrow --- include/gsl/narrow | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/gsl/narrow b/include/gsl/narrow index 32d271e..7578c8b 100644 --- a/include/gsl/narrow +++ b/include/gsl/narrow @@ -31,6 +31,10 @@ template ::value // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) +GSL_SUPPRESS(es.46) // NO-FORMAT: attribute // The warning suggests that a floating->unsigned conversion can occur + // in the static_cast below, and that gsl::narrow should be used instead. + // Suppress this warning, since gsl::narrow is defined in terms of + // static_cast // clang-format on constexpr T narrow(U u) noexcept(false) { From da01eb28dbb75bed11a51acff0f80ecedd622573 Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Thu, 28 Apr 2022 14:58:25 -0700 Subject: [PATCH 20/24] Remove useless runtime checks in span implementation (#1029) Both checks for Expects(ExtentType::size() != dynamic_extent); in storage_type are always useless. storage_type is only ever created with ExtentType == extent_type, where Extent has type std::size_t and is the extent of the span. Looking at extent_type::size(): - if Ext != dynamic_extent, then size() always returns Ext, and therefore size() != dynamic_extent - if Ext == dynamic_extent, then size() returns extent_type::size_. size_ can only be set via one of two constructors: - constexpr explicit extent_type(size_type size), which already does the check in question - constexpr explicit extent_type(extent_type ext) : size_(ext.size()), which simply relies on the other extent's size() method So there is no way for ExtentType::size() == dynamic_extent. --- include/gsl/span | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 4413a4d..4d5bc7c 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -706,14 +706,11 @@ private: template constexpr storage_type(KnownNotNull data, OtherExtentType ext) : ExtentType(ext), data_(data.p) - { - Expects(ExtentType::size() != dynamic_extent); - } + {} template constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) { - Expects(ExtentType::size() != dynamic_extent); Expects(data || ExtentType::size() == 0); } From d9fc52e20e32fcc804502480a781120b210afd41 Mon Sep 17 00:00:00 2001 From: "microsoft-github-policy-service[bot]" <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 15:27:04 -0700 Subject: [PATCH 21/24] Microsoft mandatory file (#1047) Co-authored-by: microsoft-github-policy-service[bot] <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> --- SECURITY.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..869fdfe --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + From 330583f47800c60cf001239550d291d16274756a Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Mon, 18 Jul 2022 17:42:21 -0700 Subject: [PATCH 22/24] Resolve MSVC warning C5260 (#1049) * Test solution * Mark dynamic_extent as inline, compiler-version-permitting --- include/gsl/span_ext | 2 +- include/gsl/util | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/gsl/span_ext b/include/gsl/span_ext index d86f736..516cc99 100644 --- a/include/gsl/span_ext +++ b/include/gsl/span_ext @@ -41,7 +41,7 @@ namespace gsl { // [span.views.constants], constants -constexpr const std::size_t dynamic_extent = narrow_cast(-1); +GSL_INLINE constexpr const std::size_t dynamic_extent = narrow_cast(-1); template class span; diff --git a/include/gsl/util b/include/gsl/util index b6dbd18..aebfc66 100644 --- a/include/gsl/util +++ b/include/gsl/util @@ -45,6 +45,12 @@ #define GSL_NODISCARD #endif // defined(__cplusplus) && (__cplusplus >= 201703L) +#if defined(__cpp_inline_variables) +#define GSL_INLINE inline +#else +#define GSL_INLINE +#endif + namespace gsl { // From 2e94541fcfe0c33e8536469110d3b19f156bc6f9 Mon Sep 17 00:00:00 2001 From: dmitrykobets-msft <89153909+dmitrykobets-msft@users.noreply.github.com> Date: Wed, 17 Aug 2022 12:40:45 -0700 Subject: [PATCH 23/24] Use updated NDK version in android test suite (#1053) https://github.com/actions/runner-images/issues/5930 recently updated the NDK version, resulting in test breakages. Update the version. --- .github/workflows/android.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 836b444..49e8c2e 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -29,7 +29,7 @@ jobs: echo "Emulator starting" - name: Configure - run: cmake -Werror=dev -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug .. + run: cmake -Werror=dev -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/25.0.8775105/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=16 -DANDROID_ABI=x86_64 -DCMAKE_BUILD_TYPE=Debug .. - name: Build run: cmake --build . --parallel From 10df83d292bf5bbdc487e57dc8c2dc8c7a01f4d1 Mon Sep 17 00:00:00 2001 From: Werner Henze <34543625+beinhaerter@users.noreply.github.com> Date: Thu, 18 Aug 2022 21:28:11 +0200 Subject: [PATCH 24/24] solve span compile problem with gcc 5.5.0 (#1052) GCC 4.8.0 - 7.0 has a bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480) involving specialization in a namespace enclosing the specialized template. This PR fixes an appearance of this bug in the span header. --- include/gsl/span | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 4d5bc7c..49e1502 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -343,16 +343,18 @@ namespace details }; }} // namespace gsl::details +namespace std +{ template -struct std::pointer_traits<::gsl::details::span_iterator> { - using pointer = ::gsl::details::span_iterator; - using element_type = Type; +struct pointer_traits<::gsl::details::span_iterator> +{ + using pointer = ::gsl::details::span_iterator; + using element_type = Type; using difference_type = ptrdiff_t; - static constexpr element_type* to_address(const pointer i) noexcept { - return i.current_; - } + static constexpr element_type* to_address(const pointer i) noexcept { return i.current_; } }; +} // namespace std namespace gsl { namespace details { template