Skip to content

Commit

Permalink
More checks for non-compilable code, plus fix for span (#1180)
Browse files Browse the repository at this point in the history
  • Loading branch information
beinhaerter authored Jan 4, 2025
1 parent c832885 commit 1cdb8d2
Show file tree
Hide file tree
Showing 8 changed files with 439 additions and 412 deletions.
7 changes: 7 additions & 0 deletions include/gsl/span
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,8 @@ public:
template <std::size_t Count>
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());
return span<element_type, Count>{data(), Count};
}
Expand All @@ -592,6 +594,8 @@ public:
// clang-format on
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());
return span<element_type, Count>{data() + (size() - Count), Count};
}
Expand All @@ -603,6 +607,9 @@ public:
constexpr auto subspan() const noexcept ->
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)));
using type =
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
Expand Down
2 changes: 1 addition & 1 deletion tests/algorithm_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ TEST(algorithm_tests, incompatible_type)
span<int> src_span_dyn(src);
span<int, 4> src_span_static(src);
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
copy(src_span_dyn, dst_span_dyn);
Expand Down
6 changes: 2 additions & 4 deletions tests/byte_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ TEST(byte_tests, construction)
to_byte(char{});
to_byte(3);
to_byte(3u);
to_byte<-1>();
to_byte<256u>();
#endif
}

Expand Down Expand Up @@ -174,7 +176,3 @@ static constexpr bool
static_assert(!ToIntegerCompilesFor<float>, "!ToIntegerCompilesFor<float>");

} // namespace

#ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static);
#endif
156 changes: 119 additions & 37 deletions tests/notnull_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,25 @@

#include <gsl/pointers> // for not_null, operator<, operator<=, operator>

#include <algorithm> // for addressof
#include <cstdint> // for uint16_t
#include <memory> // for shared_ptr, make_shared, operator<, opera...
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
#include <string> // for basic_string, operator==, string, operator<<
#include <typeinfo> // for type_info
#include <variant> // for variant, monostate, get
#include <algorithm> // for addressof
#include <cstdint> // for uint16_t
#include <memory> // for shared_ptr, make_shared, operator<, opera...
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
#include <string> // for basic_string, operator==, string, operator<<
#include <type_traits> // for declval
#include <typeinfo> // for type_info
#include <variant> // for variant, monostate, get

#include "deathTestCommon.h"
using namespace gsl;

#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l

