More checks for non-compilable code, plus fix for span (#1180)
Some checks failed
CI_Android / Android (push) Has been cancelled
cmake_find_package / Build ${{ matrix.os }} (macos-latest) (push) Has been cancelled
cmake_find_package / Build ${{ matrix.os }} (ubuntu-latest) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 14, 12) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 14, 13) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 14, 14) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 17, 12) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 17, 13) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 17, 14) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 20, 13) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 20, 14) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 23, 13) (push) Has been cancelled
Compiler Integration Tests / gcc (Debug, 23, 14) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 14, 12) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 14, 13) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 14, 14) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 17, 12) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 17, 13) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 17, 14) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 20, 13) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 20, 14) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 23, 13) (push) Has been cancelled
Compiler Integration Tests / gcc (Release, 23, 14) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 16, 14) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 16, 17) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 16, 20) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 16, 23) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 17, 14) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 17, 17) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 17, 20) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 18, 14) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 18, 17) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 18, 20) (push) Has been cancelled
Compiler Integration Tests / clang (Debug, 18, 23) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 16, 14) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 16, 17) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 16, 20) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 16, 23) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 17, 14) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 17, 17) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 17, 20) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 18, 14) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 18, 17) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 18, 20) (push) Has been cancelled
Compiler Integration Tests / clang (Release, 18, 23) (push) Has been cancelled
Compiler Integration Tests / xcode (Debug, 14, 15.4) (push) Has been cancelled
Compiler Integration Tests / xcode (Debug, 17, 15.4) (push) Has been cancelled
Compiler Integration Tests / xcode (Debug, 20, 15.4) (push) Has been cancelled
Compiler Integration Tests / xcode (Debug, 23, 15.4) (push) Has been cancelled
Compiler Integration Tests / xcode (Release, 14, 15.4) (push) Has been cancelled
Compiler Integration Tests / xcode (Release, 17, 15.4) (push) Has been cancelled
Compiler Integration Tests / xcode (Release, 20, 15.4) (push) Has been cancelled
Compiler Integration Tests / xcode (Release, 23, 15.4) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 14, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 14, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 14, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 14, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 17, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 17, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 17, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 17, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 20, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 20, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 20, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 20, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 23, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Debug, 23, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 14, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 14, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 14, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 14, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 17, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 17, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 17, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 17, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 20, , Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 20, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 20, -T ClangCL, Visual Studio 16 2019, windows-2019) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 20, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 23, , Visual Studio 17 2022, windows-2022) (push) Has been cancelled
Compiler Integration Tests / VisualStudio (Release, 23, -T ClangCL, Visual Studio 17 2022, windows-2022) (push) Has been cancelled
CI_iOS / iOS (push) Has been cancelled

This commit is contained in:
Werner Henze 2025-01-04 18:50:31 +01:00 committed by GitHub
parent c832885f15
commit 1cdb8d295e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 439 additions and 412 deletions

View File

@ -582,6 +582,8 @@ public:
template <std::size_t Count> template <std::size_t Count>
constexpr span<element_type, Count> first() const noexcept constexpr span<element_type, Count> first() const noexcept
{ {
static_assert(Extent == dynamic_extent || Count <= Extent,
"first() cannot extract more elements from a span than it contains.");
Expects(Count <= size()); Expects(Count <= size());
return span<element_type, Count>{data(), Count}; return span<element_type, Count>{data(), Count};
} }
@ -592,6 +594,8 @@ public:
// clang-format on // clang-format on
constexpr span<element_type, Count> last() const noexcept constexpr span<element_type, Count> last() const noexcept
{ {
static_assert(Extent == dynamic_extent || Count <= Extent,
"last() cannot extract more elements from a span than it contains.");
Expects(Count <= size()); Expects(Count <= size());
return span<element_type, Count>{data() + (size() - Count), Count}; return span<element_type, Count>{data() + (size() - Count), Count};
} }
@ -603,6 +607,9 @@ public:
constexpr auto subspan() const noexcept -> constexpr auto subspan() const noexcept ->
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
{ {
static_assert(Extent == dynamic_extent || (Extent >= Offset && (Count == dynamic_extent ||
Count <= Extent - Offset)),
"subspan() cannot extract more elements from a span than it contains.");
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
using type = using type =
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type; typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;

View File

@ -188,7 +188,7 @@ TEST(algorithm_tests, incompatible_type)
span<int> src_span_dyn(src); span<int> src_span_dyn(src);
span<int, 4> src_span_static(src); span<int, 4> src_span_static(src);
span<int*> dst_span_dyn(dst); span<int*> dst_span_dyn(dst);
span<int*, 4> dst_span_static(dst); span<int*, 4> dst_span_static(gsl::make_span(dst));
// every line should produce a compilation error // every line should produce a compilation error
copy(src_span_dyn, dst_span_dyn); copy(src_span_dyn, dst_span_dyn);

View File

@ -67,6 +67,8 @@ TEST(byte_tests, construction)
to_byte(char{}); to_byte(char{});
to_byte(3); to_byte(3);
to_byte(3u); to_byte(3u);
to_byte<-1>();
to_byte<256u>();
#endif #endif
} }
@ -174,7 +176,3 @@ static constexpr bool
static_assert(!ToIntegerCompilesFor<float>, "!ToIntegerCompilesFor<float>"); static_assert(!ToIntegerCompilesFor<float>, "!ToIntegerCompilesFor<float>");
} // namespace } // namespace
#ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static);
#endif

View File

