Skip to content

Commit 1cdb8d2

Browse files
authored
More checks for non-compilable code, plus fix for span (#1180)
1 parent c832885 commit 1cdb8d2

File tree

8 files changed

+439
-412
lines changed

8 files changed

+439
-412
lines changed

include/gsl/span

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ public:
582582
template <std::size_t Count>
583583
constexpr span<element_type, Count> first() const noexcept
584584
{
585+
static_assert(Extent == dynamic_extent || Count <= Extent,
586+
"first() cannot extract more elements from a span than it contains.");
585587
Expects(Count <= size());
586588
return span<element_type, Count>{data(), Count};
587589
}
@@ -592,6 +594,8 @@ public:
592594
// clang-format on
593595
constexpr span<element_type, Count> last() const noexcept
594596
{
597+
static_assert(Extent == dynamic_extent || Count <= Extent,
598+
"last() cannot extract more elements from a span than it contains.");
595599
Expects(Count <= size());
596600
return span<element_type, Count>{data() + (size() - Count), Count};
597601
}
@@ -603,6 +607,9 @@ public:
603607
constexpr auto subspan() const noexcept ->
604608
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
605609
{
610+
static_assert(Extent == dynamic_extent || (Extent >= Offset && (Count == dynamic_extent ||
611+
Count <= Extent - Offset)),
612+
"subspan() cannot extract more elements from a span than it contains.");
606613
Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
607614
using type =
608615
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;

tests/algorithm_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ TEST(algorithm_tests, incompatible_type)
188188
span<int> src_span_dyn(src);
189189
span<int, 4> src_span_static(src);
190190
span<int*> dst_span_dyn(dst);
191-
span<int*, 4> dst_span_static(dst);
191+
span<int*, 4> dst_span_static(gsl::make_span(dst));
192192

193193
// every line should produce a compilation error
194194
copy(src_span_dyn, dst_span_dyn);

tests/byte_tests.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ TEST(byte_tests, construction)
6767
to_byte(char{});
6868
to_byte(3);
6969
to_byte(3u);
70+
to_byte<-1>();
71+
to_byte<256u>();
7072
#endif
7173
}
7274

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

176178
} // namespace
177-
178-
#ifdef CONFIRM_COMPILATION_ERRORS
179-
copy(src_span_static, dst_span_static);
180-
#endif

tests/notnull_tests.cpp

Lines changed: 119 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,25 @@
1818

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

21-
#include <algorithm> // for addressof
22-
#include <cstdint> // for uint16_t
23-
#include <memory> // for shared_ptr, make_shared, operator<, opera...
24-
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
25-
#include <string> // for basic_string, operator==, string, operator<<
26-
#include <typeinfo> // for type_info
27-
#include <variant> // for variant, monostate, get
21+
#include <algorithm> // for addressof
22+
#include <cstdint> // for uint16_t
23+
#include <memory> // for shared_ptr, make_shared, operator<, opera...
24+
#include <sstream> // for operator<<, ostringstream, basic_ostream:...
25+
#include <string> // for basic_string, operator==, string, operator<<
26+
#include <type_traits> // for declval
27+
#include <typeinfo> // for type_info
28+
#include <variant> // for variant, monostate, get
2829

2930
#include "deathTestCommon.h"
3031
using namespace gsl;
3132

33+
#if __cplusplus >= 201703l
34+
using std::void_t;
35+
#else // __cplusplus >= 201703l
36+
template <class...>
37+
using void_t = void;
38+
#endif // __cplusplus < 201703l
39+
3240
struct MyBase
3341
{
3442
};
@@ -141,16 +149,39 @@ bool helper_const(not_null<const int*> p) { return *p == 12; }
141149
int* return_pointer() { return nullptr; }
142150
} // namespace
143151

