gsl::at behavior change regarding gsl::span (#985)

* move span specialization of 'at' to <gsl/span> 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 <jordan.maples@microsoft.com>
This commit is contained in:
Jordan Maples [MSFT] 2021-05-20 18:18:08 -07:00 committed by GitHub
parent c1cbb41b42
commit b26f6d5ec7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1304 additions and 1175 deletions

View File

@ -22,6 +22,7 @@
// Currently terminate is a no-op in this mode, so we add termination behavior back // 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)) #if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS))
#define GSL_KERNEL_MODE
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
#include <intrin.h> #include <intrin.h>

View File

@ -1,3 +1,4 @@
#pragma once #pragma once
#pragma message("This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>") #pragma message( \
"This header will soon be removed. Use <gsl/algorithm> instead of <gsl/gsl_algorithm>")
#include <gsl/algorithm> #include <gsl/algorithm>

View File

@ -35,10 +35,17 @@ namespace gsl
namespace details namespace details
{ {
template <typename T, typename = void> template <typename T, typename = void>
struct is_comparable_to_nullptr : std::false_type {}; struct is_comparable_to_nullptr : std::false_type
{
};
template <typename T> template <typename T>
struct is_comparable_to_nullptr<T, std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>> : std::true_type {}; struct is_comparable_to_nullptr<
T,
std::enable_if_t<std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value>>
: std::true_type
{
};
} // namespace details } // namespace details
// //

View File

@ -23,6 +23,7 @@
#include <array> // for array #include <array> // for array
#include <cstddef> // for ptrdiff_t, size_t, nullptr_t #include <cstddef> // for ptrdiff_t, size_t, nullptr_t
#include <gsl/span_ext> // for span specialization of gsl::at and other span-related extensions
#include <iterator> // for reverse_iterator, distance, random_access_... #include <iterator> // for reverse_iterator, distance, random_access_...
#include <type_traits> // for enable_if_t, declval, is_convertible, inte... #include <type_traits> // for enable_if_t, declval, is_convertible, inte...
@ -60,12 +61,6 @@
namespace gsl namespace gsl
{ {
// [views.constants], constants
constexpr const std::size_t dynamic_extent = narrow_cast<std::size_t>(-1);
template <class ElementType, std::size_t Extent = dynamic_extent>
class span;
// implementation details // implementation details
namespace details namespace details
{ {

View File

@ -27,16 +27,29 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gsl/span> // for span #include <gsl/assert> // GSL_KERNEL_MODE
#include <gsl/util> // for narrow_cast, narrow #include <gsl/util> // for narrow_cast, narrow
#include <algorithm> // for lexicographical_compare
#include <cstddef> // for ptrdiff_t, size_t #include <cstddef> // for ptrdiff_t, size_t
#include <utility> #include <utility>
#ifndef GSL_KERNEL_MODE
#include <algorithm> // for lexicographical_compare
#endif // GSL_KERNEL_MODE
namespace gsl namespace gsl
{ {
// [span.views.constants], constants
constexpr const std::size_t dynamic_extent = narrow_cast<std::size_t>(-1);
template <class ElementType, std::size_t Extent = dynamic_extent>
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 // [span.comparison], span comparison operators
template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent> template <class ElementType, std::size_t FirstExtent, std::size_t SecondExtent>
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r) constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r)
@ -74,6 +87,8 @@ constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent>
return !(l < r); return !(l < r);
} }
#endif // GSL_KERNEL_MODE
// //
// make_span() - Utility functions for creating spans // make_span() - Utility functions for creating spans
// //

View File

@ -25,6 +25,10 @@
#include <type_traits> // for is_signed, integral_constant #include <type_traits> // for is_signed, integral_constant
#include <utility> // for exchange, forward #include <utility> // for exchange, forward
#if defined(__cplusplus) && __cplusplus >= 202002L
#include <span>
#endif // __cplusplus >= 202002L
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push) #pragma warning(push)
@ -134,6 +138,14 @@ constexpr T at(const std::initializer_list<T> cont, const index i)
return *(cont.begin() + i); return *(cont.begin() + i);
} }
#if defined(__cplusplus) && __cplusplus >= 202002L
template <class T, size_t extent = std::dynamic_extent>
constexpr auto at(std::span<T, extent> sp, const index i)
{
Expects(i >= 0 && i < narrow_cast<i>(sp.size()));
return sp[i];
}
#endif // __cplusplus >= 202002L
} // namespace gsl } // namespace gsl
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)

View File

@ -14,16 +14,13 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h>
#include <gsl/algorithm> // for copy
#include <gsl/span> // for span
#include <array> // for array #include <array> // for array
#include <cstddef> // for size_t #include <cstddef> // for size_t
#include <gsl/algorithm> // for copy
#include <gsl/span> // for span
#include <gtest/gtest.h>
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
}
namespace gsl namespace gsl
{ {
@ -204,10 +201,11 @@ TEST(algorithm_tests, incompatible_type)
TEST(algorithm_tests, small_destination_span) TEST(algorithm_tests, small_destination_span)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. small_destination_span"; std::cerr << "Expected Death. small_destination_span";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
std::array<int, 12> src{1, 2, 3, 4}; std::array<int, 12> src{1, 2, 3, 4};
std::array<int, 4> dst{}; std::array<int, 4> dst{};
@ -217,9 +215,9 @@ TEST(algorithm_tests, small_destination_span)
const span<int> dst_span_dyn(dst); const span<int> dst_span_dyn(dst);
const span<int, 4> dst_span_static(dst); const span<int, 4> dst_span_static(dst);
EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), deathstring); EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), expected);
EXPECT_DEATH(copy(src_span_dyn, dst_span_static), deathstring); EXPECT_DEATH(copy(src_span_dyn, dst_span_static), expected);
EXPECT_DEATH(copy(src_span_static, dst_span_dyn), deathstring); EXPECT_DEATH(copy(src_span_static, dst_span_dyn), expected);
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static); copy(src_span_static, dst_span_static);