@ -23,12 +23,20 @@
#include <memory> // for shared_ptr, make_shared, operator<, opera... #include <memory> // for shared_ptr, make_shared, operator<, opera...
#include <sstream> // for operator<<, ostringstream, basic_ostream:... #include <sstream> // for operator<<, ostringstream, basic_ostream:...
#include <string> // for basic_string, operator==, string, operator<< #include <string> // for basic_string, operator==, string, operator<<
#include <type_traits> // for declval
#include <typeinfo> // for type_info #include <typeinfo> // for type_info
#include <variant> // for variant, monostate, get #include <variant> // for variant, monostate, get
#include "deathTestCommon.h" #include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l
struct MyBase struct MyBase
{ {
}; };
@ -141,16 +149,39 @@ bool helper_const(not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; } int* return_pointer() { return nullptr; }
} // namespace } // namespace
template <typename U, typename = void>
static constexpr bool CtorCompilesFor_A = false;
template <typename U>
static constexpr bool
CtorCompilesFor_A<U, void_t<decltype(gsl::not_null<void*>{std::declval<U>()})>> = true;
template <typename U, int N, typename = void>
static constexpr bool CtorCompilesFor_B = false;
template <typename U, int N>
static constexpr bool CtorCompilesFor_B<U, N, void_t<decltype(gsl::not_null<U>{N})>> = true;
template <typename U, typename = void>
static constexpr bool DefaultCtorCompilesFor = false;
template <typename U>
static constexpr bool DefaultCtorCompilesFor<U, void_t<decltype(gsl::not_null<U>{})>> = true;
template <typename U, typename = void>
static constexpr bool CtorCompilesFor_C = false;
template <typename U>
static constexpr bool
CtorCompilesFor_C<U, void_t<decltype(gsl::not_null<U*>{std::declval<std::unique_ptr<U>>()})>> =
true;
TEST(notnull_tests, TestNotNullConstructors) TEST(notnull_tests, TestNotNullConstructors)
{ {
{ {
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(CtorCompilesFor_A<void*>, "CtorCompilesFor_A<void*>");
not_null<int*> p = nullptr; // yay...does not compile! static_assert(!CtorCompilesFor_A<std::nullptr_t>, "!CtorCompilesFor_A<std::nullptr_t>");
not_null<std::vector<char>*> p1 = 0; // yay...does not compile! static_assert(!CtorCompilesFor_B<void*, 0>, "!CtorCompilesFor_B<void*, 0>");
not_null<int*> p2; // yay...does not compile! static_assert(!DefaultCtorCompilesFor<void*>, "!DefaultCtorCompilesFor<void*>");
std::unique_ptr<int> up = std::make_unique<int>(120); static_assert(!CtorCompilesFor_C<int>, "CtorCompilesFor_C<int>");
not_null<int*> p3 = up;
#ifdef CONFIRM_COMPILATION_ERRORS
// Forbid non-nullptr assignable types // Forbid non-nullptr assignable types
not_null<std::vector<int>> f(std::vector<int>{1}); not_null<std::vector<int>> f(std::vector<int>{1});
not_null<int> z(10); not_null<int> z(10);
@ -276,6 +307,27 @@ TEST(notnull_tests, TestNotNullostream)
ostream_helper<std::string>("string"); ostream_helper<std::string>("string");
} }
template <typename U, typename V, typename = void>
static constexpr bool AssignmentCompilesFor = false;
template <typename U, typename V>
static constexpr bool
AssignmentCompilesFor<U, V,
void_t<decltype(std::declval<gsl::not_null<U*>&>().operator=(
std::declval<gsl::not_null<V*>&>()))>> = true;
template <typename U, typename V, typename = void>
static constexpr bool SCastCompilesFor = false;
template <typename U, typename V>
static constexpr bool
SCastCompilesFor<U, V, void_t<decltype(static_cast<U*>(std::declval<gsl::not_null<V*>&>()))>> =
true;
template <typename U, typename V, typename = void>
static constexpr bool RCastCompilesFor = false;
template <typename U, typename V>
static constexpr bool RCastCompilesFor<
U, V, void_t<decltype(reinterpret_cast<U*>(std::declval<gsl::not_null<V*>&>()))>> = true;
TEST(notnull_tests, TestNotNullCasting) TEST(notnull_tests, TestNotNullCasting)
{ {
MyBase base; MyBase base;
@ -288,15 +340,30 @@ TEST(notnull_tests, TestNotNullCasting)
q = p; // allowed with heterogeneous copy ctor q = p; // allowed with heterogeneous copy ctor
EXPECT_TRUE(q == p); EXPECT_TRUE(q == p);
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(AssignmentCompilesFor<MyBase, MyDerived>,
q = u; // no viable conversion possible between MyBase* and Unrelated* "AssignmentCompilesFor<MyBase, MyDerived>");
p = q; // not possible to implicitly convert MyBase* to MyDerived* static_assert(!AssignmentCompilesFor<MyBase, Unrelated>,
"!AssignmentCompilesFor<MyBase, Unrelated>");
static_assert(!AssignmentCompilesFor<Unrelated, MyDerived>,
"!AssignmentCompilesFor<Unrelated, MyDerived>");
static_assert(!AssignmentCompilesFor<MyDerived, MyBase>,
"!AssignmentCompilesFor<MyDerived, MyBase>");
static_assert(SCastCompilesFor<MyDerived, MyDerived>, "SCastCompilesFor<MyDerived, MyDerived>");
static_assert(SCastCompilesFor<MyBase, MyDerived>, "SCastCompilesFor<MyBase, MyDerived>");
static_assert(!SCastCompilesFor<MyDerived, MyBase>, "!SCastCompilesFor<MyDerived, MyBase>");
static_assert(!SCastCompilesFor<Unrelated, MyDerived>,
"!SCastCompilesFor<Unrelated, MyDerived>");
static_assert(!RCastCompilesFor<MyDerived, MyDerived>,
"!SCastCompilesFor<MyDerived, MyDerived>");
static_assert(!RCastCompilesFor<Unrelated, MyDerived>,
"!SCastCompilesFor<Unrelated, MyDerived>");
not_null<Unrelated*> r = p;
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
#endif
not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get())); not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get()));
EXPECT_TRUE(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get())); EXPECT_TRUE(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
(void) static_cast<MyDerived*>(p);
(void) static_cast<MyBase*>(p);
} }
TEST(notnull_tests, TestNotNullAssignment) TEST(notnull_tests, TestNotNullAssignment)
@ -438,6 +505,18 @@ TEST(notnull_tests, TestNotNullCustomPtrComparison)
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
template <typename U, typename = void>
static constexpr bool TypeDeductionCtorCompilesFor = false;
template <typename U>
static constexpr bool
TypeDeductionCtorCompilesFor<U, void_t<decltype(not_null{std::declval<U>()})>> = true;
template <typename U, typename = void>
static constexpr bool TypeDeductionHelperCompilesFor = false;
template <typename U>
static constexpr bool
TypeDeductionHelperCompilesFor<U, void_t<decltype(helper(not_null{std::declval<U>()}))>> = true;
TEST(notnull_tests, TestNotNullConstructorTypeDeduction) TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
{ {
{ {
@ -454,9 +533,9 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
const int i = 42; const int i = 42;
not_null x{&i}; not_null x{&i};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(TypeDeductionHelperCompilesFor<int*>, "TypeDeductionHelperCompilesFor<int*>");
helper(not_null{&i}); static_assert(!TypeDeductionHelperCompilesFor<const int*>,
#endif "!TypeDeductionHelperCompilesFor<const int*>");
helper_const(not_null{&i}); helper_const(not_null{&i});
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
@ -478,9 +557,6 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
const int* p = &i; const int* p = &i;
not_null x{p}; not_null x{p};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(not_null{p});
#endif
helper_const(not_null{p}); helper_const(not_null{p});
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
@ -515,12 +591,15 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
EXPECT_DEATH(helper_const(not_null{p}), expected); EXPECT_DEATH(helper_const(not_null{p}), expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(TypeDeductionCtorCompilesFor<void*>, "TypeDeductionCtorCompilesFor<void*>");
{ #if defined(_MSC_VER) && !defined(__clang__)
not_null x{nullptr}; // Fails on gcc, clang, xcode, VS clang with
helper(not_null{nullptr}); // "error : no type named 'type' in 'std::enable_if<false>'; 'enable_if' cannot be used to
helper_const(not_null{nullptr}); // disable this declaration"
} static_assert(!TypeDeductionCtorCompilesFor<std::nullptr_t>,
"!TypeDeductionCtorCompilesFor<std::nullptr_t>");
static_assert(!TypeDeductionHelperCompilesFor<std::nullptr_t>,
"!TypeDeductionHelperCompilesFor<std::nullptr_t>");
#endif #endif
} }
@ -536,6 +615,11 @@ TEST(notnull_tests, TestVariantEmplace)
} }
#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
template <typename U, typename = void>
static constexpr bool HelperCompilesFor = false;
template <typename U>
static constexpr bool HelperCompilesFor<U, void_t<decltype(helper(std::declval<U>()))>> = true;
TEST(notnull_tests, TestMakeNotNull) TEST(notnull_tests, TestMakeNotNull)
{ {
{ {
@ -552,9 +636,8 @@ TEST(notnull_tests, TestMakeNotNull)
const int i = 42; const int i = 42;
const auto x = make_not_null(&i); const auto x = make_not_null(&i);
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(HelperCompilesFor<gsl::not_null<int*>>,
helper(make_not_null(&i)); "HelperCompilesFor<gsl::not_null<int*>>");
#endif
helper_const(make_not_null(&i)); helper_const(make_not_null(&i));
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
@ -576,9 +659,8 @@ TEST(notnull_tests, TestMakeNotNull)
const int* p = &i; const int* p = &i;
const auto x = make_not_null(p); const auto x = make_not_null(p);
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!HelperCompilesFor<gsl::not_null<const int*>>,
helper(make_not_null(p)); "!HelperCompilesFor<gsl::not_null<const int*>>");
#endif
helper_const(make_not_null(p)); helper_const(make_not_null(p));
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);

View File

@ -17,6 +17,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gsl/pointers> // for owner #include <gsl/pointers> // for owner
#include <type_traits> // for declval
using namespace gsl; using namespace gsl;
@ -32,12 +33,18 @@ TEST(owner_tests, basic_test)
delete p; delete p;
} }
TEST(owner_tests, check_pointer_constraint) #if __cplusplus >= 201703l
{ using std::void_t;
#ifdef CONFIRM_COMPILATION_ERRORS #else // __cplusplus >= 201703l
{ template <class...>
owner<int> integerTest = 10; using void_t = void;
owner<std::shared_ptr<int>> sharedPtrTest(new int(10)); #endif // __cplusplus < 201703l
}
#endif template <typename U, typename = void>
} static constexpr bool OwnerCompilesFor = false;
template <typename U>
static constexpr bool OwnerCompilesFor<U, void_t<decltype(gsl::owner<U>{})>> =
true;
static_assert(OwnerCompilesFor<int*>, "OwnerCompilesFor<int*>");
static_assert(!OwnerCompilesFor<int>, "!OwnerCompilesFor<int>");
static_assert(!OwnerCompilesFor<std::shared_ptr<int>>, "!OwnerCompilesFor<std::shared_ptr<int>>");

View File

@ -6,6 +6,13 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l
namespace namespace
{ {
// Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped. // Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped.
@ -22,6 +29,13 @@ struct NotMoveAssignableCustomPtr
int dummy{}; // Without this clang warns, that NotMoveAssignableCustomPtr() is unneeded int dummy{}; // Without this clang warns, that NotMoveAssignableCustomPtr() is unneeded
}; };
template <typename U, typename = void>
static constexpr bool SwapCompilesFor = false;
template <typename U>
static constexpr bool
SwapCompilesFor<U, void_t<decltype(gsl::swap<U>(std::declval<gsl::not_null<U>&>(),
std::declval<gsl::not_null<U>&>()))>> = true;
TEST(pointers_test, swap) TEST(pointers_test, swap)
{ {
// taken from gh-1129: // taken from gh-1129:
@ -69,22 +83,9 @@ TEST(pointers_test, swap)
EXPECT_TRUE(*a == 1); EXPECT_TRUE(*a == 1);
EXPECT_TRUE(*b == 0); EXPECT_TRUE(*b == 0);
} }
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");
} }
#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l
template <typename U, typename = void>
static constexpr bool SwapCompilesFor = false;
template <typename U>
static constexpr bool
SwapCompilesFor<U, void_t<decltype(gsl::swap<U>(std::declval<gsl::not_null<U>&>(),
std::declval<gsl::not_null<U>&>()))>> = true;
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");
} // namespace } // namespace