152+
template <typename U, typename = void>
153+
static constexpr bool CtorCompilesFor_A = false;
154+
template <typename U>
155+
static constexpr bool
156+
CtorCompilesFor_A<U, void_t<decltype(gsl::not_null<void*>{std::declval<U>()})>> = true;
157+
158+
template <typename U, int N, typename = void>
159+
static constexpr bool CtorCompilesFor_B = false;
160+
template <typename U, int N>
161+
static constexpr bool CtorCompilesFor_B<U, N, void_t<decltype(gsl::not_null<U>{N})>> = true;
162+
163+
template <typename U, typename = void>
164+
static constexpr bool DefaultCtorCompilesFor = false;
165+
template <typename U>
166+
static constexpr bool DefaultCtorCompilesFor<U, void_t<decltype(gsl::not_null<U>{})>> = true;
167+
168+
template <typename U, typename = void>
169+
static constexpr bool CtorCompilesFor_C = false;
170+
template <typename U>
171+
static constexpr bool
172+
CtorCompilesFor_C<U, void_t<decltype(gsl::not_null<U*>{std::declval<std::unique_ptr<U>>()})>> =
173+
true;
174+
144175
TEST(notnull_tests, TestNotNullConstructors)
145176
{
146177
{
147-
#ifdef CONFIRM_COMPILATION_ERRORS
148-
not_null<int*> p = nullptr; // yay...does not compile!
149-
not_null<std::vector<char>*> p1 = 0; // yay...does not compile!
150-
not_null<int*> p2; // yay...does not compile!
151-
std::unique_ptr<int> up = std::make_unique<int>(120);
152-
not_null<int*> p3 = up;
178+
static_assert(CtorCompilesFor_A<void*>, "CtorCompilesFor_A<void*>");
179+
static_assert(!CtorCompilesFor_A<std::nullptr_t>, "!CtorCompilesFor_A<std::nullptr_t>");
180+
static_assert(!CtorCompilesFor_B<void*, 0>, "!CtorCompilesFor_B<void*, 0>");
181+
static_assert(!DefaultCtorCompilesFor<void*>, "!DefaultCtorCompilesFor<void*>");
182+
static_assert(!CtorCompilesFor_C<int>, "CtorCompilesFor_C<int>");
153183

184+
#ifdef CONFIRM_COMPILATION_ERRORS
154185
// Forbid non-nullptr assignable types
155186
not_null<std::vector<int>> f(std::vector<int>{1});
156187
not_null<int> z(10);
@@ -276,6 +307,27 @@ TEST(notnull_tests, TestNotNullostream)
276307
ostream_helper<std::string>("string");
277308
}
278309

310+
template <typename U, typename V, typename = void>
311+
static constexpr bool AssignmentCompilesFor = false;
312+
template <typename U, typename V>
313+
static constexpr bool
314+
AssignmentCompilesFor<U, V,
315+
void_t<decltype(std::declval<gsl::not_null<U*>&>().operator=(
316+
std::declval<gsl::not_null<V*>&>()))>> = true;
317+
318+
template <typename U, typename V, typename = void>
319+
static constexpr bool SCastCompilesFor = false;
320+
template <typename U, typename V>
321+
static constexpr bool
322+
SCastCompilesFor<U, V, void_t<decltype(static_cast<U*>(std::declval<gsl::not_null<V*>&>()))>> =
323+
true;
324+
325+
template <typename U, typename V, typename = void>
326+
static constexpr bool RCastCompilesFor = false;
327+
template <typename U, typename V>
328+
static constexpr bool RCastCompilesFor<
329+
U, V, void_t<decltype(reinterpret_cast<U*>(std::declval<gsl::not_null<V*>&>()))>> = true;
330+
279331
TEST(notnull_tests, TestNotNullCasting)
280332
{
281333
MyBase base;
@@ -288,15 +340,30 @@ TEST(notnull_tests, TestNotNullCasting)
288340
q = p; // allowed with heterogeneous copy ctor
289341
EXPECT_TRUE(q == p);
290342

291-
#ifdef CONFIRM_COMPILATION_ERRORS
292-
q = u; // no viable conversion possible between MyBase* and Unrelated*
293-
p = q; // not possible to implicitly convert MyBase* to MyDerived*
343+
static_assert(AssignmentCompilesFor<MyBase, MyDerived>,
344+
"AssignmentCompilesFor<MyBase, MyDerived>");
345+
static_assert(!AssignmentCompilesFor<MyBase, Unrelated>,
346+
"!AssignmentCompilesFor<MyBase, Unrelated>");
347+
static_assert(!AssignmentCompilesFor<Unrelated, MyDerived>,
348+
"!AssignmentCompilesFor<Unrelated, MyDerived>");
349+
static_assert(!AssignmentCompilesFor<MyDerived, MyBase>,
350+
"!AssignmentCompilesFor<MyDerived, MyBase>");
351+
352+
static_assert(SCastCompilesFor<MyDerived, MyDerived>, "SCastCompilesFor<MyDerived, MyDerived>");
353+
static_assert(SCastCompilesFor<MyBase, MyDerived>, "SCastCompilesFor<MyBase, MyDerived>");
354+
static_assert(!SCastCompilesFor<MyDerived, MyBase>, "!SCastCompilesFor<MyDerived, MyBase>");
355+
static_assert(!SCastCompilesFor<Unrelated, MyDerived>,
356+
"!SCastCompilesFor<Unrelated, MyDerived>");
357+
static_assert(!RCastCompilesFor<MyDerived, MyDerived>,
358+
"!SCastCompilesFor<MyDerived, MyDerived>");
359+
static_assert(!RCastCompilesFor<Unrelated, MyDerived>,
360+
"!SCastCompilesFor<Unrelated, MyDerived>");
294361

295-
not_null<Unrelated*> r = p;
296-
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
297-
#endif
298362
not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get()));
299363
EXPECT_TRUE(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
364+
365+
(void) static_cast<MyDerived*>(p);
366+
(void) static_cast<MyBase*>(p);
300367
}
301368