View File

@ -14,14 +14,14 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h> #include "deathTestCommon.h"
#include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects #include <gsl/assert> // for fail_fast (ptr only), Ensures, Expects
#include <gtest/gtest.h>
using namespace gsl; using namespace gsl;
namespace namespace
{ {
static constexpr char deathstring[] = "Expected Death";
int f(int i) int f(int i)
{ {
@ -39,23 +39,22 @@ int g(int i)
TEST(assertion_tests, expects) TEST(assertion_tests, expects)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. expects"; std::cerr << "Expected Death. expects";
std::abort(); std::abort();
}); });
EXPECT_TRUE(f(2) == 2); EXPECT_TRUE(f(2) == 2);
EXPECT_DEATH(f(10), deathstring); EXPECT_DEATH(f(10), GetExpectedDeathString(terminateHandler));
} }
TEST(assertion_tests, ensures) TEST(assertion_tests, ensures)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. ensures"; std::cerr << "Expected Death. ensures";
std::abort(); std::abort();
}); });
EXPECT_TRUE(g(2) == 3); EXPECT_TRUE(g(2) == 3);
EXPECT_DEATH(g(9), deathstring); EXPECT_DEATH(g(9), GetExpectedDeathString(terminateHandler));
} }

View File

@ -22,31 +22,33 @@
#include <cstddef> // for size_t #include <cstddef> // for size_t
#include <initializer_list> // for initializer_list #include <initializer_list> // for initializer_list
#include <vector> // for vector #include <vector> // for vector
#if defined(__cplusplus) && __cplusplus >= 202002L
#include <span>
#endif // __cplusplus >= 202002L
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
}
TEST(at_tests, static_array) TEST(at_tests, static_array)
{ {
int a[4] = {1, 2, 3, 4}; int a[4] = {1, 2, 3, 4};
const int(&c_a)[4] = a; 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(a, i) == &a[i]);
EXPECT_TRUE(&gsl::at(c_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::cerr << "Expected Death. static_array";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, std_array) TEST(at_tests, std_array)
@ -54,20 +56,22 @@ TEST(at_tests, std_array)
std::array<int, 4> a = {1, 2, 3, 4}; std::array<int, 4> a = {1, 2, 3, 4};
const std::array<int, 4>& c_a = a; const std::array<int, 4>& 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<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. std_array"; std::cerr << "Expected Death. std_array";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, std_vector) TEST(at_tests, std_vector)
@ -75,42 +79,68 @@ TEST(at_tests, std_vector)
std::vector<int> a = {1, 2, 3, 4}; std::vector<int> a = {1, 2, 3, 4};
const std::vector<int>& c_a = a; const std::vector<int>& 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<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. std_vector"; std::cerr << "Expected Death. std_vector";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring); EXPECT_DEATH(gsl::at(c_a, -1), expected);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring); EXPECT_DEATH(gsl::at(c_a, 4), expected);
} }
TEST(at_tests, InitializerList) TEST(at_tests, InitializerList)
{ {
const std::initializer_list<int> a = {1, 2, 3, 4}; const std::initializer_list<int> 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(a, i) == i + 1);
EXPECT_TRUE(gsl::at({1, 2, 3, 4}, 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::cerr << "Expected Death. InitializerList";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
EXPECT_DEATH(gsl::at(a, -1), deathstring); EXPECT_DEATH(gsl::at(a, -1), expected);
EXPECT_DEATH(gsl::at(a, 4), deathstring); EXPECT_DEATH(gsl::at(a, 4), expected);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring); EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), expected);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring); EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), expected);
} }
#if defined(__cplusplus) && __cplusplus >= 202002L
TEST(at_tests, std_span)
{
std::vector<int> vec{1, 2, 3, 4, 5};
std::span sp{vec};
std::vector<int> 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 #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910
static constexpr bool test_constexpr() static constexpr bool test_constexpr()
{ {
@ -119,7 +149,8 @@ static constexpr bool test_constexpr()
std::array<int, 4> a2 = {1, 2, 3, 4}; std::array<int, 4> a2 = {1, 2, 3, 4};
const std::array<int, 4>& c_a2 = a2; const std::array<int, 4>& 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(a1, i) != &a1[i]) return false;
if (&gsl::at(c_a1, i) != &a1[i]) return false; if (&gsl::at(c_a1, i) != &a1[i]) return false;
// requires C++17: // requires C++17:

View File

@ -37,7 +37,9 @@ TEST(byte_tests, construction)
EXPECT_TRUE(static_cast<unsigned char>(b) == 4); EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
} }
// clang-format off
GSL_SUPPRESS(es.49) GSL_SUPPRESS(es.49)
// clang-format on
{ {
const byte b = byte(12); const byte b = byte(12);
EXPECT_TRUE(static_cast<unsigned char>(b) == 12); EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
@ -122,7 +124,7 @@ TEST(byte_tests, aliasing)
EXPECT_TRUE(res == i); EXPECT_TRUE(res == i);
} }
} } // namespace
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static); copy(src_span_static, dst_span_static);