View File

@ -48,6 +48,13 @@
using namespace gsl; using namespace gsl;
#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l
namespace namespace
{ {
@ -62,8 +69,7 @@ struct AddressOverloaded
#if (__cplusplus > 201402L) #if (__cplusplus > 201402L)
[[maybe_unused]] [[maybe_unused]]
#endif #endif
AddressOverloaded AddressOverloaded operator&() const
operator&() const
{ {
return {}; return {};
} }
@ -216,6 +222,12 @@ TEST(span_test, from_pointer_length_constructor)
TEST(span_test, from_pointer_pointer_construction) TEST(span_test, from_pointer_pointer_construction)
{ {
// const auto terminateHandler = std::set_terminate([] {
// std::cerr << "Expected Death. from_pointer_pointer_construction";
// std::abort();
// });
// const auto expected = GetExpectedDeathString(terminateHandler);
int arr[4] = {1, 2, 3, 4}; int arr[4] = {1, 2, 3, 4};
{ {
@ -245,19 +257,11 @@ TEST(span_test, from_pointer_pointer_construction)
EXPECT_TRUE(s.data() == &arr[0]); EXPECT_TRUE(s.data() == &arr[0]);
} }
// this will fail the std::distance() precondition, which asserts on MSVC debug builds //{ // this test succeeds on all platforms, gsl::span is more relaxed than std::span where this would be UB
//{
// auto workaround_macro = [&]() { span<int> s{&arr[1], &arr[0]}; }; // auto workaround_macro = [&]() { span<int> s{&arr[1], &arr[0]}; };
// EXPECT_DEATH(workaround_macro(), expected); // 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<int> s{&arr[0], p}; };
// EXPECT_DEATH(workaround_macro(), expected);
//}
{ {
int* p = nullptr; int* p = nullptr;
span<int> s{p, p}; span<int> s{p, p};
@ -271,19 +275,21 @@ TEST(span_test, from_pointer_pointer_construction)
EXPECT_TRUE(s.size() == 0); EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == nullptr); EXPECT_TRUE(s.data() == nullptr);
} }
// this will fail the std::distance() precondition, which asserts on MSVC debug builds
//{
// int* p = nullptr;
// auto workaround_macro = [&]() { span<int> s{&arr[0], p}; };
// EXPECT_DEATH(workaround_macro(), expected);
//}
} }
template <typename U, typename V, typename = void>
static constexpr bool CtorCompilesFor = false;
template <typename U, typename V>
static constexpr bool CtorCompilesFor<U, V, void_t<decltype(U{std::declval<V>()})>> = true;
TEST(span_test, from_array_constructor) TEST(span_test, from_array_constructor)
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
static_assert(!CtorCompilesFor<span<int, 6>, int[5]>, "!CtorCompilesFor<span<int, 6>, int[5]>");
static_assert(!CtorCompilesFor<span<int, 0>, int[5]>, "!CtorCompilesFor<span<int, 0>, int[5]>");
static_assert(!CtorCompilesFor<span<int>, int[2][3]>, "!CtorCompilesFor<span<int>, int[2][3]>");
{ {
const span<int> s{arr}; const span<int> s{arr};
EXPECT_TRUE(s.size() == 5); EXPECT_TRUE(s.size() == 5);
@ -298,70 +304,28 @@ TEST(span_test, from_array_constructor)
int arr2d[2][3] = {1, 2, 3, 4, 5, 6}; int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!CtorCompilesFor<span<int, 0>, int[2][3]>,
{ "!CtorCompilesFor<span<int, 0>, int[2][3]>");
span<int, 6> s{arr}; static_assert(!CtorCompilesFor<span<int, 6>, int[2][3]>,
} "!CtorCompilesFor<span<int, 6>, int[2][3]>");
{
span<int, 0> s{arr};
EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == &arr[0]);
}
{
span<int> 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<int, 0> s{arr2d};
EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == &arr2d[0][0]);
}
{
span<int, 6> s{arr2d};
}
#endif
{ {
const span<int[3]> s{std::addressof(arr2d[0]), 1}; const span<int[3]> s{std::addressof(arr2d[0]), 1};
EXPECT_TRUE(s.size() == 1); EXPECT_TRUE(s.size() == 1);
EXPECT_TRUE(s.data() == std::addressof(arr2d[0])); 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 static_assert(!CtorCompilesFor<span<int>, int[2][3][2]>,
{ "!CtorCompilesFor<span<int>, int[2][3][2]>");
span<int> s{arr3d}; static_assert(!CtorCompilesFor<span<int, 0>, int[2][3][2]>,
EXPECT_TRUE(s.size() == 12); "!CtorCompilesFor<span<int, 0>, int[2][3][2]>");
EXPECT_TRUE(s.data() == &arr3d[0][0][0]); static_assert(!CtorCompilesFor<span<int, 11>, int[2][3][2]>,
EXPECT_TRUE(s[0] == 1); "!CtorCompilesFor<span<int, 11>, int[2][3][2]>");
EXPECT_TRUE(s[11] == 12); static_assert(!CtorCompilesFor<span<int, 12>, int[2][3][2]>,
} "!CtorCompilesFor<span<int, 12>, int[2][3][2]>");
{
span<int, 0> s{arr3d};
EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == &arr3d[0][0][0]);
}
{
span<int, 11> s{arr3d};
}
{
span<int, 12> 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<int[3][2]> s{std::addressof(arr3d[0]), 1}; const span<int[3][2]> s{std::addressof(arr3d[0]), 1};
EXPECT_TRUE(s.size() == 1); EXPECT_TRUE(s.size() == 1);
@ -389,6 +353,13 @@ TEST(span_test, from_dynamic_array_constructor)
delete[] arr; delete[] arr;
} }
template <typename U, typename V, typename = void>
static constexpr bool ConversionCompilesFor = false;
template <typename U, typename V>
static constexpr bool
ConversionCompilesFor<U, V, void_t<decltype(std::declval<void (*)(U)>()(std::declval<V>()))>> =
true;
TEST(span_test, from_std_array_constructor) TEST(span_test, from_std_array_constructor)
{ {
std::array<int, 4> arr = {1, 2, 3, 4}; std::array<int, 4> arr = {1, 2, 3, 4};
@ -428,43 +399,31 @@ TEST(span_test, from_std_array_constructor)
EXPECT_TRUE(ao_arr.data() == fs.data()); EXPECT_TRUE(ao_arr.data() == fs.data());
} }
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!CtorCompilesFor<span<int, 2>, std::array<int, 4>&>,
{ "!CtorCompilesFor<span<int, 2>, std::array<int, 4>&>");
span<int, 2> s{arr}; static_assert(!CtorCompilesFor<span<const int, 2>, std::array<int, 4>&>,
EXPECT_TRUE(s.size() == 2); "!CtorCompilesFor<span<const int, 2>, std::array<int, 4>&>");
EXPECT_TRUE(s.data() == arr.data());
span<const int, 2> cs{arr}; static_assert(!CtorCompilesFor<span<int, 0>, std::array<int, 4>&>,
EXPECT_TRUE(cs.size() == 2); "!CtorCompilesFor<span<int, 0>, std::array<int, 4>&>");
EXPECT_TRUE(cs.data() == arr.data()); static_assert(!CtorCompilesFor<span<const int, 0>, std::array<int, 4>&>,
} "!CtorCompilesFor<span<const int, 0>, std::array<int, 4>&>");
{ static_assert(!CtorCompilesFor<span<int, 5>, std::array<int, 4>&>,
span<int, 0> s{arr}; "!CtorCompilesFor<span<int, 5>, std::array<int, 4>&>");
EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == arr.data());
span<const int, 0> cs{arr}; #if !defined(_MSC_VER) || (_MSC_VER > 1942) || (__cplusplus >= 201703L)
EXPECT_TRUE(cs.size() == 0); // Fails on "Visual Studio 16 2019/Visual Studio 17 2022, windows-2019/2022, Debug/Release, 14".
EXPECT_TRUE(cs.data() == arr.data()); static_assert(!ConversionCompilesFor<span<int>, std::array<int, 4>>,
} "!ConversionCompilesFor<span<int>, std::array<int, 4>>");
{
span<int, 5> s{arr};
}
{
auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; };
auto take_a_span = [](span<int> s) { static_cast<void>(s); };
// try to take a temporary std::array
take_a_span(get_an_array());
}
#endif #endif
{ {
auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; }; auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; };
auto take_a_span = [](span<const int> s) { static_cast<void>(s); }; auto take_a_span = [](span<const int>) {};
// try to take a temporary std::array // try to take a temporary std::array
static_assert(ConversionCompilesFor<span<const int>, std::array<int, 4>>,
"ConversionCompilesFor<span<const int>, std::array<int, 4>>");
take_a_span(get_an_array()); take_a_span(get_an_array());
} }
} }
@ -493,23 +452,12 @@ TEST(span_test, from_const_std_array_constructor)
EXPECT_TRUE(s.data() == ao_arr.data()); EXPECT_TRUE(s.data() == ao_arr.data());
} }
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!CtorCompilesFor<span<const int, 2>, std::array<int, 4>&>,
{ "!CtorCompilesFor<span<const int, 2>, std::array<int, 4>&>");
span<const int, 2> s{arr}; static_assert(!CtorCompilesFor<span<const int, 0>, std::array<int, 4>&>,
EXPECT_TRUE(s.size() == 2); "!CtorCompilesFor<span<const int, 0>, std::array<int, 4>&>");
EXPECT_TRUE(s.data() == arr.data()); static_assert(!CtorCompilesFor<span<int, 5>, std::array<int, 4>&>,
} "!CtorCompilesFor<span<int, 5>, std::array<int, 4>&>");
{
span<const int, 0> s{arr};
EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == arr.data());
}
{
span<const int, 5> s{arr};
}
#endif
{ {
auto get_an_array = []() -> const std::array<int, 4> { return {1, 2, 3, 4}; }; auto get_an_array = []() -> const std::array<int, 4> { return {1, 2, 3, 4}; };
@ -535,27 +483,14 @@ TEST(span_test, from_std_array_const_constructor)
EXPECT_TRUE(s.data() == arr.data()); EXPECT_TRUE(s.data() == arr.data());
} }
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!CtorCompilesFor<span<const int, 2>, const std::array<int, 4>&>,
{ "!CtorCompilesFor<span<const int, 2>, const std::array<int, 4>&>");
span<const int, 2> s{arr}; static_assert(!CtorCompilesFor<span<const int, 0>, const std::array<int, 4>&>,
EXPECT_TRUE(s.size() == 2); "!CtorCompilesFor<span<const int, 0>, const std::array<int, 4>&>");
EXPECT_TRUE(s.data() == arr.data()); static_assert(!CtorCompilesFor<span<const int, 5>, const std::array<int, 4>&>,
} "!CtorCompilesFor<span<const int, 5>, const std::array<int, 4>&>");
static_assert(!CtorCompilesFor<span<int, 5>, const std::array<int, 4>&>,
{ "!CtorCompilesFor<span<int, 5>, const std::array<int, 4>&>");
span<const int, 0> s{arr};
EXPECT_TRUE(s.size() == 0);
EXPECT_TRUE(s.data() == arr.data());
}
{
span<const int, 5> s{arr};
}
{
span<int, 4> s{arr};
}
#endif
} }
TEST(span_test, from_container_constructor) TEST(span_test, from_container_constructor)
@ -577,32 +512,28 @@ TEST(span_test, from_container_constructor)
const std::string cstr = "hello"; const std::string cstr = "hello";
{ {
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(CtorCompilesFor<span<char>, std::string&> == (__cplusplus >= 201703L),
span<char> s{str}; "CtorCompilesFor<span<char>, std::string&> == (__cplusplus >= 201703L)");
EXPECT_TRUE(s.size() == str.size());
EXPECT_TRUE(s.data() == str.data()));
#endif
span<const char> cs{str}; span<const char> cs{str};
EXPECT_TRUE(cs.size() == str.size()); EXPECT_TRUE(cs.size() == str.size());
EXPECT_TRUE(cs.data() == str.data()); EXPECT_TRUE(cs.data() == str.data());
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!CtorCompilesFor<span<char>, const std::string&>,
span<char> s{cstr}; "!CtorCompilesFor<span<char>, const std::string&>");
#endif
span<const char> cs{cstr}; span<const char> cs{cstr};
EXPECT_TRUE(cs.size() == cstr.size()); EXPECT_TRUE(cs.size() == cstr.size());
EXPECT_TRUE(cs.data() == cstr.data()); EXPECT_TRUE(cs.data() == cstr.data());
} }
{ #if !defined(_MSC_VER) || (_MSC_VER > 1942) || (__cplusplus >= 201703L)
#ifdef CONFIRM_COMPILATION_ERRORS // Fails on "Visual Studio 16 2019/Visual Studio 17 2022, windows-2019/2022, Debug/Release, 14".
auto get_temp_vector = []() -> std::vector<int> { return {}; }; static_assert(!ConversionCompilesFor<span<int>, std::vector<int>>,
auto use_span = [](span<int> s) { static_cast<void>(s); }; "!ConversionCompilesFor<span<int>, std::vector<int>>");
use_span(get_temp_vector()); #endif // !defined(_MSC_VER) || (_MSC_VER > 1942) || (__cplusplus >= 201703L)
#endif
}
{ {
auto get_temp_vector = []() -> std::vector<int> { return {}; }; auto get_temp_vector = []() -> std::vector<int> { return {}; };
@ -610,13 +541,8 @@ TEST(span_test, from_container_constructor)
use_span(get_temp_vector()); use_span(get_temp_vector());
} }
{ static_assert(!ConversionCompilesFor<span<char>, std::string>,
#ifdef CONFIRM_COMPILATION_ERRORS "!ConversionCompilesFor<span<char>, std::string>");
auto get_temp_string = []() -> std::string { return {}; };
auto use_span = [](span<char> s) { static_cast<void>(s); };
use_span(get_temp_string());
#endif
}
{ {
auto get_temp_string = []() -> std::string { return {}; }; auto get_temp_string = []() -> std::string { return {}; };
@ -624,13 +550,10 @@ TEST(span_test, from_container_constructor)
use_span(get_temp_string()); use_span(get_temp_string());
} }
{ static_assert(!ConversionCompilesFor<span<const char>, const std::vector<int>>,
#ifdef CONFIRM_COMPILATION_ERRORS "!ConversionCompilesFor<span<const char>, const std::vector<int>>");
auto get_temp_vector = []() -> const std::vector<int> { return {}; }; static_assert(!ConversionCompilesFor<span<char>, const std::string>,
auto use_span = [](span<const char> s) { static_cast<void>(s); }; "!ConversionCompilesFor<span<char>, const std::string>");
use_span(get_temp_vector());
#endif
}
{ {
auto get_temp_string = []() -> const std::string { return {}; }; auto get_temp_string = []() -> const std::string { return {}; };
@ -638,12 +561,8 @@ TEST(span_test, from_container_constructor)
use_span(get_temp_string()); use_span(get_temp_string());
} }
{ static_assert(!CtorCompilesFor<span<int>, std::map<int, int>&>,
#ifdef CONFIRM_COMPILATION_ERRORS "!CtorCompilesFor<span<int>, std::map<int, int>&>");
std::map<int, int> m;
span<int> s{m};
#endif
}
} }
TEST(span_test, from_convertible_span_constructor) TEST(span_test, from_convertible_span_constructor)
@ -695,52 +614,20 @@ TEST(span_test, from_convertible_span_constructor)
EXPECT_DEATH(T{avd}, expected); EXPECT_DEATH(T{avd}, expected);
} }
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!ConversionCompilesFor<span<const DerivedClass, 2>, span<DerivedClass>&>,
{ "!ConversionCompilesFor<span<const DerivedClass, 2>, span<DerivedClass>&>");
std::array<DerivedClass, 2> arr{}; static_assert(!ConversionCompilesFor<span<const DerivedClass, 1>, span<DerivedClass, 2>&>,
span<DerivedClass> avd{arr}; "!ConversionCompilesFor<span<const DerivedClass, 1>, span<DerivedClass, 2>&>");
span<const DerivedClass, 2> avcd = avd; static_assert(!ConversionCompilesFor<span<const DerivedClass, 3>, span<DerivedClass, 2>&>,
static_cast<void>(avcd); "!ConversionCompilesFor<span<const DerivedClass, 3>, span<DerivedClass, 2>&>");
} static_assert(!ConversionCompilesFor<span<BaseClass, 3>, span<DerivedClass>&>,
"!ConversionCompilesFor<span<BaseClass, 3>, span<DerivedClass>&>");
{ static_assert(!ConversionCompilesFor<span<unsigned int>, span<int>&>,
std::array<DerivedClass, 2> arr{}; "!ConversionCompilesFor<span<unsigned int>, span<int>&>");
span<DerivedClass, 2> avd{arr}; static_assert(!ConversionCompilesFor<span<const unsigned int>, span<int>&>,
span<const DerivedClass, 1> avcd = avd; "!ConversionCompilesFor<span<const unsigned int>, span<int>&>");
static_cast<void>(avcd); static_assert(!ConversionCompilesFor<span<short>, span<int>&>,
} "!ConversionCompilesFor<span<short>, span<int>&>");
{
std::array<DerivedClass, 2> arr{};
span<DerivedClass, 2> avd{arr};
span<const DerivedClass, 3> avcd = avd;
static_cast<void>(avcd);
}
{
span<DerivedClass> avd;
span<BaseClass> avb = avd;
static_cast<void>(avb);
}
{
span<int> s;
span<unsigned int> s2 = s;
static_cast<void>(s2);
}
{
span<int> s;
span<const unsigned int> s2 = s;
static_cast<void>(s2);
}
{
span<int> s;
span<short> s2 = s;
static_cast<void>(s2);
}
#endif
} }
TEST(span_test, copy_move_and_assignment) TEST(span_test, copy_move_and_assignment)
@ -800,10 +687,9 @@ TEST(span_test, first)
{ {
span<int, 5> av = arr; span<int, 5> av = arr;
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
EXPECT_TRUE(av.first<6>().size() == 6); (void) av.first<6>();
EXPECT_TRUE(av.first<-1>().size() == -1);
#endif #endif
EXPECT_DEATH(av.first(6).size(), expected); EXPECT_DEATH(av.first(6), expected);
} }
{ {
@ -844,9 +730,9 @@ TEST(span_test, last)
{ {
span<int, 5> av = arr; span<int, 5> av = arr;
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
EXPECT_TRUE(av.last<6>().size() == 6); (void) av.last<6>();
#endif #endif
EXPECT_DEATH(av.last(6).size(), expected); EXPECT_DEATH(av.last(6), expected);
} }
{ {
@ -871,6 +757,9 @@ TEST(span_test, subspan)
EXPECT_TRUE((av.subspan<2, 2>().size()) == 2); EXPECT_TRUE((av.subspan<2, 2>().size()) == 2);
EXPECT_TRUE(decltype(av.subspan<2, 2>())::extent == 2); EXPECT_TRUE(decltype(av.subspan<2, 2>())::extent == 2);
EXPECT_TRUE(av.subspan(2, 2).size() == 2); EXPECT_TRUE(av.subspan(2, 2).size() == 2);
EXPECT_TRUE((av.subspan<2, 3>().size()) == 3);
EXPECT_TRUE(decltype(av.subspan<2, 3>())::extent == 3);
EXPECT_TRUE(av.subspan(2, 3).size() == 3); EXPECT_TRUE(av.subspan(2, 3).size() == 3);
} }
@ -887,8 +776,12 @@ TEST(span_test, subspan)
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(), expected); #ifdef CONFIRM_COMPILATION_ERRORS
EXPECT_DEATH(av.subspan(1, 5).size(), expected); (void) av.subspan<0, 6>();
(void) av.subspan<1, 5>();
#endif
EXPECT_DEATH(av.subspan(0, 6), expected);
EXPECT_DEATH(av.subspan(1, 5), expected);
} }
{ {
@ -896,14 +789,22 @@ TEST(span_test, subspan)
EXPECT_TRUE((av.subspan<4, 0>().size()) == 0); EXPECT_TRUE((av.subspan<4, 0>().size()) == 0);
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(decltype(av.subspan<5, 0>())::extent == 0);
EXPECT_TRUE(av.subspan(5, 0).size() == 0); EXPECT_TRUE(av.subspan(5, 0).size() == 0);
EXPECT_DEATH(av.subspan(6, 0).size(), expected);
#ifdef CONFIRM_COMPILATION_ERRORS
(void) av.subspan<6, 0>();
#endif
EXPECT_DEATH(av.subspan(6, 0), expected);
} }
{ {
span<int, 5> av = arr; span<int, 5> av = arr;
EXPECT_TRUE(av.subspan<1>().size() == 4); EXPECT_TRUE(av.subspan<1>().size() == 4);
EXPECT_TRUE(decltype(av.subspan<1>())::extent == 4); EXPECT_TRUE(decltype(av.subspan<1>())::extent == 4);
EXPECT_TRUE(av.subspan(1).size() == 4);
} }
{ {
@ -911,35 +812,58 @@ TEST(span_test, subspan)
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()), expected);
EXPECT_DEATH((av.subspan<1, 0>()), expected);
EXPECT_DEATH((av.subspan(1, 0)), expected);
} }
{ {
span<int> av; span<int> av;
EXPECT_TRUE((av.subspan<0>().size()) == 0);
EXPECT_TRUE(decltype(av.subspan<0>())::extent == dynamic_extent);
EXPECT_TRUE(av.subspan(0).size() == 0); EXPECT_TRUE(av.subspan(0).size() == 0);
EXPECT_DEATH(av.subspan(1).size(), expected);
EXPECT_DEATH(av.subspan<1>(), expected);
EXPECT_TRUE(decltype(av.subspan<1>())::extent == dynamic_extent);
EXPECT_DEATH(av.subspan(1), expected);
} }
{ {
span<int> av = arr; span<int> av = arr;
EXPECT_TRUE(av.subspan(0).size() == 5); EXPECT_TRUE(av.subspan(0).size() == 5);
EXPECT_TRUE(av.subspan<0>().size() == 5);
EXPECT_TRUE(av.subspan(1).size() == 4); 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<4>().size() == 1);
EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_TRUE(av.subspan(5).size() == 0);
EXPECT_DEATH(av.subspan(6).size(), expected); EXPECT_TRUE(av.subspan<5>().size() == 0);
EXPECT_DEATH(av.subspan(6), expected);
EXPECT_DEATH(av.subspan<6>(), 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);
const auto av3 = av.subspan<1>();
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av3[i] == static_cast<int>(i) + 2);
} }
{ {
span<int, 5> av = arr; span<int, 5> av = arr;
EXPECT_TRUE(av.subspan(0).size() == 5); EXPECT_TRUE(av.subspan(0).size() == 5);
EXPECT_TRUE(av.subspan<0>().size() == 5);
EXPECT_TRUE(av.subspan(1).size() == 4); 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<4>().size() == 1);
EXPECT_TRUE(av.subspan(5).size() == 0); EXPECT_TRUE(av.subspan(5).size() == 0);
EXPECT_DEATH(av.subspan(6).size(), expected); EXPECT_TRUE(av.subspan<5>().size() == 0);
EXPECT_DEATH(av.subspan(6), expected);
#ifdef CONFIRM_COMPILATION_ERRORS
EXPECT_DEATH(av.subspan<6>(), expected);
#endif
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);
const auto av3 = av.subspan<1>();
for (std::size_t i = 0; i < 4; ++i) EXPECT_TRUE(av3[i] == static_cast<int>(i) + 2);
} }
} }
@ -1114,9 +1038,21 @@ TEST(span_test, rbegin_rend)
} }
} }
template <typename U, typename = void>
static constexpr bool AsWritableBytesCompilesFor = false;
template <typename U>
static constexpr bool
AsWritableBytesCompilesFor<U, void_t<decltype(as_writable_bytes(std::declval<U>()))>> = true;
TEST(span_test, as_bytes) TEST(span_test, as_bytes)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
static_assert(AsWritableBytesCompilesFor<span<int>>, "AsWriteableBytesCompilesFor<span<int>>");
// you should not be able to get writeable bytes for const objects
static_assert(!AsWritableBytesCompilesFor<span<const int>>,
"!AsWriteableBytesCompilesFor<span<const int>>");
{ {
const span<const int> s = a; const span<const int> s = a;
EXPECT_TRUE(s.size() == 4); EXPECT_TRUE(s.size() == 4);
@ -1147,17 +1083,6 @@ TEST(span_test, as_writable_bytes)
{ {
int a[] = {1, 2, 3, 4}; int a[] = {1, 2, 3, 4};
{
#ifdef CONFIRM_COMPILATION_ERRORS
// you should not be able to get writeable bytes for const objects
span<const int> s = a;
EXPECT_TRUE(s.size() == 4);
span<const byte> bs = as_writable_bytes(s);
EXPECT_TRUE(static_cast<void*>(bs.data()) == static_cast<void*>(s.data()));
EXPECT_TRUE(bs.size() == s.size_bytes());
#endif
}
{ {
span<int> s; span<int> s;
const auto bs = as_writable_bytes(s); const auto bs = as_writable_bytes(s);
@ -1197,30 +1122,15 @@ TEST(span_test, fixed_size_conversions)
static_cast<void>(s); static_cast<void>(s);
} }
// initialization or assignment to static span that REDUCES size is NOT ok // initialization or assignment to static span that REDUCES size is NOT ok
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!ConversionCompilesFor<span<int, 2>, int[4]>,
{ "!ConversionCompilesFor<span<int, 2>, int[4]>");
span<int, 2> s = arr; static_assert(!ConversionCompilesFor<span<int, 2>, span<int, 4>>,
} "!ConversionCompilesFor<span<int, 2>, span<int, 4>>");
{
span<int, 2> s2 = s4;
static_cast<void>(s2);
}
#endif
// even when done dynamically // even when done dynamically
{ static_assert(!ConversionCompilesFor<span<int, 2>, span<int>>,
/* "!ConversionCompilesFor<span<int, 2>, span<int>>");
// this now results in a compile-time error, rather than runtime.
// There is no suitable conversion from dynamic span to fixed span.
span<int> s = arr;
auto f = [&]() {
const span<int, 2> s2 = s;
static_cast<void>(s2);
};
EXPECT_DEATH(f(), expected);
*/
}
// but doing so explicitly is ok // but doing so explicitly is ok
@ -1234,32 +1144,24 @@ TEST(span_test, fixed_size_conversions)
static_cast<void>(s1); static_cast<void>(s1);
} }
/*
// this is not a legal operation in std::span, so we are no longer supporting it // this is not a legal operation in std::span, so we are no longer supporting it
// conversion from span<int, 4> to span<int, dynamic_extent> via call to `first` // conversion from span<int, 4> to span<int, dynamic_extent> via call to `first`
// then convert from span<int, dynamic_extent> to span<int, 1> // then convert from span<int, dynamic_extent> to span<int, 1>
// The dynamic to fixed extents are not supported in the standard // The dynamic to fixed extents are not supported in the standard
// to make this work, span<int, 1> would need to be span<int>. // to make this work, span<int, 1> would need to be span<int>.
{ static_assert(!ConversionCompilesFor<span<int, 1>, span<int>>,
"!ConversionCompilesFor<span<int, 1>, span<int>>");
// NB: implicit conversion to span<int,1> from span<int>
span<int, 1> s1 = s4.first(1);
static_cast<void>(s1);
}
*/
// initialization or assignment to static span that requires size INCREASE is not ok. // initialization or assignment to static span that requires size INCREASE is not ok.
int arr2[2] = {1, 2}; int arr2[2] = {1, 2};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!ConversionCompilesFor<span<int, 4>, int[2]>,
{ "!ConversionCompilesFor<span<int, 4>, int[2]>");
span<int, 4> s3 = arr2; static_assert(!ConversionCompilesFor<span<int, 2>, int[2]>,
} "!ConversionCompilesFor<span<int, 2>, int[2]>");
{ static_assert(!ConversionCompilesFor<span<int, 4>, span<int, 2>>,
span<int, 2> s2 = arr2; "!ConversionCompilesFor<span<int, 4>, span<int, 2>>");
span<int, 4> s4a = s2;
}
#endif
{ {
auto f = [&]() { auto f = [&]() {
const span<int, 4> _s4{arr2, 2}; const span<int, 4> _s4{arr2, 2};
@ -1268,16 +1170,11 @@ TEST(span_test, fixed_size_conversions)
EXPECT_DEATH(f(), expected); EXPECT_DEATH(f(), expected);
} }
/*
// This no longer compiles. There is no suitable conversion from dynamic span to a fixed size // This no longer compiles. There is no suitable conversion from dynamic span to a fixed size
span. // 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 = [&]() { static_assert(!ConversionCompilesFor<span<int, 4>, span<int>>,
const span<int, 4> _s4 = av; "!ConversionCompilesFor<span<int, 4>, span<int>>");
static_cast<void>(_s4);
};
EXPECT_DEATH(f(), expected);
*/
} }
TEST(span_test, interop_with_std_regex) TEST(span_test, interop_with_std_regex)
@ -1376,8 +1273,6 @@ TEST(span_test, msvc_compile_error_PR1100)
int arr[]{1, 7, 2, 9}; int arr[]{1, 7, 2, 9};
gsl::span sp{arr, std::size(arr)}; gsl::span sp{arr, std::size(arr)};
std::ranges::sort(sp); std::ranges::sort(sp);
for (const auto& e : sp) { for (const auto& e : sp) { (void) e; }
(void)e;
}
} }
#endif // defined(__cpp_lib_span) && defined(__cpp_lib_ranges) #endif // defined(__cpp_lib_span) && defined(__cpp_lib_ranges)