302369
TEST(notnull_tests, TestNotNullAssignment)
@@ -438,6 +505,18 @@ TEST(notnull_tests, TestNotNullCustomPtrComparison)
438505

439506
#if defined(__cplusplus) && (__cplusplus >= 201703L)
440507

508+
template <typename U, typename = void>
509+
static constexpr bool TypeDeductionCtorCompilesFor = false;
510+
template <typename U>
511+
static constexpr bool
512+
TypeDeductionCtorCompilesFor<U, void_t<decltype(not_null{std::declval<U>()})>> = true;
513+
514+
template <typename U, typename = void>
515+
static constexpr bool TypeDeductionHelperCompilesFor = false;
516+
template <typename U>
517+
static constexpr bool
518+
TypeDeductionHelperCompilesFor<U, void_t<decltype(helper(not_null{std::declval<U>()}))>> = true;
519+
441520
TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
442521
{
443522
{
@@ -454,9 +533,9 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
454533
const int i = 42;
455534

456535
not_null x{&i};
457-
#ifdef CONFIRM_COMPILATION_ERRORS
458-
helper(not_null{&i});
459-
#endif
536+
static_assert(TypeDeductionHelperCompilesFor<int*>, "TypeDeductionHelperCompilesFor<int*>");
537+
static_assert(!TypeDeductionHelperCompilesFor<const int*>,
538+
"!TypeDeductionHelperCompilesFor<const int*>");
460539
helper_const(not_null{&i});
461540

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

480559
not_null x{p};
481-
#ifdef CONFIRM_COMPILATION_ERRORS
482-
helper(not_null{p});
483-
#endif
484560
helper_const(not_null{p});
485561

486562
EXPECT_TRUE(*x == 42);
@@ -515,12 +591,15 @@ TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
515591
EXPECT_DEATH(helper_const(not_null{p}), expected);
516592
}
517593

518-
#ifdef CONFIRM_COMPILATION_ERRORS
519-
{
520-
not_null x{nullptr};
521-
helper(not_null{nullptr});
522-
helper_const(not_null{nullptr});
523-
}
594+
static_assert(TypeDeductionCtorCompilesFor<void*>, "TypeDeductionCtorCompilesFor<void*>");
595+
#if defined(_MSC_VER) && !defined(__clang__)
596+
// Fails on gcc, clang, xcode, VS clang with
597+
// "error : no type named 'type' in 'std::enable_if<false>'; 'enable_if' cannot be used to
598+
// disable this declaration"
599+
static_assert(!TypeDeductionCtorCompilesFor<std::nullptr_t>,
600+
"!TypeDeductionCtorCompilesFor<std::nullptr_t>");
601+
static_assert(!TypeDeductionHelperCompilesFor<std::nullptr_t>,
602+
"!TypeDeductionHelperCompilesFor<std::nullptr_t>");
524603
#endif
525604
}
526605

@@ -536,6 +615,11 @@ TEST(notnull_tests, TestVariantEmplace)
536615
}
537616
#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
538617