11
tests/deathTestCommon.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include <gsl/assert>
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;
}

View File

@ -25,13 +25,9 @@
#include <string> // for basic_string, operator==, string, operator<< #include <string> // for basic_string, operator==, string, operator<<
#include <typeinfo> // for type_info #include <typeinfo> // for type_info
#include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
namespace
{
constexpr char deathstring[] = "Expected Death";
} // namespace
struct MyBase struct MyBase
{ {
}; };
@ -64,7 +60,9 @@ struct CustomPtr
template <typename T, typename U> template <typename T, typename U>
std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -72,7 +70,9 @@ std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -80,7 +80,9 @@ std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -88,7 +90,9 @@ std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -96,7 +100,9 @@ std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -104,7 +110,9 @@ std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U> template <typename T, typename U>
std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{ {
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true" return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false"; : "false";
} }
@ -120,9 +128,13 @@ struct NonCopyableNonMovable
namespace namespace
{ {
// clang-format off
GSL_SUPPRESS(f .4) // NO-FORMAT: attribute GSL_SUPPRESS(f .4) // NO-FORMAT: attribute
// clang-format on
bool helper(not_null<int*> p) { return *p == 12; } bool helper(not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f .4) // NO-FORMAT: attribute GSL_SUPPRESS(f .4) // NO-FORMAT: attribute
// clang-format on
bool helper_const(not_null<const int*> p) { return *p == 12; } bool helper_const(not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; } int* return_pointer() { return nullptr; }
@ -145,10 +157,12 @@ TEST(notnull_tests, TestNotNullConstructors)
#endif #endif
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructors"; std::cerr << "Expected Death. TestNotNullConstructors";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
// from shared pointer // from shared pointer
int i = 12; int i = 12;
@ -160,7 +174,7 @@ TEST(notnull_tests, TestNotNullConstructors)
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
int* pi = nullptr; int* pi = nullptr;
EXPECT_DEATH((not_null<decltype(pi)>(pi)), deathstring); EXPECT_DEATH((not_null<decltype(pi)>(pi)), expected);
} }
{ {
@ -217,8 +231,8 @@ TEST(notnull_tests, TestNotNullConstructors)
{ {
// from returned pointer // from returned pointer
EXPECT_DEATH(helper(return_pointer()), deathstring); EXPECT_DEATH(helper(return_pointer()), expected);
EXPECT_DEATH(helper_const(return_pointer()), deathstring); EXPECT_DEATH(helper_const(return_pointer()), expected);
} }
} }
@ -278,17 +292,18 @@ TEST(notnull_tests, TestNotNullCasting)
TEST(notnull_tests, TestNotNullAssignment) TEST(notnull_tests, TestNotNullAssignment)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullAssignmentd"; std::cerr << "Expected Death. TestNotNullAssignmentd";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int i = 12; int i = 12;
not_null<int*> p(&i); not_null<int*> p(&i);
EXPECT_TRUE(helper(p)); EXPECT_TRUE(helper(p));
int* q = nullptr; int* q = nullptr;
EXPECT_DEATH(p = not_null<int*>(q), deathstring); EXPECT_DEATH(p = not_null<int*>(q), expected);
} }
TEST(notnull_tests, TestNotNullRawPointerComparison) TEST(notnull_tests, TestNotNullRawPointerComparison)
@ -437,17 +452,18 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction"; std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
auto workaround_macro = []() { auto workaround_macro = []() {
int* p1 = nullptr; int* p1 = nullptr;
const not_null x{p1}; 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 int* p1 = nullptr;
const not_null x{p1}; const not_null x{p1};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(not_null{p}), deathstring); EXPECT_DEATH(helper(not_null{p}), expected);
EXPECT_DEATH(helper_const(not_null{p}), deathstring); EXPECT_DEATH(helper_const(not_null{p}), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -498,10 +514,11 @@ TEST(notnull_tests, TestMakeNotNull)
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
} }
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestMakeNotNull"; std::cerr << "Expected Death. TestMakeNotNull";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
const auto workaround_macro = []() { const auto workaround_macro = []() {
@ -509,7 +526,7 @@ TEST(notnull_tests, TestMakeNotNull)
const auto x = make_not_null(p1); const auto x = make_not_null(p1);
EXPECT_TRUE(*x == 42); 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); const auto x = make_not_null(p1);
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(make_not_null(p)), deathstring); EXPECT_DEATH(helper(make_not_null(p)), expected);
EXPECT_DEATH(helper_const(make_not_null(p)), deathstring); EXPECT_DEATH(helper_const(make_not_null(p)), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
EXPECT_DEATH(make_not_null(nullptr), deathstring); EXPECT_DEATH(make_not_null(nullptr), expected);
EXPECT_DEATH(helper(make_not_null(nullptr)), deathstring); EXPECT_DEATH(helper(make_not_null(nullptr)), expected);
EXPECT_DEATH(helper_const(make_not_null(nullptr)), deathstring); EXPECT_DEATH(helper_const(make_not_null(nullptr)), expected);
} }
#endif #endif
} }