View File

@ -17,10 +17,19 @@
#include <gsl/pointers> // for not_null, operator<, operator<=, operator> #include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <type_traits> // for declval
#include "deathTestCommon.h" #include "deathTestCommon.h"
using namespace gsl; using namespace gsl;
#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l
// stand-in for a user-defined ref-counted class // stand-in for a user-defined ref-counted class
template <typename T> template <typename T>
struct RefCounted struct RefCounted
@ -53,21 +62,39 @@ GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
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; }
int* return_pointer() { return nullptr; } int* return_pointer() { return nullptr; }
#ifdef CONFIRM_COMPILATION_ERRORS
const int* return_pointer_const() { return nullptr; }
#endif
} // namespace } // namespace
template <typename U, typename = void>
static constexpr bool CtorCompilesFor_A = false;
template <typename U>
static constexpr bool
CtorCompilesFor_A<U, void_t<decltype(gsl::strict_not_null<void*>{std::declval<U>()})>> = true;
template <typename U, int N, typename = void>
static constexpr bool CtorCompilesFor_B = false;
template <typename U, int N>
static constexpr bool CtorCompilesFor_B<U, N, void_t<decltype(gsl::strict_not_null<U>{N})>> = true;
template <typename U, typename = void>
static constexpr bool DefaultCtorCompilesFor = false;
template <typename U>
static constexpr bool DefaultCtorCompilesFor<U, void_t<decltype(gsl::strict_not_null<U>{})>> = true;
template <typename U, typename = void>
static constexpr bool CtorCompilesFor_C = false;
template <typename U>
static constexpr bool CtorCompilesFor_C<
U, void_t<decltype(gsl::strict_not_null<U*>{std::declval<std::unique_ptr<U>>()})>> = true;
TEST(strict_notnull_tests, TestStrictNotNullConstructors) TEST(strict_notnull_tests, TestStrictNotNullConstructors)
{ {
{ {
static_assert(CtorCompilesFor_A<void*>, "CtorCompilesFor_A<void*>");
static_assert(!CtorCompilesFor_A<std::nullptr_t>, "!CtorCompilesFor_A<std::nullptr_t>");
static_assert(!CtorCompilesFor_B<void*, 0>, "!CtorCompilesFor_B<void*, 0>");
static_assert(!DefaultCtorCompilesFor<void*>, "!DefaultCtorCompilesFor<void*>");
static_assert(!CtorCompilesFor_C<int>, "CtorCompilesFor_C<int>");
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
strict_not_null<int*> p = nullptr; // yay...does not compile!
strict_not_null<std::vector<char>*> p1 = 0; // yay...does not compile!
strict_not_null<int*> p2; // yay...does not compile!
std::unique_ptr<int> up = std::make_unique<int>(120);
strict_not_null<int*> p3 = up;
// Forbid non-nullptr assignable types // Forbid non-nullptr assignable types
strict_not_null<std::vector<int>> f(std::vector<int>{1}); strict_not_null<std::vector<int>> f(std::vector<int>{1});
strict_not_null<int> z(10); strict_not_null<int> z(10);
@ -162,6 +189,26 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructors)
} }
} }
template <typename U, typename = void>
static constexpr bool StrictHelperCompilesFor = false;
template <typename U>
static constexpr bool
StrictHelperCompilesFor<U, void_t<decltype(strict_helper(std::declval<U>()))>> = true;
template <typename U, typename = void>
static constexpr bool StrictHelperConstCompilesFor = false;
template <typename U>
static constexpr bool
StrictHelperConstCompilesFor<U, void_t<decltype(strict_helper_const(std::declval<U>()))>> =
true;
template <typename U, typename = void>
static constexpr bool HelperCompilesFor = false;
template <typename U>
static constexpr bool HelperCompilesFor<U, void_t<decltype(helper(std::declval<U>()))>> = true;
TEST(strict_notnull_tests, TestStrictNotNull) TEST(strict_notnull_tests, TestStrictNotNull)
{ {
{ {
@ -170,14 +217,15 @@ TEST(strict_notnull_tests, TestStrictNotNull)
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
strict_not_null<int*> snn = &x; strict_not_null<int*> snn = &x;
strict_helper(&x);
strict_helper_const(&x);
strict_helper(return_pointer());
strict_helper_const(return_pointer_const());
#endif #endif
static_assert(!StrictHelperCompilesFor<int*>, "!StrictHelperCompilesFor<int*>");
static_assert(!StrictHelperConstCompilesFor<int*>,
"!StrictHelperCompilesFor<int*>");
const strict_not_null<int*> snn1{&x}; const strict_not_null<int*> snn1{&x};
static_assert(StrictHelperCompilesFor<const strict_not_null<int*>>,
"StrictHelperCompilesFor<const strict_not_null<int*>>");
helper(snn1); helper(snn1);
helper_const(snn1); helper_const(snn1);
@ -190,17 +238,17 @@ TEST(strict_notnull_tests, TestStrictNotNull)
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
strict_not_null<int*> snn = &x; strict_not_null<int*> snn = &x;
strict_helper(&x);
strict_helper_const(&x);
strict_helper(return_pointer());
strict_helper_const(return_pointer_const());
#endif #endif
static_assert(!StrictHelperCompilesFor<const int*>, "!StrictHelperFor<const int*>");
static_assert(!StrictHelperConstCompilesFor<const int*>,
"!StrictHelperCompilesFor<const int*>");
const strict_not_null<const int*> snn1{&x}; const strict_not_null<const int*> snn1{&x};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!HelperCompilesFor<const strict_not_null<const int*>>,
helper(snn1); "!HelperCompilesFor<const strict_not_null<const int*>>");
#endif static_assert(StrictHelperConstCompilesFor<const strict_not_null<const int*>>,
"StrictHelperCompilesFor<const strict_not_null<const int*>>");
helper_const(snn1); helper_const(snn1);
EXPECT_TRUE(*snn1 == 42); EXPECT_TRUE(*snn1 == 42);
@ -227,9 +275,8 @@ TEST(strict_notnull_tests, TestStrictNotNull)
strict_not_null<const int*> snn1{&x}; strict_not_null<const int*> snn1{&x};
const strict_not_null<const int*> snn2{&x}; const strict_not_null<const int*> snn2{&x};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!StrictHelperCompilesFor<strict_not_null<const int*>>,
strict_helper(snn1); "!StrictHelperCompilesFor<strict_not_null<const int*>>");
#endif
strict_helper_const(snn1); strict_helper_const(snn1);
strict_helper_const(snn2); strict_helper_const(snn2);
@ -261,9 +308,8 @@ TEST(strict_notnull_tests, TestStrictNotNull)
const not_null<const int*> nn1 = snn; const not_null<const int*> nn1 = snn;
const not_null<const int*> nn2{snn}; const not_null<const int*> nn2{snn};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
helper(snn); "!HelperCompilesFor<strict_not_null<const int*>>");
#endif
helper_const(snn); helper_const(snn);
EXPECT_TRUE(snn == nn1); EXPECT_TRUE(snn == nn1);
@ -303,9 +349,8 @@ TEST(strict_notnull_tests, TestStrictNotNull)
const strict_not_null<const int*> snn1{nn}; const strict_not_null<const int*> snn1{nn};
const strict_not_null<const int*> snn2{nn}; const strict_not_null<const int*> snn2{nn};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!StrictHelperCompilesFor<not_null<const int*>>,
strict_helper(nn); "!StrictHelperCompilesFor<not_null<const int*>>");
#endif
strict_helper_const(nn); strict_helper_const(nn);
EXPECT_TRUE(snn1 == nn); EXPECT_TRUE(snn1 == nn);
@ -319,12 +364,6 @@ TEST(strict_notnull_tests, TestStrictNotNull)
EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2)); EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2));
EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn)); EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
} }
#ifdef CONFIRM_COMPILATION_ERRORS
{
strict_not_null<int*> p{nullptr};
}
#endif
} }
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
@ -351,9 +390,8 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
const int i = 42; const int i = 42;
strict_not_null x{&i}; strict_not_null x{&i};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
helper(strict_not_null{&i}); "!HelperCompilesFor<strict_not_null<const int*>>");
#endif
helper_const(strict_not_null{&i}); helper_const(strict_not_null{&i});
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);
@ -375,9 +413,8 @@ TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
const int* p = &i; const int* p = &i;
strict_not_null x{p}; strict_not_null x{p};
#ifdef CONFIRM_COMPILATION_ERRORS static_assert(!HelperCompilesFor<strict_not_null<const int*>>,
helper(strict_not_null{p}); "!HelperCompilesFor<strict_not_null<const int*>>");
#endif
helper_const(strict_not_null{p}); helper_const(strict_not_null{p});
EXPECT_TRUE(*x == 42); EXPECT_TRUE(*x == 42);