span constructor no address (#723)

* Changed &arr[0] to std::array<T, N>::data and std::address_of to protect against overloaded operator&.

* Removed the usage of `std::addressof` because it is a C++ 17 feature. Using decay for C arrays instead.

* Add unit tests for #662.

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

* fixed CppCoreCheck pointer decay warning
This commit is contained in:
Anna Gringauze 2018-08-19 17:10:53 -07:00 committed by Neil MacIntosh
parent 585f48ce55
commit 1995e86d1a
2 changed files with 42 additions and 17 deletions

View File

@ -29,6 +29,7 @@
#include <stdexcept> #include <stdexcept>
#include <type_traits> // for enable_if_t, declval, is_convertible, inte... #include <type_traits> // for enable_if_t, declval, is_convertible, inte...
#include <utility> #include <utility>
#include <memory> // for std::addressof
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
@ -390,19 +391,19 @@ public:
template <std::size_t N> template <std::size_t N>
constexpr span(element_type (&arr)[N]) noexcept constexpr span(element_type (&arr)[N]) noexcept
: storage_(KnownNotNull{&arr[0]}, details::extent_type<N>()) : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type<N>())
{} {}
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>> template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
// GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug
constexpr span(std::array<ArrayElementType, N>& arr) noexcept constexpr span(std::array<ArrayElementType, N>& arr) noexcept
: storage_(&arr[0], details::extent_type<N>()) : storage_(arr.data(), details::extent_type<N>())
{} {}
template <std::size_t N> template <std::size_t N>
// GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug
constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
: storage_(&arr[0], details::extent_type<N>()) : storage_(arr.data(), details::extent_type<N>())
{} {}
// NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement

View File

@ -52,6 +52,10 @@ struct BaseClass
struct DerivedClass : BaseClass struct DerivedClass : BaseClass
{ {
}; };
struct AddressOverloaded
{
AddressOverloaded operator&() const { return {}; }
};
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
@ -306,19 +310,17 @@ TEST_CASE("from_pointer_pointer_constructor")
} }
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute // TODO: false positive?
TEST_CASE("from_array_constructor") TEST_CASE("from_array_constructor")
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
{ {
span<int> s{arr}; const span<int> s{arr};
CHECK((s.size() == 5 && s.data() == &arr[0])); CHECK((s.size() == 5 && s.data() == &arr[0]));
} }
{ {
span<int, 5> s{arr}; const span<int, 5> s{arr};
CHECK((s.size() == 5 && s.data() == &arr[0])); CHECK((s.size() == 5 && s.data() == &arr[0]));
} }
@ -350,8 +352,8 @@ TEST_CASE("from_array_constructor")
} }
#endif #endif
{ {
span<int[3]> s{&arr2d[0], 1}; const span<int[3]> s{std::addressof(arr2d[0]), 1};
CHECK((s.size() == 1 && s.data() == &arr2d[0])); CHECK((s.size() == 1 && 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};
@ -379,24 +381,32 @@ TEST_CASE("from_array_constructor")
} }
#endif #endif
{ {
span<int[3][2]> s{&arr3d[0], 1}; const span<int[3][2]> s{std::addressof(arr3d[0]), 1};
CHECK((s.size() == 1 && s.data() == &arr3d[0])); CHECK((s.size() == 1 && s.data() == std::addressof(arr3d[0])));
} }
{ {
auto s = make_span(arr); const auto s = make_span(arr);
CHECK((s.size() == 5 && s.data() == &arr[0])); CHECK((s.size() == 5 && s.data() == std::addressof(arr[0])));
} }
{ {
auto s = make_span(&(arr2d[0]), 1); const auto s = make_span(std::addressof(arr2d[0]), 1);
CHECK((s.size() == 1 && s.data() == &arr2d[0])); CHECK((s.size() == 1 && s.data() == std::addressof(arr2d[0])));
} }
{ {
auto s = make_span(&arr3d[0], 1); const auto s = make_span(std::addressof(arr3d[0]), 1);
CHECK((s.size() == 1 && s.data() == &arr3d[0])); CHECK((s.size() == 1 && s.data() == std::addressof(arr3d[0])));
} }
AddressOverloaded ao_arr[5] = {};
{
const span<AddressOverloaded, 5> s{ao_arr};
CHECK((s.size() == 5 && s.data() == std::addressof(ao_arr[0])));
}
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
@ -442,6 +452,13 @@ TEST_CASE("from_std_array_constructor")
CHECK((cs.size() == narrow_cast<ptrdiff_t>(arr.size()) && cs.data() == arr.data())); CHECK((cs.size() == narrow_cast<ptrdiff_t>(arr.size()) && cs.data() == arr.data()));
} }
std::array<AddressOverloaded, 4> ao_arr{};
{
span<AddressOverloaded, 4> fs{ao_arr};
CHECK((fs.size() == narrow_cast<ptrdiff_t>(ao_arr.size()) && ao_arr.data() == fs.data()));
}
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<int, 2> s{arr}; span<int, 2> s{arr};
@ -516,6 +533,13 @@ TEST_CASE("from_const_std_array_constructor")
CHECK((s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data())); CHECK((s.size() == narrow_cast<ptrdiff_t>(arr.size()) && s.data() == arr.data()));
} }
const std::array<AddressOverloaded, 4> ao_arr{};
{
span<const AddressOverloaded, 4> s{ao_arr};
CHECK((s.size() == narrow_cast<ptrdiff_t>(ao_arr.size()) && s.data() == ao_arr.data()));
}
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<const int, 2> s{arr}; span<const int, 2> s{arr};