View File

@ -16,8 +16,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/span> // for span and span_ext
#include <gsl/util> // for narrow_cast, at #include <gsl/util> // for narrow_cast, at
#include <gsl/span_ext> // for operator==, operator!=, make_span
#include <array> // for array #include <array> // for array
#include <iostream> // for cerr #include <iostream> // for cerr
@ -26,17 +26,16 @@
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
namespace #include "deathTestCommon.h"
{
static constexpr char deathstring[] = "Expected Death";
} // namespace
TEST(span_ext_test, make_span_from_pointer_length_constructor) 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::cerr << "Expected Death. from_pointer_length_constructor";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[4] = {1, 2, 3, 4}; int arr[4] = {1, 2, 3, 4};
{ {
@ -57,7 +56,7 @@ TEST(span_ext_test, make_span_from_pointer_length_constructor)
{ {
int* p = nullptr; int* p = nullptr;
auto workaround_macro = [=]() { make_span(p, 2); }; auto workaround_macro = [=]() { make_span(p, 2); };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
} }
@ -239,6 +238,7 @@ TEST(span_ext_test, make_span_from_array_constructor)
EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s))); EXPECT_TRUE(s.size() == static_cast<std::size_t>(ssize(s)));
} }
#ifndef GSL_KERNEL_MODE
TEST(span_ext_test, comparison_operators) TEST(span_ext_test, comparison_operators)
{ {
{ {
@ -358,3 +358,4 @@ TEST(span_ext_test, make_span_from_array_constructor)
EXPECT_FALSE(s1 >= s2); EXPECT_FALSE(s1 >= s2);
} }
} }
#endif // GSL_KERNEL_MODE

View File

