Dev/annagrin/remove explicit not null constructor (#743)

* Added c++17 test configurations for clang5.0 and clang6.0

* Removed explicit not_null constructor, sloppy_not_null, added strict_not_null

We added explicit not_null constructor in version 2.0.0.
It proved very difficult to switch to the new version for
large code bases that adopted previous versions of gsl,
due to not_null used extensively in the code. Still, using
explicit constructor is very benefitial for new code, since
it encorages better API design and make null checks intentional.

To resolve the issue, this change:
- removes explicit keyword from not_null constructor
- removes unneded sloppy_not_null type
- adds strict_not_null type to behave the same way as v2 not_null
- updates tests

* Removed explicit not_null constructor, sloppy_not_null, added strict_not_null

We added explicit not_null constructor in version 2.0.0.
It proved very difficult to switch to the new version for
large code bases that adopted previous versions of gsl,
due to not_null used extensively in the code. Still, using
explicit constructor is very benefitial for new code, since
it encorages better API design and make null checks intentional.

To resolve the issue, this change:
- removes explicit keyword from not_null constructor
- removes unneded sloppy_not_null type
- adds strict_not_null type to behave the same way as v2 not_null
- updates tests

* fixed build break for gcc7

* added more tests

* added more non-compiling tests

* Addressed PR comments and suppressed a code analysis warning

* Fixed test failure in not_null tests
This commit is contained in:
Anna Gringauze
2019-01-14 16:45:47 -08:00
committed by GitHub
parent 7a7d025ffa
commit 9ff6e19ea9
8 changed files with 384 additions and 291 deletions
+90 -32
View File
@@ -25,7 +25,7 @@
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_...
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
#include <algorithm> // for addressof
#include <memory> // for shared_ptr, make_shared, operator<, opera...
@@ -128,47 +128,105 @@ struct NonCopyableNonMovable
};
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool helper(not_null<int*> p)
{
return *p == 12;
}
bool helper(not_null<int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
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; }
const int* return_pointer_const() { return nullptr; }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
TEST_CASE("TestNotNullConstructors")
{
{
#ifdef CONFIRM_COMPILATION_ERRORS
not_null<int*> p = nullptr; // yay...does not compile!
not_null<std::vector<char>*> p = 0; // yay...does not compile!
not_null<int*> p; // yay...does not compile!
std::unique_ptr<int> up = std::make_unique<int>(120);
not_null<int*> p = up;
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;
// Forbid non-nullptr assignable types
not_null<std::vector<int>> f(std::vector<int>{1});
not_null<int> z(10);
not_null<std::vector<int>> y({1, 2});
// Forbid non-nullptr assignable types
not_null<std::vector<int>> f(std::vector<int>{1});
not_null<int> z(10);
not_null<std::vector<int>> y({1, 2});
#endif
int i = 12;
auto rp = RefCounted<int>(&i);
not_null<int*> p(rp);
CHECK(p.get() == &i);
}
not_null<std::shared_ptr<int>> x(
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
{
// from shared pointer
int i = 12;
auto rp = RefCounted<int>(&i);
not_null<int*> p(rp);
CHECK(p.get() == &i);
#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
int* pi = nullptr;
CHECK_THROWS_AS(not_null<decltype(pi)>(pi), fail_fast);
#endif
not_null<std::shared_ptr<int>> x(
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
int* pi = nullptr;
CHECK_THROWS_AS(not_null<decltype(pi)>(pi), fail_fast);
}
{
// from pointer to local
int t = 42;
not_null<int*> x = &t;
helper(&t);
helper_const(&t);
CHECK(*x == 42);
}
{
// from raw pointer
// from not_null pointer
int t = 42;
int* p = &t;
not_null<int*> x = p;
helper(p);
helper_const(p);
helper(x);
helper_const(x);
CHECK(*x == 42);
}
{
// from raw const pointer
// from not_null const pointer
int t = 42;
const int* cp = &t;
not_null<const int*> x = cp;
helper_const(cp);
helper_const(x);
CHECK(*x == 42);
}
{
// from not_null const pointer, using auto
int t = 42;
const int* cp = &t;
auto x = not_null<const int*>{cp};
CHECK(*x == 42);
}
{
// from returned pointer
CHECK_THROWS_AS(helper(return_pointer()), fail_fast);
CHECK_THROWS_AS(helper_const(return_pointer()), fail_fast);
}
}
template<typename T>
template <typename T>
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
void ostream_helper(T v)
{
@@ -474,5 +532,5 @@ TEST_CASE("TestMakeNotNull")
#endif
}
static_assert(std::is_nothrow_move_constructible<not_null<void *>>::value, "not_null must be no-throw move constructible");
static_assert(std::is_nothrow_move_constructible<not_null<void*>>::value,
"not_null must be no-throw move constructible");