struct MyBase
{
};
Expand Down Expand Up @@ -141,16 +149,39 @@ bool helper_const(not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; }
} // 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)
{
{
#ifdef CONFIRM_COMPILATION_ERRORS
not_null<int*> p = nullptr; // yay...does not compile!
not_null<std::vector<char>*> p1 = 0; // yay...does not compile!
not_null<int*> p2; // yay...does not compile!
std::unique_ptr<int> up = std::make_unique<int>(120);
not_null<int*> p3 = up;
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
// Forbid non-nullptr assignable types
not_null<std::vector<int>> f(std::vector<int>{1});
not_null<int> z(10);
Expand Down Expand Up @@ -276,6 +307,27 @@ TEST(notnull_tests, TestNotNullostream)
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)
{
MyBase base;
Expand All @@ -288,15 +340,30 @@ TEST(notnull_tests, TestNotNullCasting)
q = p; // allowed with heterogeneous copy ctor
EXPECT_TRUE(q == p);

#ifdef CONFIRM_COMPILATION_ERRORS
q = u; // no viable conversion possible between MyBase* and Unrelated*
p = q; // not possible to implicitly convert MyBase* to MyDerived*
static_assert(AssignmentCompilesFor<MyBase, MyDerived>,
"AssignmentCompilesFor<MyBase, 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()));
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)
Expand Down Expand Up @@ -438,6 +505,18 @@ TEST(notnull_tests, TestNotNullCustomPtrComparison)

#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)
{
{
Expand All @@ -454,9 +533,9 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
const int i = 42;

not_null x{&i};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(not_null{&i});
#endif
static_assert(TypeDeductionHelperCompilesFor<int*>, "TypeDeductionHelperCompilesFor<int*>");
static_assert(!TypeDeductionHelperCompilesFor<const int*>,
"!TypeDeductionHelperCompilesFor<const int*>");
helper_const(not_null{&i});

EXPECT_TRUE(*x == 42);
Expand All @@ -478,9 +557,6 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
const int* p = &i;

not_null x{p};
#ifdef CONFIRM_COMPILATION_ERRORS
helper(not_null{p});
#endif
helper_const(not_null{p});

EXPECT_TRUE(*x == 42);
Expand Down Expand Up @@ -515,12 +591,15 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
EXPECT_DEATH(helper_const(not_null{p}), expected);
}

#ifdef CONFIRM_COMPILATION_ERRORS
{
not_null x{nullptr};
helper(not_null{nullptr});
helper_const(not_null{nullptr});
}
static_assert(TypeDeductionCtorCompilesFor<void*>, "TypeDeductionCtorCompilesFor<void*>");
#if defined(_MSC_VER) && !defined(__clang__)
// Fails on gcc, clang, xcode, VS clang with
// "error : no type named 'type' in 'std::enable_if<false>'; 'enable_if' cannot be used to
// disable this declaration"
static_assert(!TypeDeductionCtorCompilesFor<std::nullptr_t>,
"!TypeDeductionCtorCompilesFor<std::nullptr_t>");
static_assert(!TypeDeductionHelperCompilesFor<std::nullptr_t>,
"!TypeDeductionHelperCompilesFor<std::nullptr_t>");
#endif
}

Expand All @@ -536,6 +615,11 @@ TEST(notnull_tests, TestVariantEmplace)
}
#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)
{
{
Expand All @@ -552,9 +636,8 @@ TEST(notnull_tests, TestMakeNotNull)
const int i = 42;

const auto x = make_not_null(&i);
#ifdef CONFIRM_COMPILATION_ERRORS
helper(make_not_null(&i));
#endif
static_assert(HelperCompilesFor<gsl::not_null<int*>>,
"HelperCompilesFor<gsl::not_null<int*>>");
helper_const(make_not_null(&i));

EXPECT_TRUE(*x == 42);
Expand All @@ -576,9 +659,8 @@ TEST(notnull_tests, TestMakeNotNull)
const int* p = &i;

const auto x = make_not_null(p);
#ifdef CONFIRM_COMPILATION_ERRORS
helper(make_not_null(p));
#endif
static_assert(!HelperCompilesFor<gsl::not_null<const int*>>,
"!HelperCompilesFor<gsl::not_null<const int*>>");
helper_const(make_not_null(p));

EXPECT_TRUE(*x == 42);
Expand Down
25 changes: 16 additions & 9 deletions tests/owner_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <gtest/gtest.h>

#include <gsl/pointers> // for owner
#include <type_traits> // for declval

using namespace gsl;

Expand All @@ -32,12 +33,18 @@ TEST(owner_tests, basic_test)
delete p;
}

TEST(owner_tests, check_pointer_constraint)
{
#ifdef CONFIRM_COMPILATION_ERRORS
{
owner<int> integerTest = 10;
owner<std::shared_ptr<int>> sharedPtrTest(new int(10));
}
#endif
}
#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 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>>");
33 changes: 17 additions & 16 deletions tests/pointers_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
#include <type_traits>
#include <utility>

#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l

namespace
{
// Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped.
Expand All @@ -22,6 +29,13 @@ struct NotMoveAssignableCustomPtr
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)
{
// taken from gh-1129:
Expand Down Expand Up @@ -69,22 +83,9 @@ TEST(pointers_test, swap)
EXPECT_TRUE(*a == 1);
EXPECT_TRUE(*b == 0);
}
}

#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>");
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");
}

} // namespace
Loading

0 comments on commit 1cdb8d2

Please sign in to comment.