@ -17,19 +17,19 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/byte> // for byte #include <gsl/byte> // for byte
#include <gsl/util> // for narrow_cast, at
#include <gsl/span> // for span, span_iterator, operator==, operator!= #include <gsl/span> // for span, span_iterator, operator==, operator!=
#include <gsl/util> // for narrow_cast, at
#include <array> // for array #include <array> // for array
#include <cstddef> // for ptrdiff_t
#include <iostream> // for ptrdiff_t #include <iostream> // for ptrdiff_t
#include <iterator> // for reverse_iterator, operator-, operator== #include <iterator> // for reverse_iterator, operator-, operator==
#include <memory> // for unique_ptr, shared_ptr, make_unique, allo... #include <memory> // for unique_ptr, shared_ptr, make_unique, allo...
#include <regex> // for match_results, sub_match, match_results<>... #include <regex> // for match_results, sub_match, match_results<>...
#include <cstddef> // for ptrdiff_t
#include <string> // for string #include <string> // for string
#include <type_traits> // for integral_constant<>::value, is_default_co... #include <type_traits> // for integral_constant<>::value, is_default_co...
#include <vector> // for vector
#include <utility> #include <utility>
#include <vector> // for vector
// the string_view include and macro are used in the deduction guide verification // the string_view include and macro are used in the deduction guide verification
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
@ -41,12 +41,13 @@
#endif // __has_include #endif // __has_include
#endif // (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) #endif // (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
#include "deathTestCommon.h"
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
namespace namespace
{ {
static constexpr char deathstring[] = "Expected Death";
struct BaseClass struct BaseClass
{ {
@ -111,10 +112,12 @@ TEST(span_test, size_optimization)
TEST(span_test, from_nullptr_size_constructor) 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::cerr << "Expected Death. from_nullptr_size_constructor";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
span<int> s{nullptr, narrow_cast<span<int>::size_type>(0)}; span<int> s{nullptr, narrow_cast<span<int>::size_type>(0)};
EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.size() == 0);
@ -128,21 +131,21 @@ TEST(span_test, from_nullptr_size_constructor)
auto workaround_macro = []() { auto workaround_macro = []() {
const span<int, 1> s{nullptr, narrow_cast<span<int>::size_type>(0)}; const span<int, 1> s{nullptr, narrow_cast<span<int>::size_type>(0)};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
auto workaround_macro = []() { const span<int> s{nullptr, 1}; }; auto workaround_macro = []() { const span<int> s{nullptr, 1}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
auto const_workaround_macro = []() { const span<const int> s{nullptr, 1}; }; auto const_workaround_macro = []() { const span<const int> s{nullptr, 1}; };
EXPECT_DEATH(const_workaround_macro(), deathstring); EXPECT_DEATH(const_workaround_macro(), expected);
} }
{ {
auto workaround_macro = []() { const span<int, 0> s{nullptr, 1}; }; auto workaround_macro = []() { const span<int, 0> s{nullptr, 1}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
auto const_workaround_macro = []() { const span<const int, 0> s{nullptr, 1}; }; auto const_workaround_macro = []() { const span<const int, 0> s{nullptr, 1}; };
EXPECT_DEATH(const_workaround_macro(), deathstring); EXPECT_DEATH(const_workaround_macro(), expected);
} }
{ {
span<int*> s{nullptr, narrow_cast<span<int>::size_type>(0)}; span<int*> s{nullptr, narrow_cast<span<int>::size_type>(0)};
@ -157,10 +160,12 @@ TEST(span_test, from_nullptr_size_constructor)
TEST(span_test, from_pointer_length_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::cerr << "Expected Death. from_pointer_length_constructor";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[4] = {1, 2, 3, 4}; int arr[4] = {1, 2, 3, 4};
{ {
@ -171,8 +176,7 @@ TEST(span_test, from_pointer_length_constructor)
EXPECT_TRUE(s.size() == narrow_cast<std::size_t>(i)); EXPECT_TRUE(s.size() == narrow_cast<std::size_t>(i));
EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.data() == &arr[0]);
EXPECT_TRUE(s.empty() == (i == 0)); EXPECT_TRUE(s.empty() == (i == 0));
for (int j = 0; j < i; ++j) for (int j = 0; j < i; ++j) EXPECT_TRUE(arr[j] == s[narrow_cast<std::size_t>(j)]);
EXPECT_TRUE(arr[j] == s[narrow_cast<std::size_t>(j)]);
} }
{ {
span<int> s = {&arr[i], 4 - narrow_cast<std::size_t>(i)}; span<int> s = {&arr[i], 4 - narrow_cast<std::size_t>(i)};
@ -204,7 +208,7 @@ TEST(span_test, from_pointer_length_constructor)
{ {
int* p = nullptr; int* p = nullptr;
auto workaround_macro = [=]() { const span<int> s{p, 2}; }; auto workaround_macro = [=]() { const span<int> 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 // this will fail the std::distance() precondition, which asserts on MSVC debug builds
//{ //{
// auto workaround_macro = [&]() { span<int> s{&arr[1], &arr[0]}; }; // auto workaround_macro = [&]() { span<int> 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 // this will fail the std::distance() precondition, which asserts on MSVC debug builds
//{ //{
// int* p = nullptr; // int* p = nullptr;
// auto workaround_macro = [&]() { span<int> s{&arr[0], p}; }; // auto workaround_macro = [&]() { span<int> s{&arr[0], p}; };
// EXPECT_DEATH(workaround_macro(), deathstring); // EXPECT_DEATH(workaround_macro(), expected);
//} //}
{ {
@ -270,7 +274,7 @@ TEST(span_test, from_pointer_pointer_construction)
//{ //{
// int* p = nullptr; // int* p = nullptr;
// auto workaround_macro = [&]() { span<int> s{&arr[0], p}; }; // auto workaround_macro = [&]() { span<int> s{&arr[0], p}; };
// EXPECT_DEATH(workaround_macro(), deathstring); // EXPECT_DEATH(workaround_macro(), expected);
//} //}
} }
@ -692,7 +696,8 @@ TEST(span_test, from_array_constructor)
auto use_span = [&](span<const int> s) { auto use_span = [&](span<const int> s) {
EXPECT_TRUE(s.size() == 2); EXPECT_TRUE(s.size() == 2);
EXPECT_TRUE(s.data() == &arr[1]); EXPECT_TRUE(s.data() == &arr[1]);
}; use_span(get_temp_span()); };
use_span(get_temp_span());
s1 = get_temp_span(); s1 = get_temp_span();
EXPECT_TRUE(s1.size() == 2); EXPECT_TRUE(s1.size() == 2);
@ -701,10 +706,12 @@ TEST(span_test, from_array_constructor)
TEST(span_test, first) TEST(span_test, first)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. first"; std::cerr << "Expected Death. first";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
{ {
@ -731,7 +738,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(av.first<6>().size() == 6); EXPECT_TRUE(av.first<6>().size() == 6);
EXPECT_TRUE(av.first<-1>().size() == -1); EXPECT_TRUE(av.first<-1>().size() == -1);
#endif #endif
EXPECT_DEATH(av.first(6).size(), deathstring); EXPECT_DEATH(av.first(6).size(), expected);
} }
{ {
@ -743,10 +750,12 @@ TEST(span_test, from_array_constructor)
TEST(span_test, last) TEST(span_test, last)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. last"; std::cerr << "Expected Death. last";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
{ {
@ -772,7 +781,7 @@ TEST(span_test, from_array_constructor)
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
EXPECT_TRUE(av.last<6>().size() == 6); EXPECT_TRUE(av.last<6>().size() == 6);
#endif #endif
EXPECT_DEATH(av.last(6).size(), deathstring); EXPECT_DEATH(av.last(6).size(), expected);
} }
{ {
@ -784,10 +793,12 @@ TEST(span_test, from_array_constructor)
TEST(span_test, subspan) TEST(span_test, subspan)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. subspan"; std::cerr << "Expected Death. subspan";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
{ {
@ -811,8 +822,8 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5); EXPECT_TRUE(decltype(av.subspan<0, 5>())::extent == 5);
EXPECT_TRUE(av.subspan(0, 5).size() == 5); EXPECT_TRUE(av.subspan(0, 5).size() == 5);
EXPECT_DEATH(av.subspan(0, 6).size(), deathstring); EXPECT_DEATH(av.subspan(0, 6).size(), expected);
EXPECT_DEATH(av.subspan(1, 5).size(), deathstring); EXPECT_DEATH(av.subspan(1, 5).size(), expected);
} }
{ {
@ -821,7 +832,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0); EXPECT_TRUE(decltype(av.subspan<4, 0>())::extent == 0);
EXPECT_TRUE(av.subspan(4, 0).size() == 0); EXPECT_TRUE(av.subspan(4, 0).size() == 0);
EXPECT_TRUE(av.subspan(5, 0).size() == 0); EXPECT_TRUE(av.subspan(5, 0).size() == 0);
EXPECT_DEATH(av.subspan(6, 0).size(), deathstring); EXPECT_DEATH(av.subspan(6, 0).size(), expected);
} }
{ {
@ -835,13 +846,13 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE((av.subspan<0, 0>().size()) == 0); EXPECT_TRUE((av.subspan<0, 0>().size()) == 0);
EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0); EXPECT_TRUE(decltype(av.subspan<0, 0>())::extent == 0);
EXPECT_TRUE(av.subspan(0, 0).size() == 0); EXPECT_TRUE(av.subspan(0, 0).size() == 0);
EXPECT_DEATH((av.subspan<1, 0>().size()), deathstring); EXPECT_DEATH((av.subspan<1, 0>().size()), expected);
} }
{ {
span<int> av; span<int> av;
EXPECT_TRUE(av.subspan(0).size() == 0); EXPECT_TRUE(av.subspan(0).size() == 0);
EXPECT_DEATH(av.subspan(1).size(), deathstring); EXPECT_DEATH(av.subspan(1).size(), expected);
} }
{ {
@ -850,7 +861,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(av.subspan(1).size() == 4); EXPECT_TRUE(av.subspan(1).size() == 4);
EXPECT_TRUE(av.subspan(4).size() == 1); EXPECT_TRUE(av.subspan(4).size() == 1);
EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_TRUE(av.subspan(5).size() == 0);
EXPECT_DEATH(av.subspan(6).size(), deathstring); EXPECT_DEATH(av.subspan(6).size(), expected);
const auto av2 = av.subspan(1); const auto av2 = av.subspan(1);
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2); for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2);
} }
@ -861,7 +872,7 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(av.subspan(1).size() == 4); EXPECT_TRUE(av.subspan(1).size() == 4);
EXPECT_TRUE(av.subspan(4).size() == 1); EXPECT_TRUE(av.subspan(4).size() == 1);
EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_TRUE(av.subspan(5).size() == 0);
EXPECT_DEATH(av.subspan(6).size(), deathstring); EXPECT_DEATH(av.subspan(6).size(), expected);
const auto av2 = av.subspan(1); const auto av2 = av.subspan(1);
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2); for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av2[i] == static_cast<int>(i) + 2);
} }
@ -906,10 +917,11 @@ TEST(span_test, from_array_constructor)
TEST(span_test, incomparable_iterators) TEST(span_test, incomparable_iterators)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. incomparable_iterators"; std::cerr << "Expected Death. incomparable_iterators";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
int b[] = {1, 2, 3, 4}; int b[] = {1, 2, 3, 4};
@ -917,21 +929,23 @@ TEST(span_test, from_array_constructor)
span<int> s = a; span<int> s = a;
span<int> s2 = b; span<int> s2 = b;
#if (__cplusplus > 201402L) #if (__cplusplus > 201402L)
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()), deathstring); EXPECT_DEATH([[maybe_unused]] bool _ = (s.begin() <= s2.begin()), expected);
#else #else
EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), deathstring); EXPECT_DEATH(bool _ = (s.begin() == s2.begin()), expected);
EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), deathstring); EXPECT_DEATH(bool _ = (s.begin() <= s2.begin()), expected);
#endif #endif
} }
} }
TEST(span_test, begin_end) TEST(span_test, begin_end)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. begin_end"; std::cerr << "Expected Death. begin_end";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s = a; span<int> s = a;
@ -956,7 +970,7 @@ TEST(span_test, from_array_constructor)
auto beyond = s.end(); auto beyond = s.end();
EXPECT_TRUE(it != beyond); EXPECT_TRUE(it != beyond);
EXPECT_DEATH(*beyond, deathstring); EXPECT_DEATH(*beyond, expected);
EXPECT_TRUE(beyond - first == 4); EXPECT_TRUE(beyond - first == 4);
EXPECT_TRUE(first - first == 0); EXPECT_TRUE(first - first == 0);
@ -986,10 +1000,12 @@ TEST(span_test, from_array_constructor)
TEST(span_test, rbegin_rend) TEST(span_test, rbegin_rend)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. rbegin_rend"; std::cerr << "Expected Death. rbegin_rend";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
span<int> s = a; span<int> s = a;
@ -1002,9 +1018,9 @@ TEST(span_test, from_array_constructor)
auto beyond = s.rend(); auto beyond = s.rend();
EXPECT_TRUE(it != beyond); EXPECT_TRUE(it != beyond);
#if (__cplusplus > 201402L) #if (__cplusplus > 201402L)
EXPECT_DEATH([[maybe_unused]] auto _ = *beyond , deathstring); EXPECT_DEATH([[maybe_unused]] auto _ = *beyond, expected);
#else #else
EXPECT_DEATH(auto _ = *beyond , deathstring); EXPECT_DEATH(auto _ = *beyond, expected);
#endif #endif
EXPECT_TRUE(beyond - first == 4); EXPECT_TRUE(beyond - first == 4);
@ -1035,10 +1051,11 @@ TEST(span_test, from_array_constructor)
TEST(span_test, as_bytes) TEST(span_test, as_bytes)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. as_bytes"; std::cerr << "Expected Death. as_bytes";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
{ {
@ -1069,7 +1086,7 @@ TEST(span_test, from_array_constructor)
int b[5] = {1, 2, 3, 4, 5}; int b[5] = {1, 2, 3, 4, 5};
{ {
span<int> sp(begin(b), static_cast<size_t>(-2)); span<int> sp(begin(b), static_cast<size_t>(-2));
EXPECT_DEATH((void) sp.size_bytes(), deathstring); EXPECT_DEATH((void) sp.size_bytes(), expected);
} }
} }
@ -1108,10 +1125,12 @@ TEST(span_test, from_array_constructor)
TEST(span_test, fixed_size_conversions) TEST(span_test, fixed_size_conversions)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. fixed_size_conversions"; std::cerr << "Expected Death. fixed_size_conversions";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
int arr[] = {1, 2, 3, 4}; int arr[] = {1, 2, 3, 4};
// converting to an span from an equal size array is ok // converting to an span from an equal size array is ok
@ -1146,7 +1165,7 @@ TEST(span_test, from_array_constructor)
const span<int, 2> s2 = s; const span<int, 2> s2 = s;
static_cast<void>(s2); static_cast<void>(s2);
}; };
EXPECT_DEATH(f(), deathstring); EXPECT_DEATH(f(), expected);
*/ */
} }
@ -1193,17 +1212,18 @@ TEST(span_test, from_array_constructor)
const span<int, 4> _s4{arr2, 2}; const span<int, 4> _s4{arr2, 2};
static_cast<void>(_s4); static_cast<void>(_s4);
}; };
EXPECT_DEATH(f(), deathstring); 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 // this should fail - we are trying to assign a small dynamic span to a fixed_size larger one
span<int> av = arr2; auto f = [&]() { span<int> av = arr2; auto f = [&]() {
const span<int, 4> _s4 = av; const span<int, 4> _s4 = av;
static_cast<void>(_s4); static_cast<void>(_s4);
}; };
EXPECT_DEATH(f(), deathstring); EXPECT_DEATH(f(), expected);
*/ */
} }
@ -1268,11 +1288,13 @@ TEST(span_test, from_array_constructor)
EXPECT_TRUE(s.front() == 1); EXPECT_TRUE(s.front() == 1);
EXPECT_TRUE(s.back() == 5); EXPECT_TRUE(s.back() == 5);
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. front_back"; std::cerr << "Expected Death. front_back";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
span<int> s2; span<int> s2;
EXPECT_DEATH(s2.front(), deathstring); EXPECT_DEATH(s2.front(), expected);
EXPECT_DEATH(s2.back(), deathstring); EXPECT_DEATH(s2.back(), expected);
} }