618+
template <typename U, typename = void>
619+
static constexpr bool HelperCompilesFor = false;
620+
template <typename U>
621+
static constexpr bool HelperCompilesFor<U, void_t<decltype(helper(std::declval<U>()))>> = true;
622+
539623
TEST(notnull_tests, TestMakeNotNull)
540624
{
541625
{
@@ -552,9 +636,8 @@ TEST(notnull_tests, TestMakeNotNull)
552636
const int i = 42;
553637

554638
const auto x = make_not_null(&i);
555-
#ifdef CONFIRM_COMPILATION_ERRORS
556-
helper(make_not_null(&i));
557-
#endif
639+
static_assert(HelperCompilesFor<gsl::not_null<int*>>,
640+
"HelperCompilesFor<gsl::not_null<int*>>");
558641
helper_const(make_not_null(&i));
559642

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

578661
const auto x = make_not_null(p);
579-
#ifdef CONFIRM_COMPILATION_ERRORS
580-
helper(make_not_null(p));
581-
#endif
662+
static_assert(!HelperCompilesFor<gsl::not_null<const int*>>,
663+
"!HelperCompilesFor<gsl::not_null<const int*>>");
582664
helper_const(make_not_null(p));
583665

584666
EXPECT_TRUE(*x == 42);

tests/owner_tests.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <gtest/gtest.h>
1818

1919
#include <gsl/pointers> // for owner
20+
#include <type_traits> // for declval
2021

2122
using namespace gsl;
2223

@@ -32,12 +33,18 @@ TEST(owner_tests, basic_test)
3233
delete p;
3334
}
3435

35-
TEST(owner_tests, check_pointer_constraint)
36-
{
37-
#ifdef CONFIRM_COMPILATION_ERRORS
38-
{
39-
owner<int> integerTest = 10;
40-
owner<std::shared_ptr<int>> sharedPtrTest(new int(10));
41-
}
42-
#endif
43-
}
36+
#if __cplusplus >= 201703l
37+
using std::void_t;
38+
#else // __cplusplus >= 201703l
39+
template <class...>
40+
using void_t = void;
41+
#endif // __cplusplus < 201703l
42+
43+
template <typename U, typename = void>
44+
static constexpr bool OwnerCompilesFor = false;
45+
template <typename U>
46+
static constexpr bool OwnerCompilesFor<U, void_t<decltype(gsl::owner<U>{})>> =
47+
true;
48+
static_assert(OwnerCompilesFor<int*>, "OwnerCompilesFor<int*>");
49+
static_assert(!OwnerCompilesFor<int>, "!OwnerCompilesFor<int>");
50+
static_assert(!OwnerCompilesFor<std::shared_ptr<int>>, "!OwnerCompilesFor<std::shared_ptr<int>>");

tests/pointers_tests.cpp

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
#include <type_traits>
77
#include <utility>
88

9+
#if __cplusplus >= 201703l
10+
using std::void_t;
11+
#else // __cplusplus >= 201703l
12+
template <class...>
13+
using void_t = void;
14+
#endif // __cplusplus < 201703l
15+
916
namespace
1017
{
1118
// Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped.
@@ -22,6 +29,13 @@ struct NotMoveAssignableCustomPtr
2229
int dummy{}; // Without this clang warns, that NotMoveAssignableCustomPtr() is unneeded
2330
};
2431

32+
template <typename U, typename = void>
33+
static constexpr bool SwapCompilesFor = false;
34+
template <typename U>
35+
static constexpr bool
36+
SwapCompilesFor<U, void_t<decltype(gsl::swap<U>(std::declval<gsl::not_null<U>&>(),
37+
std::declval<gsl::not_null<U>&>()))>> = true;
38+
2539
TEST(pointers_test, swap)
2640
{
2741
// taken from gh-1129:
@@ -69,22 +83,9 @@ TEST(pointers_test, swap)
6983
EXPECT_TRUE(*a == 1);
7084
EXPECT_TRUE(*b == 0);
7185
}
72-
}
7386

74-
#if __cplusplus >= 201703l
75-
using std::void_t;
76-
#else // __cplusplus >= 201703l
77-
template <class...>
78-
using void_t = void;
79-
#endif // __cplusplus < 201703l
80-
81-
template <typename U, typename = void>
82-
static constexpr bool SwapCompilesFor = false;
83-
template <typename U>
84-
static constexpr bool
85-
SwapCompilesFor<U, void_t<decltype(gsl::swap<U>(std::declval<gsl::not_null<U>&>(),
86-
std::declval<gsl::not_null<U>&>()))>> = true;
87-
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
88-
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");
87+
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
88+
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");
89+
}
8990

9091
} // namespace

0 commit comments

Comments
 (0)