View File

@ -14,23 +14,33 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include <gtest/gtest.h>
#include <gsl/pointers> // for not_null, operator<, operator<=, operator> #include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <gtest/gtest.h>
#include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
namespace namespace
{ {
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool helper(not_null<int*> p) { return *p == 12; } bool helper(not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool helper_const(not_null<const int*> p) { return *p == 12; } bool helper_const(not_null<const int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool strict_helper(strict_not_null<int*> p) { return *p == 12; } bool strict_helper(strict_not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; } bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -123,17 +133,14 @@ TEST(strict_notnull_tests, TestStrictNotNull)
} }
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction) TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction"; std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
{ {
int i = 42; int i = 42;
@ -161,7 +168,7 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
int* p1 = nullptr; int* p1 = nullptr;
const strict_not_null x{p1}; 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 int* p1 = nullptr;
const strict_not_null x{p1}; const strict_not_null x{p1};
}; };
EXPECT_DEATH(workaround_macro(), deathstring); EXPECT_DEATH(workaround_macro(), expected);
} }
{ {
int* p = nullptr; int* p = nullptr;
EXPECT_DEATH(helper(strict_not_null{p}), deathstring); EXPECT_DEATH(helper(strict_not_null{p}), expected);
EXPECT_DEATH(helper_const(strict_not_null{p}), deathstring); EXPECT_DEATH(helper_const(strict_not_null{p}), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS

View File

@ -28,13 +28,11 @@
#include <type_traits> // for remove_reference<>::type #include <type_traits> // for remove_reference<>::type
#include <vector> // for vector, allocator #include <vector> // for vector, allocator
#include "deathTestCommon.h"
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
// Generic string functions // Generic string functions
namespace generic namespace generic
@ -76,8 +74,7 @@ T create()
template <class T> template <class T>
void use(basic_string_span<T, gsl::dynamic_extent>) void use(basic_string_span<T, gsl::dynamic_extent>)
{ {}
}
#endif #endif
czstring_span<> CreateTempName(string_span<> span) czstring_span<> CreateTempName(string_span<> span)
@ -85,7 +82,8 @@ czstring_span<> CreateTempName(string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = 't'; span[0] = 't';
span[1] = 'm'; span[1] = 'm';
span[2] = 'p'; span[2] = 'p';
@ -102,7 +100,8 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = L't'; span[0] = L't';
span[1] = L'm'; span[1] = L'm';
span[2] = L'p'; span[2] = L'p';
@ -119,7 +118,8 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = u't'; span[0] = u't';
span[1] = u'm'; span[1] = u'm';
span[2] = u'p'; span[2] = u'p';
@ -136,7 +136,8 @@ cu32zstring_span<> CreateTempNameU32(u32string_span<> span)
Expects(span.size() > 1); Expects(span.size() > 1);
std::size_t last = 0; std::size_t last = 0;
if (span.size() > 4) { if (span.size() > 4)
{
span[0] = U't'; span[0] = U't';
span[1] = U'm'; span[1] = U'm';
span[2] = U'p'; span[2] = U'p';
@ -950,10 +951,11 @@ TEST(string_span_tests, Conversion)
TEST(string_span_tests, zstring) TEST(string_span_tests, zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. zstring"; std::cerr << "Expected Death. zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -973,7 +975,7 @@ TEST(string_span_tests, zstring)
buf[0] = 'a'; buf[0] = 'a';
auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); }; 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 // 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]; char buf[10];
auto name = CreateTempName({buf, 10}); auto name = CreateTempName({buf, 10});
if (!name.empty()) { if (!name.empty())
{
czstring<> str = name.assume_z(); czstring<> str = name.assume_z();
EXPECT_TRUE(generic::strlen(str) == 3); EXPECT_TRUE(generic::strlen(str) == 3);
EXPECT_TRUE(*(str + 3) == '\0'); EXPECT_TRUE(*(str + 3) == '\0');
@ -991,10 +994,11 @@ TEST(string_span_tests, zstring)
TEST(string_span_tests, wzstring) TEST(string_span_tests, wzstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. wzstring"; std::cerr << "Expected Death. wzstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1014,7 +1018,7 @@ TEST(string_span_tests, wzstring)
buf[0] = L'a'; buf[0] = L'a';
const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); }; 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 // 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]; wchar_t buf[10];
const auto name = CreateTempNameW({buf, 10}); const auto name = CreateTempNameW({buf, 10});
if (!name.empty()) { if (!name.empty())
{
cwzstring<> str = name.assume_z(); cwzstring<> str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');
@ -1032,10 +1037,11 @@ TEST(string_span_tests, wzstring)
TEST(string_span_tests, u16zstring) TEST(string_span_tests, u16zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. u16zstring"; std::cerr << "Expected Death. u16zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1055,7 +1061,7 @@ TEST(string_span_tests, u16zstring)
buf[0] = u'a'; buf[0] = u'a';
const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); }; 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 // 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]; char16_t buf[10];
const auto name = CreateTempNameU16({buf, 10}); const auto name = CreateTempNameU16({buf, 10});
if (!name.empty()) { if (!name.empty())
{
cu16zstring<> str = name.assume_z(); cu16zstring<> str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');
@ -1073,10 +1080,11 @@ TEST(string_span_tests, u16zstring)
TEST(string_span_tests, u32zstring) TEST(string_span_tests, u32zstring)
{ {
std::set_terminate([] { const auto terminateHandler = std::set_terminate([] {
std::cerr << "Expected Death. u31zstring"; std::cerr << "Expected Death. u31zstring";
std::abort(); std::abort();
}); });
const auto expected = GetExpectedDeathString(terminateHandler);
// create zspan from zero terminated string // create zspan from zero terminated string
{ {
@ -1096,7 +1104,7 @@ TEST(string_span_tests, u32zstring)
buf[0] = u'a'; buf[0] = u'a';
const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); }; 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 // 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]; char32_t buf[10];
const auto name = CreateTempNameU32({buf, 10}); const auto name = CreateTempNameU32({buf, 10});
if (!name.empty()) { if (!name.empty())
{
cu32zstring<> str = name.assume_z(); cu32zstring<> str = name.assume_z();
EXPECT_TRUE(generic::strnlen(str, 10) == 3); EXPECT_TRUE(generic::strnlen(str, 10) == 3);
EXPECT_TRUE(*(str + 3) == L'\0'); EXPECT_TRUE(*(str + 3) == L'\0');

View File

@ -16,14 +16,14 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/util> // finally, narrow_cast
#include <gsl/narrow> // for narrow, narrowing_error
#include <algorithm> // for move #include <algorithm> // for move
#include <cstddef> // for std::ptrdiff_t
#include <functional> // for reference_wrapper, _Bind_helper<>::type #include <functional> // for reference_wrapper, _Bind_helper<>::type
#include <gsl/narrow> // for narrow, narrowing_error
#include <gsl/util> // finally, narrow_cast
#include <limits> // for numeric_limits #include <limits> // for numeric_limits
#include <stdint.h> // for uint32_t, int32_t #include <stdint.h> // for uint32_t, int32_t
#include <type_traits> // for is_same #include <type_traits> // for is_same
#include <cstddef> // for std::ptrdiff_t
using namespace gsl; using namespace gsl;
@ -32,8 +32,7 @@ namespace
void f(int& i) { i += 1; } void f(int& i) { i += 1; }
static int j = 0; static int j = 0;
void g() { j += 1; } void g() { j += 1; }
} } // namespace
TEST(utils_tests, sanity_check_for_gsl_index_typedef) TEST(utils_tests, sanity_check_for_gsl_index_typedef)
{ {
@ -123,6 +122,7 @@ TEST(utils_tests, narrow_cast)
EXPECT_TRUE(uc == 44); EXPECT_TRUE(uc == 44);
} }
#ifndef GSL_KERNEL_MODE
TEST(utils_tests, narrow) TEST(utils_tests, narrow)
{ {
int n = 120; int n = 120;
@ -145,3 +145,4 @@ TEST(utils_tests, narrow)
n = -42; n = -42;
EXPECT_THROW(narrow<unsigned>(n), narrowing_error); EXPECT_THROW(narrow<unsigned>(n), narrowing_error);
} }
#endif // GSL_KERNEL_MODE