From 1f76fbd168a9db5ffee39e33b751da81704bbc8d Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Tue, 31 Jul 2018 17:30:43 -0700 Subject: [PATCH 01/13] Dev/annagrin/failfast in noexcept mode windows (#710) made terminate call __fastfail in noexcept mode when using msvc --- include/gsl/gsl_assert | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/gsl/gsl_assert b/include/gsl/gsl_assert index 131fa8b..be4676b 100644 --- a/include/gsl/gsl_assert +++ b/include/gsl/gsl_assert @@ -26,6 +26,8 @@ // #if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND +#include +#define RANGE_CHECKS_FAILURE 0 #endif // @@ -82,10 +84,15 @@ namespace details #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) typedef void (__cdecl *terminate_handler)(); + + [[noreturn]] inline void __cdecl default_terminate_handler() + { + __fastfail(RANGE_CHECKS_FAILURE); + } inline gsl::details::terminate_handler& get_terminate_handler() noexcept { - static terminate_handler handler = &abort; + static terminate_handler handler = &default_terminate_handler; return handler; } From f4a715816ceb2dc136e86a68b71f05a8773c8f2b Mon Sep 17 00:00:00 2001 From: beinhaerter <34543625+beinhaerter@users.noreply.github.com> Date: Wed, 1 Aug 2018 02:53:00 +0200 Subject: [PATCH 02/13] Suppress warnings on VS (#642) - gsl::narrow, gsl::narrow_cast and gsl::at are the safe variants suggested by CppCoreGuideline. It does not make sense to let VS warn inside the implementation of these functions that unsafe static_cast is used and that the safe variants shall be used. - Suppress warning that throw_exception can be declared noexcept (for the GSL_TERMINATE_ON_CONTRACT_VIOLATION case) --- include/gsl/gsl_assert | 4 ++++ include/gsl/gsl_util | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/gsl/gsl_assert b/include/gsl/gsl_assert index be4676b..70a6eba 100644 --- a/include/gsl/gsl_assert +++ b/include/gsl/gsl_assert @@ -110,6 +110,10 @@ namespace details #if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) template +#if defined(__clang__) || defined(__GNUC__) +#else + [[gsl::suppress(f.6)]] +#endif [[noreturn]] void throw_exception(Exception&&) { gsl::details::terminate(); diff --git a/include/gsl/gsl_util b/include/gsl/gsl_util index 25f8502..ee61711 100644 --- a/include/gsl/gsl_util +++ b/include/gsl/gsl_util @@ -88,6 +88,10 @@ final_action finally(F&& f) noexcept // narrow_cast(): a searchable way to do narrowing casts of values template +#if defined(__clang__) || defined(__GNUC__) +#else +[[gsl::suppress(type.1)]] +#endif constexpr T narrow_cast(U&& u) noexcept { return static_cast(std::forward(u)); @@ -108,6 +112,10 @@ namespace details // narrow() : a checked version of narrow_cast() that throws if the cast changed the value template +#if defined(__clang__) || defined(__GNUC__) +#else +[[gsl::suppress(type.1)]] +#endif T narrow(U u) { T t = narrow_cast(u); @@ -121,6 +129,10 @@ T narrow(U u) // at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector // template +#if defined(__clang__) || defined(__GNUC__) +#else +[[gsl::suppress(type.1,bounds.2,bounds.4)]] +#endif constexpr T& at(T (&arr)[N], const index i) { Expects(i >= 0 && i < narrow_cast(N)); @@ -128,6 +140,10 @@ constexpr T& at(T (&arr)[N], const index i) } template +#if defined(__clang__) || defined(__GNUC__) +#else +[[gsl::suppress(type.1,bounds.4)]] +#endif constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) { Expects(i >= 0 && i < narrow_cast(cont.size())); From b6c531f7c159a685eb71ad6a93d8308793a4f61b Mon Sep 17 00:00:00 2001 From: Stefan Reinhold Date: Fri, 3 Aug 2018 19:39:12 +0200 Subject: [PATCH 03/13] Explicitly check for availability of std::byte (fixes #713) (#714) * Explicitly check for availbility of std::byte GCC > 7.3 defines __cpp_lib_byte >= 201603 when std::byte is available. On libc++ std::byte is available since version 5.0. This can be checked with _LIBCPP_VERSION >= 5000. This fixes 713. * Add missing \ in preprocessor check --- include/gsl/gsl_byte | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/gsl/gsl_byte b/include/gsl/gsl_byte index e861173..6b770fd 100644 --- a/include/gsl/gsl_byte +++ b/include/gsl/gsl_byte @@ -43,16 +43,23 @@ #ifndef GSL_USE_STD_BYTE // this tests if we are under GCC or Clang with enough -std:c++1z power to get us std::byte -#if defined(__cplusplus) && (__cplusplus >= 201703L) +// also check if libc++ version is sufficient (> 5.0) or libstc++ actually contains std::byte +#if defined(__cplusplus) && (__cplusplus >= 201703L) && \ + (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || \ + defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) #define GSL_USE_STD_BYTE 1 #include -#else // defined(__cplusplus) && (__cplusplus >= 201703L) +#else // defined(__cplusplus) && (__cplusplus >= 201703L) && + // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || + // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) #define GSL_USE_STD_BYTE 0 #endif //defined(__cplusplus) && (__cplusplus >= 201703L) + // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || + // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) #endif // GSL_USE_STD_BYTE #endif // _MSC_VER From 6a75903c79ff7109c24d281372005b622a9d9177 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Sun, 12 Aug 2018 20:19:16 -0700 Subject: [PATCH 04/13] replace uses of GSL_NOEXCEPT macro (#719) * Added c++17 test configurations for clang5.0 and clang6.0 * removed GSL_NOEXCEPT - Removed GSL_NOEXCEPT macro - Replaced by noexcept keyword when needed - removed noexcept where a function could throw * remove unneded undef * fixed replace errors * removed noexcept where function can throw --- include/gsl/multi_span | 380 ++++++++++++++++++++-------------------- include/gsl/string_span | 95 +++++----- 2 files changed, 229 insertions(+), 246 deletions(-) diff --git a/include/gsl/multi_span b/include/gsl/multi_span index 9c0c27b..9862d0d 100644 --- a/include/gsl/multi_span +++ b/include/gsl/multi_span @@ -61,12 +61,6 @@ #pragma GCC diagnostic ignored "-Wsign-conversion" #endif -#ifdef GSL_THROW_ON_CONTRACT_VIOLATION -#define GSL_NOEXCEPT /*noexcept*/ -#else -#define GSL_NOEXCEPT noexcept -#endif // GSL_THROW_ON_CONTRACT_VIOLATION - namespace gsl { @@ -109,22 +103,22 @@ public: using reference = std::add_lvalue_reference_t; using const_reference = std::add_lvalue_reference_t>; - constexpr multi_span_index() GSL_NOEXCEPT {} + constexpr multi_span_index() noexcept {} - constexpr multi_span_index(const value_type (&values)[Rank]) GSL_NOEXCEPT + constexpr multi_span_index(const value_type (&values)[Rank]) noexcept { std::copy(values, values + Rank, elems); } template ::value>> - constexpr multi_span_index(Ts... ds) GSL_NOEXCEPT : elems{narrow_cast(ds)...} + constexpr multi_span_index(Ts... ds) noexcept : elems{narrow_cast(ds)...} { } - constexpr multi_span_index(const multi_span_index& other) GSL_NOEXCEPT = default; + constexpr multi_span_index(const multi_span_index& other) noexcept = default; - constexpr multi_span_index& operator=(const multi_span_index& rhs) GSL_NOEXCEPT = default; + constexpr multi_span_index& operator=(const multi_span_index& rhs) noexcept = default; // Preconditions: component_idx < rank constexpr reference operator[](std::size_t component_idx) @@ -134,81 +128,81 @@ public: } // Preconditions: component_idx < rank - constexpr const_reference operator[](std::size_t component_idx) const GSL_NOEXCEPT + constexpr const_reference operator[](std::size_t component_idx) const { Expects(component_idx < Rank); // Component index must be less than rank return elems[component_idx]; } - constexpr bool operator==(const multi_span_index& rhs) const GSL_NOEXCEPT + constexpr bool operator==(const multi_span_index& rhs) const { return std::equal(elems, elems + rank, rhs.elems); } - constexpr bool operator!=(const multi_span_index& rhs) const GSL_NOEXCEPT { return !(*this == rhs); } + constexpr bool operator!=(const multi_span_index& rhs) const { return !(*this == rhs); } - constexpr multi_span_index operator+() const GSL_NOEXCEPT { return *this; } + constexpr multi_span_index operator+() const noexcept { return *this; } - constexpr multi_span_index operator-() const GSL_NOEXCEPT + constexpr multi_span_index operator-() const { multi_span_index ret = *this; std::transform(ret, ret + rank, ret, std::negate{}); return ret; } - constexpr multi_span_index operator+(const multi_span_index& rhs) const GSL_NOEXCEPT + constexpr multi_span_index operator+(const multi_span_index& rhs) const { multi_span_index ret = *this; ret += rhs; return ret; } - constexpr multi_span_index operator-(const multi_span_index& rhs) const GSL_NOEXCEPT + constexpr multi_span_index operator-(const multi_span_index& rhs) const { multi_span_index ret = *this; ret -= rhs; return ret; } - constexpr multi_span_index& operator+=(const multi_span_index& rhs) GSL_NOEXCEPT + constexpr multi_span_index& operator+=(const multi_span_index& rhs) { std::transform(elems, elems + rank, rhs.elems, elems, std::plus{}); return *this; } - constexpr multi_span_index& operator-=(const multi_span_index& rhs) GSL_NOEXCEPT + constexpr multi_span_index& operator-=(const multi_span_index& rhs) { std::transform(elems, elems + rank, rhs.elems, elems, std::minus{}); return *this; } - constexpr multi_span_index operator*(value_type v) const GSL_NOEXCEPT + constexpr multi_span_index operator*(value_type v) const { multi_span_index ret = *this; ret *= v; return ret; } - constexpr multi_span_index operator/(value_type v) const GSL_NOEXCEPT + constexpr multi_span_index operator/(value_type v) const { multi_span_index ret = *this; ret /= v; return ret; } - friend constexpr multi_span_index operator*(value_type v, const multi_span_index& rhs) GSL_NOEXCEPT + friend constexpr multi_span_index operator*(value_type v, const multi_span_index& rhs) { return rhs * v; } - constexpr multi_span_index& operator*=(value_type v) GSL_NOEXCEPT + constexpr multi_span_index& operator*=(value_type v) { std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies{}(x, v); }); return *this; } - constexpr multi_span_index& operator/=(value_type v) GSL_NOEXCEPT + constexpr multi_span_index& operator/=(value_type v) { std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides{}(x, v); }); @@ -224,42 +218,42 @@ private: struct static_bounds_dynamic_range_t { template ::value>> - constexpr operator T() const GSL_NOEXCEPT + constexpr operator T() const noexcept { return narrow_cast(-1); } }; -constexpr bool operator==(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) GSL_NOEXCEPT +constexpr bool operator==(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept { return true; } -constexpr bool operator!=(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) GSL_NOEXCEPT +constexpr bool operator!=(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept { return false; } template ::value>> -constexpr bool operator==(static_bounds_dynamic_range_t, T other) GSL_NOEXCEPT +constexpr bool operator==(static_bounds_dynamic_range_t, T other) noexcept { return narrow_cast(-1) == other; } template ::value>> -constexpr bool operator==(T left, static_bounds_dynamic_range_t right) GSL_NOEXCEPT +constexpr bool operator==(T left, static_bounds_dynamic_range_t right) noexcept { return right == left; } template ::value>> -constexpr bool operator!=(static_bounds_dynamic_range_t, T other) GSL_NOEXCEPT +constexpr bool operator!=(static_bounds_dynamic_range_t, T other) noexcept { return narrow_cast(-1) != other; } template ::value>> -constexpr bool operator!=(T left, static_bounds_dynamic_range_t right) GSL_NOEXCEPT +constexpr bool operator!=(T left, static_bounds_dynamic_range_t right) noexcept { return right != left; } @@ -320,11 +314,11 @@ namespace details return -1; } - size_type elementNum(std::size_t) const GSL_NOEXCEPT { return 0; } + size_type elementNum(std::size_t) const noexcept { return 0; } - size_type totalSize() const GSL_NOEXCEPT { return TotalSize; } + size_type totalSize() const noexcept { return TotalSize; } - bool operator==(const BoundsRanges&) const GSL_NOEXCEPT { return true; } + bool operator==(const BoundsRanges&) const noexcept { return true; } }; template @@ -381,11 +375,11 @@ namespace details return cur < m_bound ? cur + last : -1; } - size_type totalSize() const GSL_NOEXCEPT { return m_bound; } + size_type totalSize() const noexcept { return m_bound; } - size_type elementNum() const GSL_NOEXCEPT { return totalSize() / this->Base::totalSize(); } + size_type elementNum() const noexcept { return totalSize() / this->Base::totalSize(); } - size_type elementNum(std::size_t dim) const GSL_NOEXCEPT + size_type elementNum(std::size_t dim) const noexcept { if (dim > 0) return this->Base::elementNum(dim - 1); @@ -393,7 +387,7 @@ namespace details return elementNum(); } - bool operator==(const BoundsRanges& rhs) const GSL_NOEXCEPT + bool operator==(const BoundsRanges& rhs) const noexcept { return m_bound == rhs.m_bound && static_cast(*this) == static_cast(rhs); @@ -446,11 +440,11 @@ namespace details return this->Base::totalSize() * arr[Dim] + last; } - size_type totalSize() const GSL_NOEXCEPT { return CurrentRange * this->Base::totalSize(); } + size_type totalSize() const noexcept { return CurrentRange * this->Base::totalSize(); } - size_type elementNum() const GSL_NOEXCEPT { return CurrentRange; } + size_type elementNum() const noexcept { return CurrentRange; } - size_type elementNum(std::size_t dim) const GSL_NOEXCEPT + size_type elementNum(std::size_t dim) const noexcept { if (dim > 0) return this->Base::elementNum(dim - 1); @@ -458,7 +452,7 @@ namespace details return elementNum(); } - bool operator==(const BoundsRanges& rhs) const GSL_NOEXCEPT + bool operator==(const BoundsRanges& rhs) const noexcept { return static_cast(*this) == static_cast(rhs); } @@ -508,7 +502,7 @@ namespace details template 1), typename Ret = std::enable_if_t>> - constexpr Ret shift_left(const multi_span_index& other) GSL_NOEXCEPT + constexpr Ret shift_left(const multi_span_index& other) noexcept { Ret ret{}; for (std::size_t i = 0; i < Rank - 1; ++i) { @@ -623,31 +617,31 @@ public: constexpr static_bounds() = default; - constexpr sliced_type slice() const GSL_NOEXCEPT + constexpr sliced_type slice() const noexcept { return sliced_type{static_cast&>(m_ranges)}; } - constexpr size_type stride() const GSL_NOEXCEPT { return rank > 1 ? slice().size() : 1; } + constexpr size_type stride() const noexcept { return rank > 1 ? slice().size() : 1; } - constexpr size_type size() const GSL_NOEXCEPT { return m_ranges.totalSize(); } + constexpr size_type size() const noexcept { return m_ranges.totalSize(); } - constexpr size_type total_size() const GSL_NOEXCEPT { return m_ranges.totalSize(); } + constexpr size_type total_size() const noexcept { return m_ranges.totalSize(); } constexpr size_type linearize(const index_type& idx) const { return m_ranges.linearize(idx); } - constexpr bool contains(const index_type& idx) const GSL_NOEXCEPT + constexpr bool contains(const index_type& idx) const noexcept { return m_ranges.contains(idx) != -1; } - constexpr size_type operator[](std::size_t idx) const GSL_NOEXCEPT + constexpr size_type operator[](std::size_t idx) const noexcept { return m_ranges.elementNum(idx); } template - constexpr size_type extent() const GSL_NOEXCEPT + constexpr size_type extent() const noexcept { static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)"); @@ -655,7 +649,7 @@ public: } template - constexpr size_type extent(IntType dim) const GSL_NOEXCEPT + constexpr size_type extent(IntType dim) const { static_assert(std::is_integral::value, "Dimension parameter must be supplied as an integral type."); @@ -665,7 +659,7 @@ public: return m_ranges.elementNum(real_dim); } - constexpr index_type index_bounds() const GSL_NOEXCEPT + constexpr index_type index_bounds() const noexcept { size_type extents[rank] = {}; m_ranges.serialize(extents); @@ -673,23 +667,23 @@ public: } template - constexpr bool operator==(const static_bounds& rhs) const GSL_NOEXCEPT + constexpr bool operator==(const static_bounds& rhs) const noexcept { return this->size() == rhs.size(); } template - constexpr bool operator!=(const static_bounds& rhs) const GSL_NOEXCEPT + constexpr bool operator!=(const static_bounds& rhs) const noexcept { return !(*this == rhs); } - constexpr const_iterator begin() const GSL_NOEXCEPT + constexpr const_iterator begin() const noexcept { return const_iterator(*this, index_type{}); } - constexpr const_iterator end() const GSL_NOEXCEPT + constexpr const_iterator end() const noexcept { return const_iterator(*this, this->index_bounds()); } @@ -717,24 +711,24 @@ public: using sliced_type = std::conditional_t, void>; using mapping_type = generalized_mapping_tag; - constexpr strided_bounds(const strided_bounds&) GSL_NOEXCEPT = default; + constexpr strided_bounds(const strided_bounds&) noexcept = default; - constexpr strided_bounds& operator=(const strided_bounds&) GSL_NOEXCEPT = default; + constexpr strided_bounds& operator=(const strided_bounds&) noexcept = default; constexpr strided_bounds(const value_type (&values)[rank], index_type strides) : m_extents(values), m_strides(std::move(strides)) { } - constexpr strided_bounds(const index_type& extents, const index_type& strides) GSL_NOEXCEPT + constexpr strided_bounds(const index_type& extents, const index_type& strides) noexcept : m_extents(extents), m_strides(strides) { } - constexpr index_type strides() const GSL_NOEXCEPT { return m_strides; } + constexpr index_type strides() const noexcept { return m_strides; } - constexpr size_type total_size() const GSL_NOEXCEPT + constexpr size_type total_size() const noexcept { size_type ret = 0; for (std::size_t i = 0; i < rank; ++i) { @@ -743,7 +737,7 @@ public: return ret + 1; } - constexpr size_type size() const GSL_NOEXCEPT + constexpr size_type size() const noexcept { size_type ret = 1; for (std::size_t i = 0; i < rank; ++i) { @@ -752,7 +746,7 @@ public: return ret; } - constexpr bool contains(const index_type& idx) const GSL_NOEXCEPT + constexpr bool contains(const index_type& idx) const noexcept { for (std::size_t i = 0; i < rank; ++i) { if (idx[i] < 0 || idx[i] >= m_extents[i]) return false; @@ -760,7 +754,7 @@ public: return true; } - constexpr size_type linearize(const index_type& idx) const GSL_NOEXCEPT + constexpr size_type linearize(const index_type& idx) const { size_type ret = 0; for (std::size_t i = 0; i < rank; i++) { @@ -770,7 +764,7 @@ public: return ret; } - constexpr size_type stride() const GSL_NOEXCEPT { return m_strides[0]; } + constexpr size_type stride() const noexcept { return m_strides[0]; } template 1), typename Ret = std::enable_if_t> constexpr sliced_type slice() const @@ -779,20 +773,20 @@ public: } template - constexpr size_type extent() const GSL_NOEXCEPT + constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)"); return m_extents[Dim]; } - constexpr index_type index_bounds() const GSL_NOEXCEPT { return m_extents; } - constexpr const_iterator begin() const GSL_NOEXCEPT + constexpr index_type index_bounds() const noexcept { return m_extents; } + constexpr const_iterator begin() const noexcept { return const_iterator{*this, index_type{}}; } - constexpr const_iterator end() const GSL_NOEXCEPT + constexpr const_iterator end() const noexcept { return const_iterator{*this, index_bounds()}; } @@ -828,18 +822,18 @@ public: using index_type = value_type; using index_size_type = typename IndexType::value_type; template - explicit bounds_iterator(const Bounds& bnd, value_type curr) GSL_NOEXCEPT + explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept : boundary_(bnd.index_bounds()), curr_(std::move(curr)) { static_assert(is_bounds::value, "Bounds type must be provided"); } - constexpr reference operator*() const GSL_NOEXCEPT { return curr_; } + constexpr reference operator*() const noexcept { return curr_; } - constexpr pointer operator->() const GSL_NOEXCEPT { return &curr_; } + constexpr pointer operator->() const noexcept { return &curr_; } - constexpr bounds_iterator& operator++() GSL_NOEXCEPT + constexpr bounds_iterator& operator++() noexcept { for (std::size_t i = rank; i-- > 0;) { if (curr_[i] < boundary_[i] - 1) { @@ -853,14 +847,14 @@ public: return *this; } - constexpr bounds_iterator operator++(int) GSL_NOEXCEPT + constexpr bounds_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } - constexpr bounds_iterator& operator--() GSL_NOEXCEPT + constexpr bounds_iterator& operator--() { if (!less(curr_, boundary_)) { // if at the past-the-end, set to last element @@ -882,20 +876,20 @@ public: return *this; } - constexpr bounds_iterator operator--(int) GSL_NOEXCEPT + constexpr bounds_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } - constexpr bounds_iterator operator+(difference_type n) const GSL_NOEXCEPT + constexpr bounds_iterator operator+(difference_type n) const noexcept { bounds_iterator ret{*this}; return ret += n; } - constexpr bounds_iterator& operator+=(difference_type n) GSL_NOEXCEPT + constexpr bounds_iterator& operator+=(difference_type n) { auto linear_idx = linearize(curr_) + n; std::remove_const_t stride = 0; @@ -912,56 +906,56 @@ public: return *this; } - constexpr bounds_iterator operator-(difference_type n) const GSL_NOEXCEPT + constexpr bounds_iterator operator-(difference_type n) const noexcept { bounds_iterator ret{*this}; return ret -= n; } - constexpr bounds_iterator& operator-=(difference_type n) GSL_NOEXCEPT { return *this += -n; } + constexpr bounds_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - constexpr difference_type operator-(const bounds_iterator& rhs) const GSL_NOEXCEPT + constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept { return linearize(curr_) - linearize(rhs.curr_); } - constexpr value_type operator[](difference_type n) const GSL_NOEXCEPT { return *(*this + n); } + constexpr value_type operator[](difference_type n) const noexcept { return *(*this + n); } - constexpr bool operator==(const bounds_iterator& rhs) const GSL_NOEXCEPT + constexpr bool operator==(const bounds_iterator& rhs) const noexcept { return curr_ == rhs.curr_; } - constexpr bool operator!=(const bounds_iterator& rhs) const GSL_NOEXCEPT + constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } - constexpr bool operator<(const bounds_iterator& rhs) const GSL_NOEXCEPT + constexpr bool operator<(const bounds_iterator& rhs) const noexcept { return less(curr_, rhs.curr_); } - constexpr bool operator<=(const bounds_iterator& rhs) const GSL_NOEXCEPT + constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } - constexpr bool operator>(const bounds_iterator& rhs) const GSL_NOEXCEPT { return rhs < *this; } + constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } - constexpr bool operator>=(const bounds_iterator& rhs) const GSL_NOEXCEPT + constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); } - void swap(bounds_iterator& rhs) GSL_NOEXCEPT + void swap(bounds_iterator& rhs) noexcept { std::swap(boundary_, rhs.boundary_); std::swap(curr_, rhs.curr_); } private: - constexpr bool less(index_type& one, index_type& other) const GSL_NOEXCEPT + constexpr bool less(index_type& one, index_type& other) const noexcept { for (std::size_t i = 0; i < rank; ++i) { if (one[i] < other[i]) return true; @@ -969,7 +963,7 @@ private: return false; } - constexpr index_size_type linearize(const value_type& idx) const GSL_NOEXCEPT + constexpr index_size_type linearize(const value_type& idx) const noexcept { // TODO: Smarter impl. // Check if past-the-end @@ -998,7 +992,7 @@ private: template bounds_iterator operator+(typename bounds_iterator::difference_type n, - const bounds_iterator& rhs) GSL_NOEXCEPT + const bounds_iterator& rhs) noexcept { return rhs + n; } @@ -1009,7 +1003,7 @@ namespace details constexpr std::enable_if_t< std::is_same::value, typename Bounds::index_type> - make_stride(const Bounds& bnd) GSL_NOEXCEPT + make_stride(const Bounds& bnd) noexcept { return bnd.strides(); } @@ -1019,7 +1013,7 @@ namespace details constexpr std::enable_if_t< std::is_same::value, typename Bounds::index_type> - make_stride(const Bounds& bnd) GSL_NOEXCEPT + make_stride(const Bounds& bnd) noexcept { auto extents = bnd.index_bounds(); typename Bounds::size_type stride[Bounds::rank] = {}; @@ -1062,17 +1056,17 @@ struct dim_t { static const std::ptrdiff_t value = dynamic_range; const std::ptrdiff_t dvalue; - constexpr dim_t(std::ptrdiff_t size) GSL_NOEXCEPT : dvalue(size) {} + constexpr dim_t(std::ptrdiff_t size) noexcept : dvalue(size) {} }; template = 0)>> -constexpr dim_t dim() GSL_NOEXCEPT +constexpr dim_t dim() noexcept { return dim_t(); } template > -constexpr dim_t dim(std::ptrdiff_t n) GSL_NOEXCEPT +constexpr dim_t dim(std::ptrdiff_t n) noexcept { return dim_t<>(n); } @@ -1217,7 +1211,7 @@ private: public: // default constructor - same as constructing from nullptr_t - constexpr multi_span() GSL_NOEXCEPT : multi_span(nullptr, bounds_type{}) + constexpr multi_span() noexcept : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), @@ -1226,7 +1220,7 @@ public: } // construct from nullptr - get an empty multi_span - constexpr multi_span(std::nullptr_t) GSL_NOEXCEPT : multi_span(nullptr, bounds_type{}) + constexpr multi_span(std::nullptr_t) noexcept : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), @@ -1236,7 +1230,7 @@ public: // construct from nullptr with size of 0 (helps with template function calls) template ::value>> - constexpr multi_span(std::nullptr_t, IntType size) GSL_NOEXCEPT + constexpr multi_span(std::nullptr_t, IntType size) : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || @@ -1247,7 +1241,7 @@ public: } // construct from a single element - constexpr multi_span(reference data) GSL_NOEXCEPT : multi_span(&data, bounds_type{1}) + constexpr multi_span(reference data) noexcept : multi_span(&data, bounds_type{1}) { static_assert(bounds_type::dynamic_rank > 0 || bounds_type::static_size == 0 || bounds_type::static_size == 1, @@ -1259,13 +1253,13 @@ public: constexpr multi_span(value_type&&) = delete; // construct from pointer + length - constexpr multi_span(pointer ptr, size_type size) GSL_NOEXCEPT + constexpr multi_span(pointer ptr, size_type size) : multi_span(ptr, bounds_type{size}) { } // construct from pointer + length - multidimensional - constexpr multi_span(pointer data, bounds_type bounds) GSL_NOEXCEPT : data_(data), + constexpr multi_span(pointer data, bounds_type bounds) : data_(data), bounds_(std::move(bounds)) { Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0); @@ -1361,7 +1355,7 @@ public: typename OtherBounds = static_bounds, typename = std::enable_if_t::value && std::is_convertible::value>> - constexpr multi_span(multi_span other) GSL_NOEXCEPT + constexpr multi_span(multi_span other) : data_(other.data_), bounds_(other.bounds_) { @@ -1377,7 +1371,7 @@ public: // first() - extract the first Count elements into a new multi_span template - constexpr multi_span first() const GSL_NOEXCEPT + constexpr multi_span first() const { static_assert(Count >= 0, "Count must be >= 0."); static_assert(bounds_type::static_size == dynamic_range || @@ -1389,7 +1383,7 @@ public: } // first() - extract the first count elements into a new multi_span - constexpr multi_span first(size_type count) const GSL_NOEXCEPT + constexpr multi_span first(size_type count) const { Expects(count >= 0 && count <= this->size()); return {this->data(), count}; @@ -1397,7 +1391,7 @@ public: // last() - extract the last Count elements into a new multi_span template - constexpr multi_span last() const GSL_NOEXCEPT + constexpr multi_span last() const { static_assert(Count >= 0, "Count must be >= 0."); static_assert(bounds_type::static_size == dynamic_range || @@ -1409,7 +1403,7 @@ public: } // last() - extract the last count elements into a new multi_span - constexpr multi_span last(size_type count) const GSL_NOEXCEPT + constexpr multi_span last(size_type count) const { Expects(count >= 0 && count <= this->size()); return {this->data() + this->size() - count, count}; @@ -1417,7 +1411,7 @@ public: // subspan() - create a subview of Count elements starting at Offset template - constexpr multi_span subspan() const GSL_NOEXCEPT + constexpr multi_span subspan() const { static_assert(Count >= 0, "Count must be >= 0."); static_assert(Offset >= 0, "Offset must be >= 0."); @@ -1434,7 +1428,7 @@ public: // subspan() - create a subview of count elements starting at offset // supplying dynamic_range for count will consume all available elements from offset constexpr multi_span - subspan(size_type offset, size_type count = dynamic_range) const GSL_NOEXCEPT + subspan(size_type offset, size_type count = dynamic_range) const { Expects((offset >= 0 && offset <= this->size()) && (count == dynamic_range || (count <= this->size() - offset))); @@ -1443,7 +1437,7 @@ public: // section - creates a non-contiguous, strided multi_span from a contiguous one constexpr strided_span section(index_type origin, - index_type extents) const GSL_NOEXCEPT + index_type extents) const { size_type size = this->bounds().total_size() - this->bounds().linearize(origin); return {&this->operator[](origin), size, @@ -1451,26 +1445,26 @@ public: } // length of the multi_span in elements - constexpr size_type size() const GSL_NOEXCEPT { return bounds_.size(); } + constexpr size_type size() const noexcept { return bounds_.size(); } // length of the multi_span in elements - constexpr size_type length() const GSL_NOEXCEPT { return this->size(); } + constexpr size_type length() const noexcept { return this->size(); } // length of the multi_span in bytes - constexpr size_type size_bytes() const GSL_NOEXCEPT + constexpr size_type size_bytes() const noexcept { return narrow_cast(sizeof(value_type)) * this->size(); } // length of the multi_span in bytes - constexpr size_type length_bytes() const GSL_NOEXCEPT { return this->size_bytes(); } + constexpr size_type length_bytes() const noexcept { return this->size_bytes(); } - constexpr bool empty() const GSL_NOEXCEPT { return this->size() == 0; } + constexpr bool empty() const noexcept { return this->size() == 0; } static constexpr std::size_t rank() { return Rank; } template - constexpr size_type extent() const GSL_NOEXCEPT + constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "Dimension should be less than rank (dimension count starts from 0)."); @@ -1478,14 +1472,14 @@ public: } template - constexpr size_type extent(IntType dim) const GSL_NOEXCEPT + constexpr size_type extent(IntType dim) const { return bounds_.extent(dim); } - constexpr bounds_type bounds() const GSL_NOEXCEPT { return bounds_; } + constexpr bounds_type bounds() const noexcept { return bounds_; } - constexpr pointer data() const GSL_NOEXCEPT { return data_; } + constexpr pointer data() const noexcept { return data_; } template constexpr reference operator()(FirstIndex idx) @@ -1501,13 +1495,13 @@ public: return this->operator[](idx); } - constexpr reference operator[](const index_type& idx) const GSL_NOEXCEPT + constexpr reference operator[](const index_type& idx) const { return data_[bounds_.linearize(idx)]; } template 1), typename Ret = std::enable_if_t> - constexpr Ret operator[](size_type idx) const GSL_NOEXCEPT + constexpr Ret operator[](size_type idx) const { Expects(idx >= 0 && idx < bounds_.size()); // index is out of bounds of the array const size_type ridx = idx * bounds_.stride(); @@ -1517,30 +1511,30 @@ public: return Ret{data_ + ridx, bounds_.slice()}; } - constexpr iterator begin() const GSL_NOEXCEPT { return iterator{this, true}; } + constexpr iterator begin() const noexcept { return iterator{this, true}; } - constexpr iterator end() const GSL_NOEXCEPT { return iterator{this, false}; } + constexpr iterator end() const noexcept { return iterator{this, false}; } - constexpr const_iterator cbegin() const GSL_NOEXCEPT + constexpr const_iterator cbegin() const noexcept { return const_iterator{reinterpret_cast(this), true}; } - constexpr const_iterator cend() const GSL_NOEXCEPT + constexpr const_iterator cend() const noexcept { return const_iterator{reinterpret_cast(this), false}; } - constexpr reverse_iterator rbegin() const GSL_NOEXCEPT { return reverse_iterator{end()}; } + constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } - constexpr reverse_iterator rend() const GSL_NOEXCEPT { return reverse_iterator{begin()}; } + constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } - constexpr const_reverse_iterator crbegin() const GSL_NOEXCEPT + constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; } - constexpr const_reverse_iterator crend() const GSL_NOEXCEPT + constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; } @@ -1549,7 +1543,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator==(const multi_span& other) const GSL_NOEXCEPT + operator==(const multi_span& other) const noexcept { return bounds_.size() == other.bounds_.size() && (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); @@ -1559,7 +1553,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator!=(const multi_span& other) const GSL_NOEXCEPT + operator!=(const multi_span& other) const noexcept { return !(*this == other); } @@ -1568,7 +1562,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator<(const multi_span& other) const GSL_NOEXCEPT + operator<(const multi_span& other) const noexcept { return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); } @@ -1577,7 +1571,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator<=(const multi_span& other) const GSL_NOEXCEPT + operator<=(const multi_span& other) const noexcept { return !(other < *this); } @@ -1586,7 +1580,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator>(const multi_span& other) const GSL_NOEXCEPT + operator>(const multi_span& other) const noexcept { return (other < *this); } @@ -1595,7 +1589,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator>=(const multi_span& other) const GSL_NOEXCEPT + operator>=(const multi_span& other) const noexcept { return !(*this < other); } @@ -1623,7 +1617,7 @@ constexpr auto as_multi_span(SpanType s, Dimensions2... dims) // convert a multi_span to a multi_span template -multi_span as_bytes(multi_span s) GSL_NOEXCEPT +multi_span as_bytes(multi_span s) noexcept { static_assert(std::is_trivial>::value, "The value_type of multi_span must be a trivial type."); @@ -1635,7 +1629,7 @@ multi_span as_bytes(multi_span s) G // on all implementations. It should be considered an experimental extension // to the standard GSL interface. template -multi_span as_writeable_bytes(multi_span s) GSL_NOEXCEPT +multi_span as_writeable_bytes(multi_span s) noexcept { static_assert(std::is_trivial>::value, "The value_type of multi_span must be a trivial type."); @@ -1648,7 +1642,7 @@ multi_span as_writeable_bytes(multi_span s) GSL_NOEXCEPT // to the standard GSL interface. template constexpr auto -as_multi_span(multi_span s) GSL_NOEXCEPT -> multi_span< +as_multi_span(multi_span s) -> multi_span< const U, static_cast( multi_span::bounds_type::static_size != dynamic_range ? (static_cast( @@ -1674,7 +1668,7 @@ as_multi_span(multi_span s) GSL_NOEXCEPT -> multi_spa // on all implementations. It should be considered an experimental extension // to the standard GSL interface. template -constexpr auto as_multi_span(multi_span s) GSL_NOEXCEPT +constexpr auto as_multi_span(multi_span s) -> multi_span( multi_span::bounds_type::static_size != dynamic_range ? static_cast( @@ -1868,21 +1862,21 @@ public: return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()}; } - constexpr bounds_type bounds() const GSL_NOEXCEPT { return bounds_; } + constexpr bounds_type bounds() const noexcept { return bounds_; } template - constexpr size_type extent() const GSL_NOEXCEPT + constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "dimension should be less than Rank (dimension count starts from 0)"); return bounds_.template extent(); } - constexpr size_type size() const GSL_NOEXCEPT { return bounds_.size(); } + constexpr size_type size() const noexcept { return bounds_.size(); } - constexpr pointer data() const GSL_NOEXCEPT { return data_; } + constexpr pointer data() const noexcept { return data_; } - constexpr explicit operator bool() const GSL_NOEXCEPT { return data_ != nullptr; } + constexpr explicit operator bool() const noexcept { return data_ != nullptr; } constexpr iterator begin() const { return iterator{this, true}; } @@ -1910,7 +1904,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator==(const strided_span& other) const GSL_NOEXCEPT + operator==(const strided_span& other) const { return bounds_.size() == other.bounds_.size() && (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); @@ -1920,7 +1914,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator!=(const strided_span& other) const GSL_NOEXCEPT + operator!=(const strided_span& other) const { return !(*this == other); } @@ -1929,7 +1923,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator<(const strided_span& other) const GSL_NOEXCEPT + operator<(const strided_span& other) const { return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); } @@ -1938,7 +1932,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator<=(const strided_span& other) const GSL_NOEXCEPT + operator<=(const strided_span& other) const { return !(other < *this); } @@ -1947,7 +1941,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator>(const strided_span& other) const GSL_NOEXCEPT + operator>(const strided_span& other) const { return (other < *this); } @@ -1956,7 +1950,7 @@ public: typename = std::enable_if_t, std::remove_cv_t>::value>> constexpr bool - operator>=(const strided_span& other) const GSL_NOEXCEPT + operator>=(const strided_span& other) const { return !(*this < other); } @@ -2031,84 +2025,84 @@ private: } public: - reference operator*() const GSL_NOEXCEPT + reference operator*() const { validateThis(); return *data_; } - pointer operator->() const GSL_NOEXCEPT + pointer operator->() const { validateThis(); return data_; } - contiguous_span_iterator& operator++() GSL_NOEXCEPT + contiguous_span_iterator& operator++() noexcept { ++data_; return *this; } - contiguous_span_iterator operator++(int) GSL_NOEXCEPT + contiguous_span_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } - contiguous_span_iterator& operator--() GSL_NOEXCEPT + contiguous_span_iterator& operator--() noexcept { --data_; return *this; } - contiguous_span_iterator operator--(int) GSL_NOEXCEPT + contiguous_span_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } - contiguous_span_iterator operator+(difference_type n) const GSL_NOEXCEPT + contiguous_span_iterator operator+(difference_type n) const noexcept { contiguous_span_iterator ret{*this}; return ret += n; } - contiguous_span_iterator& operator+=(difference_type n) GSL_NOEXCEPT + contiguous_span_iterator& operator+=(difference_type n) noexcept { data_ += n; return *this; } - contiguous_span_iterator operator-(difference_type n) const GSL_NOEXCEPT + contiguous_span_iterator operator-(difference_type n) const noexcept { contiguous_span_iterator ret{*this}; return ret -= n; } - contiguous_span_iterator& operator-=(difference_type n) GSL_NOEXCEPT { return *this += -n; } - difference_type operator-(const contiguous_span_iterator& rhs) const GSL_NOEXCEPT + contiguous_span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } + difference_type operator-(const contiguous_span_iterator& rhs) const { Expects(m_validator == rhs.m_validator); return data_ - rhs.data_; } - reference operator[](difference_type n) const GSL_NOEXCEPT { return *(*this + n); } - bool operator==(const contiguous_span_iterator& rhs) const GSL_NOEXCEPT + reference operator[](difference_type n) const { return *(*this + n); } + bool operator==(const contiguous_span_iterator& rhs) const { Expects(m_validator == rhs.m_validator); return data_ == rhs.data_; } - bool operator!=(const contiguous_span_iterator& rhs) const GSL_NOEXCEPT + bool operator!=(const contiguous_span_iterator& rhs) const { return !(*this == rhs); } - bool operator<(const contiguous_span_iterator& rhs) const GSL_NOEXCEPT + bool operator<(const contiguous_span_iterator& rhs) const { Expects(m_validator == rhs.m_validator); return data_ < rhs.data_; } - bool operator<=(const contiguous_span_iterator& rhs) const GSL_NOEXCEPT + bool operator<=(const contiguous_span_iterator& rhs) const { return !(rhs < *this); } - bool operator>(const contiguous_span_iterator& rhs) const GSL_NOEXCEPT { return rhs < *this; } - bool operator>=(const contiguous_span_iterator& rhs) const GSL_NOEXCEPT + bool operator>(const contiguous_span_iterator& rhs) const { return rhs < *this; } + bool operator>=(const contiguous_span_iterator& rhs) const { return !(rhs > *this); } - void swap(contiguous_span_iterator& rhs) GSL_NOEXCEPT + void swap(contiguous_span_iterator& rhs) noexcept { std::swap(data_, rhs.data_); std::swap(m_validator, rhs.m_validator); @@ -2117,7 +2111,7 @@ public: template contiguous_span_iterator operator+(typename contiguous_span_iterator::difference_type n, - const contiguous_span_iterator& rhs) GSL_NOEXCEPT + const contiguous_span_iterator& rhs) noexcept { return rhs + n; } @@ -2145,68 +2139,68 @@ private: } public: - reference operator*() GSL_NOEXCEPT { return (*m_container)[*m_itr]; } - pointer operator->() GSL_NOEXCEPT { return &(*m_container)[*m_itr]; } - general_span_iterator& operator++() GSL_NOEXCEPT + reference operator*() noexcept { return (*m_container)[*m_itr]; } + pointer operator->() noexcept { return &(*m_container)[*m_itr]; } + general_span_iterator& operator++() noexcept { ++m_itr; return *this; } - general_span_iterator operator++(int) GSL_NOEXCEPT + general_span_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } - general_span_iterator& operator--() GSL_NOEXCEPT + general_span_iterator& operator--() noexcept { --m_itr; return *this; } - general_span_iterator operator--(int) GSL_NOEXCEPT + general_span_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } - general_span_iterator operator+(difference_type n) const GSL_NOEXCEPT + general_span_iterator operator+(difference_type n) const noexcept { general_span_iterator ret{*this}; return ret += n; } - general_span_iterator& operator+=(difference_type n) GSL_NOEXCEPT + general_span_iterator& operator+=(difference_type n) noexcept { m_itr += n; return *this; } - general_span_iterator operator-(difference_type n) const GSL_NOEXCEPT + general_span_iterator operator-(difference_type n) const noexcept { general_span_iterator ret{*this}; return ret -= n; } - general_span_iterator& operator-=(difference_type n) GSL_NOEXCEPT { return *this += -n; } - difference_type operator-(const general_span_iterator& rhs) const GSL_NOEXCEPT + general_span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } + difference_type operator-(const general_span_iterator& rhs) const { Expects(m_container == rhs.m_container); return m_itr - rhs.m_itr; } - value_type operator[](difference_type n) const GSL_NOEXCEPT { return (*m_container)[m_itr[n]]; } + value_type operator[](difference_type n) const { return (*m_container)[m_itr[n]]; } - bool operator==(const general_span_iterator& rhs) const GSL_NOEXCEPT + bool operator==(const general_span_iterator& rhs) const { Expects(m_container == rhs.m_container); return m_itr == rhs.m_itr; } - bool operator!=(const general_span_iterator& rhs) const GSL_NOEXCEPT { return !(*this == rhs); } - bool operator<(const general_span_iterator& rhs) const GSL_NOEXCEPT + bool operator!=(const general_span_iterator& rhs) const { return !(*this == rhs); } + bool operator<(const general_span_iterator& rhs) const { Expects(m_container == rhs.m_container); return m_itr < rhs.m_itr; } - bool operator<=(const general_span_iterator& rhs) const GSL_NOEXCEPT { return !(rhs < *this); } - bool operator>(const general_span_iterator& rhs) const GSL_NOEXCEPT { return rhs < *this; } - bool operator>=(const general_span_iterator& rhs) const GSL_NOEXCEPT { return !(rhs > *this); } - void swap(general_span_iterator& rhs) GSL_NOEXCEPT + bool operator<=(const general_span_iterator& rhs) const { return !(rhs < *this); } + bool operator>(const general_span_iterator& rhs) const { return rhs < *this; } + bool operator>=(const general_span_iterator& rhs) const { return !(rhs > *this); } + void swap(general_span_iterator& rhs) noexcept { std::swap(m_itr, rhs.m_itr); std::swap(m_container, rhs.m_container); @@ -2215,15 +2209,13 @@ public: template general_span_iterator operator+(typename general_span_iterator::difference_type n, - const general_span_iterator& rhs) GSL_NOEXCEPT + const general_span_iterator& rhs) noexcept { return rhs + n; } } // namespace gsl -#undef GSL_NOEXCEPT - #ifdef _MSC_VER #if _MSC_VER < 1910 diff --git a/include/gsl/string_span b/include/gsl/string_span index c08f246..2a89561 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -44,13 +44,6 @@ #endif // _MSC_VER < 1910 #endif // _MSC_VER -// In order to test the library, we need it to throw exceptions that we can catch -#ifdef GSL_THROW_ON_CONTRACT_VIOLATION -#define GSL_NOEXCEPT /*noexcept*/ -#else -#define GSL_NOEXCEPT noexcept -#endif // GSL_THROW_ON_CONTRACT_VIOLATION - namespace gsl { // @@ -189,13 +182,13 @@ public: using const_reverse_iterator = typename impl_type::const_reverse_iterator; // default (empty) - constexpr basic_string_span() GSL_NOEXCEPT = default; + constexpr basic_string_span() noexcept = default; // copy - constexpr basic_string_span(const basic_string_span& other) GSL_NOEXCEPT = default; + constexpr basic_string_span(const basic_string_span& other) noexcept = default; // assign - constexpr basic_string_span& operator=(const basic_string_span& other) GSL_NOEXCEPT = default; + constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default; constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {} constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {} @@ -208,12 +201,12 @@ public: } template > - constexpr basic_string_span(std::array& arr) GSL_NOEXCEPT : span_(arr) + constexpr basic_string_span(std::array& arr) noexcept : span_(arr) { } template > - constexpr basic_string_span(const std::array& arr) GSL_NOEXCEPT + constexpr basic_string_span(const std::array& arr) noexcept : span_(arr) { } @@ -301,23 +294,23 @@ public: constexpr pointer data() const { return span_.data(); } - constexpr index_type length() const GSL_NOEXCEPT { return span_.size(); } - constexpr index_type size() const GSL_NOEXCEPT { return span_.size(); } - constexpr index_type size_bytes() const GSL_NOEXCEPT { return span_.size_bytes(); } - constexpr index_type length_bytes() const GSL_NOEXCEPT { return span_.length_bytes(); } - constexpr bool empty() const GSL_NOEXCEPT { return size() == 0; } + constexpr index_type length() const noexcept { return span_.size(); } + constexpr index_type size() const noexcept { return span_.size(); } + constexpr index_type size_bytes() const noexcept { return span_.size_bytes(); } + constexpr index_type length_bytes() const noexcept { return span_.length_bytes(); } + constexpr bool empty() const noexcept { return size() == 0; } - constexpr iterator begin() const GSL_NOEXCEPT { return span_.begin(); } - constexpr iterator end() const GSL_NOEXCEPT { return span_.end(); } + constexpr iterator begin() const noexcept { return span_.begin(); } + constexpr iterator end() const noexcept { return span_.end(); } - constexpr const_iterator cbegin() const GSL_NOEXCEPT { return span_.cbegin(); } - constexpr const_iterator cend() const GSL_NOEXCEPT { return span_.cend(); } + constexpr const_iterator cbegin() const noexcept { return span_.cbegin(); } + constexpr const_iterator cend() const noexcept { return span_.cend(); } - constexpr reverse_iterator rbegin() const GSL_NOEXCEPT { return span_.rbegin(); } - constexpr reverse_iterator rend() const GSL_NOEXCEPT { return span_.rend(); } + constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); } + constexpr reverse_iterator rend() const noexcept { return span_.rend(); } - constexpr const_reverse_iterator crbegin() const GSL_NOEXCEPT { return span_.crbegin(); } - constexpr const_reverse_iterator crend() const GSL_NOEXCEPT { return span_.crend(); } + constexpr const_reverse_iterator crbegin() const noexcept { return span_.crbegin(); } + constexpr const_reverse_iterator crend() const noexcept { return span_.crend(); } private: static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) @@ -409,7 +402,7 @@ public: using impl_type = span; using string_span_type = basic_string_span; - constexpr basic_zstring_span(impl_type s) GSL_NOEXCEPT : span_(s) + constexpr basic_zstring_span(impl_type s) : span_(s) { // expects a zero-terminated span Expects(s[s.size() - 1] == '\0'); @@ -427,16 +420,16 @@ public: // move assign constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default; - constexpr bool empty() const GSL_NOEXCEPT { return span_.size() == 0; } + constexpr bool empty() const noexcept { return span_.size() == 0; } - constexpr string_span_type as_string_span() const GSL_NOEXCEPT + constexpr string_span_type as_string_span() const noexcept { auto sz = span_.size(); return { span_.data(), sz > 1 ? sz - 1 : 0 }; } - constexpr string_span_type ensure_z() const GSL_NOEXCEPT { return gsl::ensure_z(span_); } + constexpr string_span_type ensure_z() const noexcept { return gsl::ensure_z(span_); } - constexpr const_zstring_type assume_z() const GSL_NOEXCEPT { return span_.data(); } + constexpr const_zstring_type assume_z() const noexcept { return span_.data(); } private: impl_type span_; @@ -471,7 +464,7 @@ template ::value || std::is_convertible>>::value>> -bool operator==(const gsl::basic_string_span& one, const T& other) GSL_NOEXCEPT +bool operator==(const gsl::basic_string_span& one, const T& other) noexcept { const gsl::basic_string_span> tmp(other); return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); @@ -481,7 +474,7 @@ template ::value && std::is_convertible>>::value>> -bool operator==(const T& one, const gsl::basic_string_span& other) GSL_NOEXCEPT +bool operator==(const T& one, const gsl::basic_string_span& other) noexcept { gsl::basic_string_span> tmp(one); return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end()); @@ -491,7 +484,7 @@ bool operator==(const T& one, const gsl::basic_string_span& other template , Extent>>::value>> -bool operator!=(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator!=(gsl::basic_string_span one, const T& other) noexcept { return !(one == other); } @@ -501,7 +494,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator!=(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator!=(const T& one, gsl::basic_string_span other) noexcept { return !(one == other); } @@ -510,7 +503,7 @@ bool operator!=(const T& one, gsl::basic_string_span other) GSL_N template , Extent>>::value>> -bool operator<(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator<(gsl::basic_string_span one, const T& other) noexcept { const gsl::basic_string_span, Extent> tmp(other); return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); @@ -521,7 +514,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator<(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator<(const T& one, gsl::basic_string_span other) noexcept { gsl::basic_string_span, Extent> tmp(one); return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); @@ -540,7 +533,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator<(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator<(gsl::basic_string_span one, const T& other) noexcept { gsl::basic_string_span, Extent> tmp(other); return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); @@ -554,7 +547,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator<(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator<(const T& one, gsl::basic_string_span other) noexcept { gsl::basic_string_span, Extent> tmp(one); return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); @@ -565,7 +558,7 @@ bool operator<(const T& one, gsl::basic_string_span other) GSL_NO template , Extent>>::value>> -bool operator<=(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator<=(gsl::basic_string_span one, const T& other) noexcept { return !(other < one); } @@ -575,7 +568,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator<=(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator<=(const T& one, gsl::basic_string_span other) noexcept { return !(other < one); } @@ -593,7 +586,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator<=(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator<=(gsl::basic_string_span one, const T& other) noexcept { return !(other < one); } @@ -606,7 +599,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator<=(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator<=(const T& one, gsl::basic_string_span other) noexcept { return !(other < one); } @@ -616,7 +609,7 @@ bool operator<=(const T& one, gsl::basic_string_span other) GSL_N template , Extent>>::value>> -bool operator>(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator>(gsl::basic_string_span one, const T& other) noexcept { return other < one; } @@ -626,7 +619,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator>(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator>(const T& one, gsl::basic_string_span other) noexcept { return other < one; } @@ -644,7 +637,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator>(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator>(gsl::basic_string_span one, const T& other) noexcept { return other < one; } @@ -657,7 +650,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator>(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator>(const T& one, gsl::basic_string_span other) noexcept { return other < one; } @@ -667,7 +660,7 @@ bool operator>(const T& one, gsl::basic_string_span other) GSL_NO template , Extent>>::value>> -bool operator>=(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator>=(gsl::basic_string_span one, const T& other) noexcept { return !(one < other); } @@ -677,7 +670,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator>=(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator>=(const T& one, gsl::basic_string_span other) noexcept { return !(one < other); } @@ -695,7 +688,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator>=(gsl::basic_string_span one, const T& other) GSL_NOEXCEPT +bool operator>=(gsl::basic_string_span one, const T& other) noexcept { return !(one < other); } @@ -708,15 +701,13 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator>=(const T& one, gsl::basic_string_span other) GSL_NOEXCEPT +bool operator>=(const T& one, gsl::basic_string_span other) noexcept { return !(one < other); } #endif } // namespace gsl -#undef GSL_NOEXCEPT - #ifdef _MSC_VER #pragma warning(pop) From cea0d0ac2bd775f0fb4c7e357a089979370ae3cd Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Sun, 12 Aug 2018 21:44:17 -0700 Subject: [PATCH 05/13] fix cppcorecheck warnings (#703) * Added c++17 test configurations for clang5.0 and clang6.0 * Fixed CppCoreCheck warnings in GSL and tests - Added CMakeSettings.json for VS Open Folder configuration - So we can easily run CppCoreCheck in VS - Fixed CppCorecheck warnings where it made sense - Suppressed the rest - Some suppression does not work due to compiler/tool bugs, so replaced by #pragma disable - CppCoreCheck has noise, suppressed those with comments - Catch produces many warnings, blanket-supressed them all - Had to fix clang formatting to keep attributes in place - clang-format does not support attributes, so I am using - "CommentPragmas: '^ NO-FORMAT:'" to skip formatiting on them - Removed GSL_NOEXCEPT macro, removed incorred noexcepts * Ignore unknown attributes * ignore unknown attributes in noexception mode tests * fixed C26472 in at() * created GSL_SUPPRESS macro to allow all compilers to parse suppression attributes * try to fix gcc compilation problems with attributes * ignore gsl::suppress for gcc * move suppression to function level on return statements clang5.0 and up does not allow attributes on return statemets in constexpr functions * move suppression to function level on return statements * use GSL_SUPPRESS in algorithm_tests * Addressed PR comments --- .clang-format | 15 +- CMakeSettings.json | 18 ++ include/gsl/gsl_algorithm | 8 +- include/gsl/gsl_assert | 21 +- include/gsl/gsl_byte | 25 +- include/gsl/gsl_util | 40 +-- include/gsl/multi_span | 441 ++++++++++++++++------------ include/gsl/span | 157 +++++----- include/gsl/string_span | 112 ++++--- tests/CMakeLists.txt | 4 +- tests/algorithm_tests.cpp | 51 ++-- tests/assertion_tests.cpp | 6 + tests/at_tests.cpp | 21 +- tests/bounds_tests.cpp | 16 + tests/byte_tests.cpp | 24 +- tests/multi_span_tests.cpp | 224 +++++++++----- tests/no_exception_ensure_tests.cpp | 8 +- tests/no_exception_throw_tests.cpp | 4 +- tests/notnull_tests.cpp | 39 ++- tests/owner_tests.cpp | 11 + tests/span_tests.cpp | 88 ++++-- tests/strided_span_tests.cpp | 38 ++- tests/string_span_tests.cpp | 55 +++- tests/test.cpp | 8 + tests/utils_tests.cpp | 9 + 25 files changed, 940 insertions(+), 503 deletions(-) create mode 100644 CMakeSettings.json diff --git a/.clang-format b/.clang-format index 78696f5..c12d3bf 100644 --- a/.clang-format +++ b/.clang-format @@ -5,7 +5,19 @@ IndentWidth: 4 AccessModifierOffset: -4 NamespaceIndentation: Inner -BreakBeforeBraces: Allman +BreakBeforeBraces: Custom +BraceWrapping: + AfterNamespace: true + AfterEnum: true + AfterStruct: true + AfterClass: true + SplitEmptyFunction: false + AfterControlStatement: true + AfterFunction: true + AfterUnion: true + BeforeElse: true + + AlwaysBreakTemplateDeclarations: true BreakConstructorInitializersBeforeComma: true ConstructorInitializerAllOnOneLineOrOnePerLine: true @@ -19,3 +31,4 @@ AlignConsecutiveAssignments: false AlignTrailingComments: true SpaceAfterCStyleCast: true +CommentPragmas: '^ NO-FORMAT:' diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000..2e1ad24 --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ + "msvc_x64_x64" + ], + "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", + "cmakeCommandArgs": "-DGSL_CXX_STANDARD=17", + "buildCommandArgs": "-v", + "ctestCommandArgs": "", + "codeAnalysisRuleset": "CppCoreCheckRules.ruleset" + } + ] +} \ No newline at end of file diff --git a/include/gsl/gsl_algorithm b/include/gsl/gsl_algorithm index 710792f..c2ba31f 100644 --- a/include/gsl/gsl_algorithm +++ b/include/gsl/gsl_algorithm @@ -31,15 +31,12 @@ #pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4996) // unsafe use of std::copy_n -// blanket turn off warnings from CppCoreCheck for now -// so people aren't annoyed by them when running the tool. -// more targeted suppressions will be added in a future update to the GSL -#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495) #endif // _MSC_VER namespace gsl { - +// Note: this will generate faster code than std::copy using span iterator in older msvc+stl +// not necessary for msvc since VS2017 15.8 (_MSC_VER >= 1915) template void copy(span src, span dest) @@ -51,6 +48,7 @@ void copy(span src, span "Source range is longer than target range"); Expects(dest.size() >= src.size()); + GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute std::copy_n(src.data(), src.size(), dest.data()); } diff --git a/include/gsl/gsl_assert b/include/gsl/gsl_assert index 70a6eba..321bf20 100644 --- a/include/gsl/gsl_assert +++ b/include/gsl/gsl_assert @@ -20,6 +20,20 @@ #include #include // for logic_error +// +// make suppress attributes parse for some compilers +// Hopefully temporary until suppresion stardization occurs +// +#if defined (_MSC_VER) +#define GSL_SUPPRESS(x) [[gsl::suppress(x)]] +#else +#if defined(__clang__) +#define GSL_SUPPRESS(x) [[gsl::suppress("x")]] +#else +#define GSL_SUPPRESS(x) +#endif // __clang__ +#endif // _MSC_VER + // // Temporary until MSVC STL supports no-exceptions mode. // Currently terminate is a no-op in this mode, so we add termination behavior back @@ -85,6 +99,7 @@ namespace details typedef void (__cdecl *terminate_handler)(); + GSL_SUPPRESS(f.6) // NO-FORMAT: attribute [[noreturn]] inline void __cdecl default_terminate_handler() { __fastfail(RANGE_CHECKS_FAILURE); @@ -110,11 +125,7 @@ namespace details #if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) template -#if defined(__clang__) || defined(__GNUC__) -#else - [[gsl::suppress(f.6)]] -#endif - [[noreturn]] void throw_exception(Exception&&) + [[noreturn]] void throw_exception(Exception&&) noexcept { gsl::details::terminate(); } diff --git a/include/gsl/gsl_byte b/include/gsl/gsl_byte index 6b770fd..bc18886 100644 --- a/include/gsl/gsl_byte +++ b/include/gsl/gsl_byte @@ -17,14 +17,28 @@ #ifndef GSL_BYTE_H #define GSL_BYTE_H +// +// make suppress attributes work for some compilers +// Hopefully temporary until suppresion standardization occurs +// +#if defined(_MSC_VER) +#define GSL_SUPPRESS(x) [[gsl::suppress(x)]] +#else +#if defined(__clang__) +#define GSL_SUPPRESS(x) [[gsl::suppress("x")]] +#else +#define GSL_SUPPRESS(x) +#endif // __clang__ +#endif // _MSC_VER + #include #ifdef _MSC_VER #pragma warning(push) -// don't warn about function style casts in byte related operators -#pragma warning(disable : 26493) +// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. +#pragma warning(disable : 26493) // don't use c-style casts // TODO: MSVC suppression in templates does not always work #ifndef GSL_USE_STD_BYTE // this tests if we are under MSVC and the standard lib has std::byte and it is enabled @@ -57,12 +71,12 @@ #define GSL_USE_STD_BYTE 0 -#endif //defined(__cplusplus) && (__cplusplus >= 201703L) +#endif //defined(__cplusplus) && (__cplusplus >= 201703L) && // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) #endif // GSL_USE_STD_BYTE -#endif // _MSC_VER +#endif // _MSC_VER // Use __may_alias__ attribute on gcc and clang #if defined __clang__ || (__GNUC__ > 5) @@ -75,7 +89,6 @@ namespace gsl { #if GSL_USE_STD_BYTE - using std::byte; using std::to_integer; @@ -160,6 +173,8 @@ constexpr byte to_byte_impl(T t) noexcept return static_cast(t); } template <> +// NOTE: need suppression since c++14 does not allow "return {t}" +// GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work constexpr byte to_byte_impl(unsigned char t) noexcept { return byte(t); diff --git a/include/gsl/gsl_util b/include/gsl/gsl_util index ee61711..542bbaa 100644 --- a/include/gsl/gsl_util +++ b/include/gsl/gsl_util @@ -34,8 +34,8 @@ #if _MSC_VER < 1910 #pragma push_macro("constexpr") #define constexpr /*constexpr*/ -#endif // _MSC_VER < 1910 -#endif // _MSC_VER +#endif // _MSC_VER < 1910 +#endif // _MSC_VER namespace gsl { @@ -62,6 +62,7 @@ public: final_action& operator=(const final_action&) = delete; final_action& operator=(final_action&&) = delete; + GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws ~final_action() noexcept { if (invoke_) f_(); @@ -69,12 +70,11 @@ public: private: F f_; - bool invoke_ {true}; + bool invoke_{true}; }; // finally() - convenience function to generate a final_action template - final_action finally(const F& f) noexcept { return final_action(f); @@ -88,10 +88,7 @@ final_action finally(F&& f) noexcept // narrow_cast(): a searchable way to do narrowing casts of values template -#if defined(__clang__) || defined(__GNUC__) -#else -[[gsl::suppress(type.1)]] -#endif +GSL_SUPPRESS(type.1) // NO-FORMAT: attribute constexpr T narrow_cast(U&& u) noexcept { return static_cast(std::forward(u)); @@ -108,15 +105,13 @@ namespace details : public std::integral_constant::value == std::is_signed::value> { }; -} +} // namespace details // narrow() : a checked version of narrow_cast() that throws if the cast changed the value template -#if defined(__clang__) || defined(__GNUC__) -#else -[[gsl::suppress(type.1)]] -#endif -T narrow(U u) +GSL_SUPPRESS(type.1) // NO-FORMAT: attribute +GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) +T narrow(U u) noexcept(false) { T t = narrow_cast(u); if (static_cast(t) != u) gsl::details::throw_exception(narrowing_error()); @@ -129,29 +124,26 @@ T narrow(U u) // at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector // template -#if defined(__clang__) || defined(__GNUC__) -#else -[[gsl::suppress(type.1,bounds.2,bounds.4)]] -#endif +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr T& at(T (&arr)[N], const index i) { Expects(i >= 0 && i < narrow_cast(N)); - return arr[static_cast(i)]; + return arr[narrow_cast(i)]; } template -#if defined(__clang__) || defined(__GNUC__) -#else -[[gsl::suppress(type.1,bounds.4)]] -#endif +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) { Expects(i >= 0 && i < narrow_cast(cont.size())); using size_type = decltype(cont.size()); - return cont[static_cast(i)]; + return cont[narrow_cast(i)]; } template +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr T at(const std::initializer_list cont, const index i) { Expects(i >= 0 && i < narrow_cast(cont.size())); diff --git a/include/gsl/multi_span b/include/gsl/multi_span index 9862d0d..a7c96ce 100644 --- a/include/gsl/multi_span +++ b/include/gsl/multi_span @@ -44,6 +44,12 @@ #pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4702) // unreachable code +// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. +#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor +#pragma warning(disable : 26473) // in some instantiations we cast to the same type +#pragma warning(disable : 26490) // TODO: bug in parser - attributes and templates +#pragma warning(disable : 26465) // TODO: bug - suppression does not work on template functions + #if _MSC_VER < 1910 #pragma push_macro("constexpr") #define constexpr /*constexpr*/ @@ -52,9 +58,9 @@ #endif // _MSC_VER // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) -// While there is a conversion from signed to unsigned, it happens at -// compiletime, so the compiler wouldn't have to warn indiscriminently, but -// could check if the source value actually doesn't fit into the target type +// While there is a conversion from signed to unsigned, it happens at +// compiletime, so the compiler wouldn't have to warn indiscriminently, but +// could check if the source value actually doesn't fit into the target type // and only warn in those cases. #if __GNUC__ > 6 #pragma GCC diagnostic push @@ -86,7 +92,7 @@ namespace details std::is_integral::value && are_integral::value> { }; -} +} // namespace details template class multi_span_index final @@ -107,20 +113,23 @@ public: constexpr multi_span_index(const value_type (&values)[Rank]) noexcept { + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::copy(values, values + Rank, elems); } template ::value>> constexpr multi_span_index(Ts... ds) noexcept : elems{narrow_cast(ds)...} - { - } + {} constexpr multi_span_index(const multi_span_index& other) noexcept = default; constexpr multi_span_index& operator=(const multi_span_index& rhs) noexcept = default; // Preconditions: component_idx < rank + GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr reference operator[](std::size_t component_idx) { Expects(component_idx < Rank); // Component index must be less than rank @@ -128,18 +137,25 @@ public: } // Preconditions: component_idx < rank - constexpr const_reference operator[](std::size_t component_idx) const + GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute + constexpr const_reference operator[](std::size_t component_idx) const { Expects(component_idx < Rank); // Component index must be less than rank return elems[component_idx]; } + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute constexpr bool operator==(const multi_span_index& rhs) const { return std::equal(elems, elems + rank, rhs.elems); } - constexpr bool operator!=(const multi_span_index& rhs) const { return !(*this == rhs); } + constexpr bool operator!=(const multi_span_index& rhs) const + { + return !(*this == rhs); + } constexpr multi_span_index operator+() const noexcept { return *this; } @@ -166,12 +182,17 @@ public: constexpr multi_span_index& operator+=(const multi_span_index& rhs) { - std::transform(elems, elems + rank, rhs.elems, elems, std::plus{}); + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute + std::transform(elems, elems + rank, rhs.elems, elems, + std::plus{}); return *this; } constexpr multi_span_index& operator-=(const multi_span_index& rhs) { + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::transform(elems, elems + rank, rhs.elems, elems, std::minus{}); return *this; } @@ -197,6 +218,8 @@ public: constexpr multi_span_index& operator*=(value_type v) { + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies{}(x, v); }); return *this; @@ -204,6 +227,8 @@ public: constexpr multi_span_index& operator/=(value_type v) { + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides{}(x, v); }); return *this; @@ -291,16 +316,14 @@ namespace details // TODO : following signature is for work around VS bug template BoundsRanges(const OtherRange&, bool /* firstLevel */) - { - } + {} BoundsRanges(const std::ptrdiff_t* const) {} - BoundsRanges() = default; + BoundsRanges() noexcept = default; template void serialize(T&) const - { - } + {} template size_type linearize(const T&) const @@ -335,21 +358,22 @@ namespace details size_type m_bound; public: + GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // this pointer type is cannot be assigned nullptr - issue in not_null + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr + 1), m_bound(*arr * this->Base::totalSize()) { Expects(0 <= *arr); } - BoundsRanges() : m_bound(0) {} + BoundsRanges() noexcept : m_bound(0) {} template BoundsRanges(const BoundsRanges& other, bool /* firstLevel */ = true) : Base(static_cast&>(other), false) , m_bound(other.totalSize()) - { - } + {} template void serialize(T& arr) const @@ -359,6 +383,7 @@ namespace details } template + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute size_type linearize(const T& arr) const { const size_type index = this->Base::totalSize() * arr[Dim]; @@ -375,9 +400,17 @@ namespace details return cur < m_bound ? cur + last : -1; } - size_type totalSize() const noexcept { return m_bound; } + GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used + size_type totalSize() const noexcept + { + return m_bound; + } - size_type elementNum() const noexcept { return totalSize() / this->Base::totalSize(); } + GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used + size_type elementNum() const noexcept + { + return totalSize() / this->Base::totalSize(); + } size_type elementNum(std::size_t dim) const noexcept { @@ -413,6 +446,7 @@ namespace details bool firstLevel = true) : Base(static_cast&>(other), false) { + GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive (void) firstLevel; } @@ -426,7 +460,10 @@ namespace details template size_type linearize(const T& arr) const { + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute Expects(arr[Dim] >= 0 && arr[Dim] < CurrentRange); // Index is out of range + + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute return this->Base::totalSize() * arr[Dim] + this->Base::template linearize(arr); } @@ -440,10 +477,19 @@ namespace details return this->Base::totalSize() * arr[Dim] + last; } - size_type totalSize() const noexcept { return CurrentRange * this->Base::totalSize(); } + GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used + size_type totalSize() const noexcept + { + return CurrentRange * this->Base::totalSize(); + } - size_type elementNum() const noexcept { return CurrentRange; } + GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used + size_type elementNum() const noexcept + { + return CurrentRange; + } + GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used size_type elementNum(std::size_t dim) const noexcept { if (dim > 0) @@ -505,12 +551,14 @@ namespace details constexpr Ret shift_left(const multi_span_index& other) noexcept { Ret ret{}; - for (std::size_t i = 0; i < Rank - 1; ++i) { - ret[i] = other[i + 1]; + for (std::size_t i = 0; i < Rank - 1; ++i) + { + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute + ret[i] = other[i + 1]; } return ret; } -} +} // namespace details template class bounds_iterator; @@ -528,7 +576,7 @@ class static_bounds using MyRanges = details::BoundsRanges; MyRanges m_ranges; - constexpr static_bounds(const MyRanges& range) : m_ranges(range) {} + constexpr static_bounds(const MyRanges& range) noexcept : m_ranges(range) {} template friend class static_bounds; @@ -547,7 +595,8 @@ public: using sliced_type = static_bounds; using mapping_type = contiguous_mapping_tag; - constexpr static_bounds(const static_bounds&) = default; + constexpr static_bounds(const static_bounds&) noexcept = default; + constexpr static_bounds() /*noexcept*/ = default; template struct BoundsRangeConvertible2; @@ -605,8 +654,7 @@ public: MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize()); } - constexpr static_bounds(std::initializer_list il) - : m_ranges(il.begin()) + constexpr static_bounds(std::initializer_list il) : m_ranges(il.begin()) { // Size of the initializer list must match the rank of the array Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || @@ -615,8 +663,6 @@ public: Expects(m_ranges.totalSize() <= PTRDIFF_MAX); } - constexpr static_bounds() = default; - constexpr sliced_type slice() const noexcept { return sliced_type{static_cast&>(m_ranges)}; @@ -690,8 +736,7 @@ public: }; template -class strided_bounds -{ +class strided_bounds { template friend class strided_bounds; @@ -717,53 +762,53 @@ public: constexpr strided_bounds(const value_type (&values)[rank], index_type strides) : m_extents(values), m_strides(std::move(strides)) - { - } + {} constexpr strided_bounds(const index_type& extents, const index_type& strides) noexcept - : m_extents(extents), - m_strides(strides) + : m_extents(extents), m_strides(strides) { } constexpr index_type strides() const noexcept { return m_strides; } + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type total_size() const noexcept { size_type ret = 0; - for (std::size_t i = 0; i < rank; ++i) { - ret += (m_extents[i] - 1) * m_strides[i]; - } + for (std::size_t i = 0; i < rank; ++i) { ret += (m_extents[i] - 1) * m_strides[i]; } return ret + 1; } + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type size() const noexcept { size_type ret = 1; - for (std::size_t i = 0; i < rank; ++i) { - ret *= m_extents[i]; - } + for (std::size_t i = 0; i < rank; ++i) { ret *= m_extents[i]; } return ret; } constexpr bool contains(const index_type& idx) const noexcept { - for (std::size_t i = 0; i < rank; ++i) { + for (std::size_t i = 0; i < rank; ++i) + { if (idx[i] < 0 || idx[i] >= m_extents[i]) return false; } return true; } + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type linearize(const index_type& idx) const { size_type ret = 0; - for (std::size_t i = 0; i < rank; i++) { + for (std::size_t i = 0; i < rank; i++) + { Expects(idx[i] < m_extents[i]); // index is out of bounds of the array ret += idx[i] * m_strides[i]; } return ret; } + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type stride() const noexcept { return m_strides[0]; } template 1), typename Ret = std::enable_if_t> @@ -773,6 +818,8 @@ public: } template + + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr size_type extent() const noexcept { static_assert(Dim < Rank, @@ -781,15 +828,10 @@ public: } constexpr index_type index_bounds() const noexcept { return m_extents; } - constexpr const_iterator begin() const noexcept - { - return const_iterator{*this, index_type{}}; - } - constexpr const_iterator end() const noexcept - { - return const_iterator{*this, index_bounds()}; - } + constexpr const_iterator begin() const noexcept { return const_iterator{*this, index_type{}}; } + + constexpr const_iterator end() const noexcept { return const_iterator{*this, index_bounds()}; } private: index_type m_extents; @@ -823,8 +865,7 @@ public: using index_size_type = typename IndexType::value_type; template explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept - : boundary_(bnd.index_bounds()), - curr_(std::move(curr)) + : boundary_(bnd.index_bounds()), curr_(std::move(curr)) { static_assert(is_bounds::value, "Bounds type must be provided"); } @@ -833,10 +874,15 @@ public: constexpr pointer operator->() const noexcept { return &curr_; } + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute constexpr bounds_iterator& operator++() noexcept + { - for (std::size_t i = rank; i-- > 0;) { - if (curr_[i] < boundary_[i] - 1) { + for (std::size_t i = rank; i-- > 0;) + { + if (curr_[i] < boundary_[i] - 1) + { curr_[i]++; return *this; } @@ -854,17 +900,19 @@ public: return ret; } + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr bounds_iterator& operator--() { - if (!less(curr_, boundary_)) { + if (!less(curr_, boundary_)) + { // if at the past-the-end, set to last element - for (std::size_t i = 0; i < rank; ++i) { - curr_[i] = boundary_[i] - 1; - } + for (std::size_t i = 0; i < rank; ++i) { curr_[i] = boundary_[i] - 1; } return *this; } - for (std::size_t i = rank; i-- > 0;) { - if (curr_[i] >= 1) { + for (std::size_t i = rank; i-- > 0;) + { + if (curr_[i] >= 1) + { curr_[i]--; return *this; } @@ -889,15 +937,15 @@ public: return ret += n; } + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr bounds_iterator& operator+=(difference_type n) { auto linear_idx = linearize(curr_) + n; std::remove_const_t stride = 0; stride[rank - 1] = 1; - for (std::size_t i = rank - 1; i-- > 0;) { - stride[i] = stride[i + 1] * boundary_[i + 1]; - } - for (std::size_t i = 0; i < rank; ++i) { + for (std::size_t i = rank - 1; i-- > 0;) { stride[i] = stride[i + 1] * boundary_[i + 1]; } + for (std::size_t i = 0; i < rank; ++i) + { curr_[i] = linear_idx / stride[i]; linear_idx = linear_idx % stride[i]; } @@ -926,27 +974,19 @@ public: return curr_ == rhs.curr_; } - constexpr bool operator!=(const bounds_iterator& rhs) const noexcept - { - return !(*this == rhs); - } + + constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } constexpr bool operator<(const bounds_iterator& rhs) const noexcept { return less(curr_, rhs.curr_); } - constexpr bool operator<=(const bounds_iterator& rhs) const noexcept - { - return !(rhs < *this); - } + constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } - constexpr bool operator>=(const bounds_iterator& rhs) const noexcept - { - return !(rhs > *this); - } + constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); } void swap(bounds_iterator& rhs) noexcept { @@ -955,30 +995,37 @@ public: } private: + + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr bool less(index_type& one, index_type& other) const noexcept { - for (std::size_t i = 0; i < rank; ++i) { + for (std::size_t i = 0; i < rank; ++i) + { if (one[i] < other[i]) return true; } return false; } + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr index_size_type linearize(const value_type& idx) const noexcept { // TODO: Smarter impl. // Check if past-the-end index_size_type multiplier = 1; index_size_type res = 0; - if (!less(idx, boundary_)) { + if (!less(idx, boundary_)) + { res = 1; - for (std::size_t i = rank; i-- > 0;) { + for (std::size_t i = rank; i-- > 0;) + { res += (idx[i] - 1) * multiplier; multiplier *= boundary_[i]; } } else { - for (std::size_t i = rank; i-- > 0;) { + for (std::size_t i = rank; i-- > 0;) + { res += idx[i] * multiplier; multiplier *= boundary_[i]; } @@ -1019,7 +1066,10 @@ namespace details typename Bounds::size_type stride[Bounds::rank] = {}; stride[Bounds::rank - 1] = 1; - for (std::size_t i = 1; i < Bounds::rank; ++i) { + for (std::size_t i = 1; i < Bounds::rank; ++i) + { + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute + GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i]; } return {stride}; @@ -1175,7 +1225,7 @@ namespace details struct is_multi_span : is_multi_span_oracle> { }; -} +} // namespace details template class multi_span @@ -1211,7 +1261,9 @@ private: public: // default constructor - same as constructing from nullptr_t - constexpr multi_span() noexcept : multi_span(nullptr, bounds_type{}) + GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive + constexpr multi_span() noexcept + : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), @@ -1220,7 +1272,9 @@ public: } // construct from nullptr - get an empty multi_span - constexpr multi_span(std::nullptr_t) noexcept : multi_span(nullptr, bounds_type{}) + GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive + constexpr multi_span(std::nullptr_t) noexcept + : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), @@ -1230,8 +1284,9 @@ public: // construct from nullptr with size of 0 (helps with template function calls) template ::value>> - constexpr multi_span(std::nullptr_t, IntType size) - : multi_span(nullptr, bounds_type{}) + + // GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive // TODO: parser bug + constexpr multi_span(std::nullptr_t, IntType size) : multi_span(nullptr, bounds_type{}) { static_assert(bounds_type::dynamic_rank != 0 || (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), @@ -1241,7 +1296,10 @@ public: } // construct from a single element - constexpr multi_span(reference data) noexcept : multi_span(&data, bounds_type{1}) + + GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive + constexpr multi_span(reference data) noexcept + : multi_span(&data, bounds_type{1}) { static_assert(bounds_type::dynamic_rank > 0 || bounds_type::static_size == 0 || bounds_type::static_size == 1, @@ -1253,14 +1311,14 @@ public: constexpr multi_span(value_type&&) = delete; // construct from pointer + length + GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive constexpr multi_span(pointer ptr, size_type size) : multi_span(ptr, bounds_type{size}) - { - } + {} // construct from pointer + length - multidimensional - constexpr multi_span(pointer data, bounds_type bounds) : data_(data), - bounds_(std::move(bounds)) + constexpr multi_span(pointer data, bounds_type bounds) + : data_(data), bounds_(std::move(bounds)) { Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0); } @@ -1314,8 +1372,9 @@ public: constexpr multi_span(const std::array& arr) : multi_span(arr.data(), bounds_type{static_bounds{}}) { - static_assert(std::is_convertible(*)[]>::value, - "Cannot convert from source type to target multi_span type."); + static_assert( + std::is_convertible(*)[]>::value, + "Cannot convert from source type to target multi_span type."); static_assert(std::is_convertible, bounds_type>::value, "You cannot construct a multi_span from a std::array of smaller size."); } @@ -1337,8 +1396,7 @@ public: constexpr multi_span(Cont& cont) : multi_span(static_cast(cont.data()), details::newBoundsHelper(narrow_cast(cont.size()))) - { - } + {} // prevent constructing from temporary containers template ::value && std::is_convertible::value>> constexpr multi_span(multi_span other) - : data_(other.data_), - bounds_(other.bounds_) - { - } + : data_(other.data_), bounds_(other.bounds_) + {} // trivial copy and move constexpr multi_span(const multi_span&) = default; @@ -1371,6 +1427,7 @@ public: // first() - extract the first Count elements into a new multi_span template + constexpr multi_span first() const { static_assert(Count >= 0, "Count must be >= 0."); @@ -1427,8 +1484,8 @@ public: // subspan() - create a subview of count elements starting at offset // supplying dynamic_range for count will consume all available elements from offset - constexpr multi_span - subspan(size_type offset, size_type count = dynamic_range) const + constexpr multi_span subspan(size_type offset, + size_type count = dynamic_range) const { Expects((offset >= 0 && offset <= this->size()) && (count == dynamic_range || (count <= this->size() - offset))); @@ -1439,7 +1496,7 @@ public: constexpr strided_span section(index_type origin, index_type extents) const { - size_type size = this->bounds().total_size() - this->bounds().linearize(origin); + const size_type size = this->bounds().total_size() - this->bounds().linearize(origin); return {&this->operator[](origin), size, strided_bounds{extents, details::make_stride(bounds())}}; } @@ -1490,17 +1547,20 @@ public: template constexpr reference operator()(FirstIndex firstIndex, OtherIndices... indices) { - index_type idx = {narrow_cast(firstIndex), - narrow_cast(indices)...}; + const index_type idx = {narrow_cast(firstIndex), + narrow_cast(indices)...}; return this->operator[](idx); } + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](const index_type& idx) const { return data_[bounds_.linearize(idx)]; } template 1), typename Ret = std::enable_if_t> + + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr Ret operator[](size_type idx) const { Expects(idx >= 0 && idx < bounds_.size()); // index is out of bounds of the array @@ -1515,6 +1575,7 @@ public: constexpr iterator end() const noexcept { return iterator{this, false}; } + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute constexpr const_iterator cbegin() const noexcept { return const_iterator{reinterpret_cast(this), true}; @@ -1540,56 +1601,51 @@ public: } template , std::remove_cv_t>::value>> - constexpr bool - operator==(const multi_span& other) const noexcept + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator==(const multi_span& other) const { return bounds_.size() == other.bounds_.size() && (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); } template , std::remove_cv_t>::value>> - constexpr bool - operator!=(const multi_span& other) const noexcept + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator!=(const multi_span& other) const { return !(*this == other); } template , std::remove_cv_t>::value>> - constexpr bool - operator<(const multi_span& other) const noexcept + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator<(const multi_span& other) const { return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); } template , std::remove_cv_t>::value>> - constexpr bool - operator<=(const multi_span& other) const noexcept + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator<=(const multi_span& other) const { return !(other < *this); } template , std::remove_cv_t>::value>> - constexpr bool - operator>(const multi_span& other) const noexcept + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator>(const multi_span& other) const + noexcept { return (other < *this); } template , std::remove_cv_t>::value>> - constexpr bool - operator>=(const multi_span& other) const noexcept + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator>=(const multi_span& other) const { return !(*this < other); } @@ -1610,7 +1666,7 @@ constexpr auto as_multi_span(SpanType s, Dimensions2... dims) "Variadic as_multi_span() is for reshaping existing spans."); using BoundsType = typename multi_span::bounds_type; - auto tobounds = details::static_as_multi_span_helper(dims..., details::Sep{}); + const auto tobounds = details::static_as_multi_span_helper(dims..., details::Sep{}); details::verifyBoundsReshape(s.bounds(), tobounds); return {s.data(), tobounds}; } @@ -1641,8 +1697,7 @@ multi_span as_writeable_bytes(multi_span s) noexcept // on all implementations. It should be considered an experimental extension // to the standard GSL interface. template -constexpr auto -as_multi_span(multi_span s) -> multi_span< +constexpr auto as_multi_span(multi_span s) -> multi_span< const U, static_cast( multi_span::bounds_type::static_size != dynamic_range ? (static_cast( @@ -1677,11 +1732,10 @@ constexpr auto as_multi_span(multi_span s) : dynamic_range)> { using ByteSpan = multi_span; - static_assert( - std::is_trivial>::value && - (ByteSpan::bounds_type::static_size == dynamic_range || - ByteSpan::bounds_type::static_size % sizeof(U) == 0), - "Target type must be a trivial type and its size must match the byte array size"); + static_assert(std::is_trivial>::value && + (ByteSpan::bounds_type::static_size == dynamic_range || + ByteSpan::bounds_type::static_size % sizeof(U) == 0), + "Target type must be a trivial type and its size must match the byte array size"); Expects((s.size_bytes() % sizeof(U)) == 0); return {reinterpret_cast(s.data()), @@ -1747,6 +1801,7 @@ constexpr auto as_multi_span(Cont&& arr) -> std::enable_if_t< // from basic_string which doesn't have nonconst .data() member like other contiguous containers template +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute constexpr auto as_multi_span(std::basic_string& str) -> multi_span { @@ -1792,6 +1847,7 @@ public: Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0); // Bounds cross data boundaries Expects(this->bounds().total_size() <= size); + GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive (void) size; } @@ -1799,8 +1855,7 @@ public: template constexpr strided_span(value_type (&values)[N], bounds_type bounds) : strided_span(values, N, std::move(bounds)) - { - } + {} // from array view template > constexpr strided_span(multi_span av, bounds_type bounds) : strided_span(av.data(), av.bounds().total_size(), std::move(bounds)) - { - } + {} // convertible template ::value>> constexpr strided_span(const strided_span& other) : data_(other.data_), bounds_(other.bounds_) - { - } + {} // convert from bytes template @@ -1832,7 +1885,7 @@ public: "OtherValueType should have a size to contain a multiple of ValueTypes"); auto d = narrow_cast(sizeof(OtherValueType) / sizeof(value_type)); - size_type size = this->bounds().total_size() / d; + const size_type size = this->bounds().total_size() / d; return {const_cast(reinterpret_cast(this->data())), size, bounds_type{resize_extent(this->bounds().index_bounds(), d), @@ -1841,17 +1894,19 @@ public: constexpr strided_span section(index_type origin, index_type extents) const { - size_type size = this->bounds().total_size() - this->bounds().linearize(origin); + const size_type size = this->bounds().total_size() - this->bounds().linearize(origin); return {&this->operator[](origin), size, bounds_type{extents, details::make_stride(bounds())}}; } + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](const index_type& idx) const { return data_[bounds_.linearize(idx)]; } template 1), typename Ret = std::enable_if_t> + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr Ret operator[](size_type idx) const { Expects(idx < bounds_.size()); // index is out of bounds of the array @@ -1901,56 +1956,50 @@ public: constexpr const_reverse_iterator crend() const { return const_reverse_iterator{cbegin()}; } template , std::remove_cv_t>::value>> - constexpr bool - operator==(const strided_span& other) const + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator==(const strided_span& other) const { return bounds_.size() == other.bounds_.size() && (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); } template , std::remove_cv_t>::value>> - constexpr bool - operator!=(const strided_span& other) const + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator!=(const strided_span& other) const { return !(*this == other); } template , std::remove_cv_t>::value>> - constexpr bool - operator<(const strided_span& other) const + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator<(const strided_span& other) const { return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); } template , std::remove_cv_t>::value>> - constexpr bool - operator<=(const strided_span& other) const + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator<=(const strided_span& other) const { return !(other < *this); } template , std::remove_cv_t>::value>> - constexpr bool - operator>(const strided_span& other) const + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator>(const strided_span& other) const { return (other < *this); } template , std::remove_cv_t>::value>> - constexpr bool - operator>=(const strided_span& other) const + typename = std::enable_if_t, + std::remove_cv_t>::value>> + constexpr bool operator>=(const strided_span& other) const { return !(*this < other); } @@ -1959,6 +2008,7 @@ private: static index_type resize_extent(const index_type& extent, std::ptrdiff_t d) { // The last dimension of the array needs to contain a multiple of new type elements + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0)); index_type ret = extent; @@ -1971,12 +2021,14 @@ private: static index_type resize_stride(const index_type& strides, std::ptrdiff_t, void* = nullptr) { // Only strided arrays with regular strides can be resized + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute Expects(strides[Rank - 1] == 1); return strides; } template 1), typename = std::enable_if_t> + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute static index_type resize_stride(const index_type& strides, std::ptrdiff_t d) { // Only strided arrays with regular strides can be resized @@ -1985,7 +2037,8 @@ private: // memory that can contain a multiple of new type elements Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0)); - for (std::size_t i = Rank - 1; i > 0; --i) { + for (std::size_t i = Rank - 1; i > 0; --i) + { // Only strided arrays with regular strides can be resized Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0)); } @@ -2013,16 +2066,18 @@ private: pointer data_; const Span* m_validator; - void validateThis() const - { + + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + void validateThis() const { // iterator is out of range of the array Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size()); } + + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute contiguous_span_iterator(const Span* container, bool isbegin) : data_(isbegin ? container->data_ : container->data_ + container->size()) , m_validator(container) - { - } + {} public: reference operator*() const @@ -2035,6 +2090,8 @@ public: validateThis(); return data_; } + + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute contiguous_span_iterator& operator++() noexcept { ++data_; @@ -2046,6 +2103,8 @@ public: ++(*this); return ret; } + + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute contiguous_span_iterator& operator--() noexcept { --data_; @@ -2072,7 +2131,8 @@ public: contiguous_span_iterator ret{*this}; return ret -= n; } - contiguous_span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } + + contiguous_span_iterator& operator-=(difference_type n) { return *this += -n; } difference_type operator-(const contiguous_span_iterator& rhs) const { Expects(m_validator == rhs.m_validator); @@ -2084,24 +2144,19 @@ public: Expects(m_validator == rhs.m_validator); return data_ == rhs.data_; } - bool operator!=(const contiguous_span_iterator& rhs) const - { - return !(*this == rhs); - } + + bool operator!=(const contiguous_span_iterator& rhs) const { return !(*this == rhs); } + bool operator<(const contiguous_span_iterator& rhs) const { Expects(m_validator == rhs.m_validator); return data_ < rhs.data_; } - bool operator<=(const contiguous_span_iterator& rhs) const - { - return !(rhs < *this); - } + + bool operator<=(const contiguous_span_iterator& rhs) const { return !(rhs < *this); } bool operator>(const contiguous_span_iterator& rhs) const { return rhs < *this; } - bool operator>=(const contiguous_span_iterator& rhs) const - { - return !(rhs > *this); - } + bool operator>=(const contiguous_span_iterator& rhs) const { return !(rhs > *this); } + void swap(contiguous_span_iterator& rhs) noexcept { std::swap(data_, rhs.data_); @@ -2117,8 +2172,7 @@ contiguous_span_iterator operator+(typename contiguous_span_iterator } template -class general_span_iterator -{ +class general_span_iterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = typename Span::value_type; @@ -2135,8 +2189,7 @@ private: general_span_iterator(const Span* container, bool isbegin) : m_container(container) , m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) - { - } + {} public: reference operator*() noexcept { return (*m_container)[*m_itr]; } @@ -2184,6 +2237,8 @@ public: Expects(m_container == rhs.m_container); return m_itr - rhs.m_itr; } + + GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute value_type operator[](difference_type n) const { return (*m_container)[m_itr[n]]; } bool operator==(const general_span_iterator& rhs) const @@ -2227,7 +2282,7 @@ general_span_iterator operator+(typename general_span_iterator::diff #endif // _MSC_VER -#if __GNUC__ > 6 +#if __GNUC__ > 6 #pragma GCC diagnostic pop #endif // __GNUC__ > 6 diff --git a/include/gsl/span b/include/gsl/span index 2fa9cc5..3e5a053 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -37,10 +37,9 @@ #pragma warning(disable : 4127) // conditional expression is constant #pragma warning(disable : 4702) // unreachable code -// blanket turn off warnings from CppCoreCheck for now -// so people aren't annoyed by them when running the tool. -// more targeted suppressions will be added in a future update to the GSL -#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495) +// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. +#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor +#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates #if _MSC_VER < 1910 #pragma push_macro("constexpr") @@ -48,7 +47,7 @@ #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND #endif // _MSC_VER < 1910 -#else // _MSC_VER +#endif // _MSC_VER // See if we have enough C++17 power to use a static constexpr data member // without needing an out-of-line definition @@ -56,12 +55,10 @@ #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND #endif // !(defined(__cplusplus) && (__cplusplus >= 201703L)) -#endif // _MSC_VER - // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) -// While there is a conversion from signed to unsigned, it happens at -// compiletime, so the compiler wouldn't have to warn indiscriminently, but -// could check if the source value actually doesn't fit into the target type +// While there is a conversion from signed to unsigned, it happens at +// compiletime, so the compiler wouldn't have to warn indiscriminently, but +// could check if the source value actually doesn't fit into the target type // and only warn in those cases. #if __GNUC__ > 6 #pragma GCC diagnostic push @@ -129,7 +126,6 @@ namespace details using element_type_ = typename Span::element_type; public: - #ifdef _MSC_VER // Tell Microsoft standard library that span_iterators are checked. using _Unchecked_type = typename Span::pointer; @@ -146,15 +142,17 @@ namespace details constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept : span_(span), index_(idx) - {} + { + } friend span_iterator; - template* = nullptr> + template * = nullptr> constexpr span_iterator(const span_iterator& other) noexcept : span_iterator(other.span_, other.index_) { } + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator*() const { Expects(index_ != span_->size()); @@ -227,43 +225,34 @@ namespace details return index_ - rhs.index_; } - constexpr reference operator[](difference_type n) const - { - return *(*this + n); - } + constexpr reference operator[](difference_type n) const { return *(*this + n); } - constexpr friend bool operator==(span_iterator lhs, - span_iterator rhs) noexcept + constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept { return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; } - constexpr friend bool operator!=(span_iterator lhs, - span_iterator rhs) noexcept + constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept { return !(lhs == rhs); } - constexpr friend bool operator<(span_iterator lhs, - span_iterator rhs) noexcept + constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept { return lhs.index_ < rhs.index_; } - constexpr friend bool operator<=(span_iterator lhs, - span_iterator rhs) noexcept + constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept { return !(rhs < lhs); } - constexpr friend bool operator>(span_iterator lhs, - span_iterator rhs) noexcept + constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept { return rhs < lhs; } - constexpr friend bool operator>=(span_iterator lhs, - span_iterator rhs) noexcept + constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept { return !(rhs > lhs); } @@ -272,21 +261,21 @@ namespace details // MSVC++ iterator debugging support; allows STL algorithms in 15.8+ // to unwrap span_iterator to a pointer type after a range check in STL // algorithm calls - friend constexpr void _Verify_range(span_iterator lhs, - span_iterator rhs) noexcept - { // test that [lhs, rhs) forms a valid range inside an STL algorithm - Expects(lhs.span_ == rhs.span_ // range spans have to match - && lhs.index_ <= rhs.index_); // range must not be transposed + friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept + { // test that [lhs, rhs) forms a valid range inside an STL algorithm + Expects(lhs.span_ == rhs.span_ // range spans have to match + && lhs.index_ <= rhs.index_); // range must not be transposed } constexpr void _Verify_offset(const difference_type n) const noexcept - { // test that the iterator *this + n is a valid range in an STL + { // test that the iterator *this + n is a valid range in an STL // algorithm call Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); } + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr pointer _Unwrapped() const noexcept - { // after seeking *this to a high water mark, or using one of the + { // after seeking *this to a high water mark, or using one of the // _Verify_xxx functions above, unwrap this span_iterator to a raw // pointer return span_->data() + index_; @@ -299,8 +288,9 @@ namespace details #else static constexpr bool _Unwrap_when_unverified = false; #endif + GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive constexpr void _Seek_to(const pointer p) noexcept - { // adjust the position of *this to previously verified location p + { // adjust the position of *this to previously verified location p // after _Unwrapped index_ = p - span_->data(); } @@ -356,7 +346,9 @@ namespace details template struct calculate_subspan_type { - using type = span; + using type = span; }; } // namespace details @@ -380,9 +372,9 @@ public: using size_type = index_type; #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) - static constexpr const index_type extent { Extent }; + static constexpr const index_type extent{Extent}; #else - static constexpr index_type extent { Extent }; + static constexpr index_type extent{Extent}; #endif // [span.cons], span constructors, copy, assignment, and destructor @@ -408,12 +400,14 @@ public: } template > + // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr span(std::array& arr) noexcept : storage_(&arr[0], details::extent_type()) { } template + // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr span(const std::array, N>& arr) noexcept : storage_(&arr[0], details::extent_type()) { @@ -465,6 +459,7 @@ public: } template + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr span last() const { Expects(Count >= 0 && size() - Count >= 0); @@ -472,7 +467,9 @@ public: } template - constexpr auto subspan() const -> typename details::calculate_subspan_type::type + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + constexpr auto subspan() const -> + typename details::calculate_subspan_type::type { Expects((Offset >= 0 && size() - Offset >= 0) && (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); @@ -497,7 +494,6 @@ public: return make_subspan(offset, count, subspan_selector{}); } - // [span.obs], span observers constexpr index_type size() const noexcept { return storage_.size(); } constexpr index_type size_bytes() const noexcept @@ -507,6 +503,7 @@ public: constexpr bool empty() const noexcept { return size() == 0; } // [span.elem], span element access + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](index_type idx) const { Expects(idx >= 0 && idx < storage_.size()); @@ -527,17 +524,26 @@ public: constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } - constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; } - constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; } + constexpr const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator{cend()}; + } + constexpr const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator{cbegin()}; + } #ifdef _MSC_VER // Tell MSVC how to unwrap spans in range-based-for constexpr pointer _Unchecked_begin() const noexcept { return data(); } - constexpr pointer _Unchecked_end() const noexcept { return data() + size(); } + constexpr pointer _Unchecked_end() const noexcept + { + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + return data() + size(); + } #endif // _MSC_VER private: - // Needed to remove unnecessary null check in subspans struct KnownNotNull { @@ -554,17 +560,17 @@ private: // KnownNotNull parameter is needed to remove unnecessary null check // in subspans and constructors from arrays template - constexpr storage_type(KnownNotNull data, OtherExtentType ext) : ExtentType(ext), data_(data.p) + constexpr storage_type(KnownNotNull data, OtherExtentType ext) + : ExtentType(ext), data_(data.p) { - Expects(ExtentType::size() >= 0); + Expects(ExtentType::size() >= 0); } - template constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) { - Expects(ExtentType::size() >= 0); - Expects(data || ExtentType::size() == 0); + Expects(ExtentType::size() >= 0); + Expects(data || ExtentType::size() == 0); } constexpr pointer data() const noexcept { return data_; } @@ -580,29 +586,28 @@ private: constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {} template - class subspan_selector {}; + class subspan_selector + { + }; template - span make_subspan(index_type offset, - index_type count, + span make_subspan(index_type offset, index_type count, subspan_selector) const { - span tmp(*this); + const span tmp(*this); return tmp.subspan(offset, count); } - span make_subspan(index_type offset, - index_type count, + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + span make_subspan(index_type offset, index_type count, subspan_selector) const { Expects(offset >= 0 && size() - offset >= 0); - if (count == dynamic_extent) - { - return { KnownNotNull{ data() + offset }, size() - offset }; - } + + if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } Expects(count >= 0 && size() - offset >= count); - return { KnownNotNull{ data() + offset }, count }; + return {KnownNotNull{data() + offset}, count}; } }; @@ -611,46 +616,39 @@ template constexpr const typename span::index_type span::extent; #endif - // [span.comparison], span comparison operators template -constexpr bool operator==(span l, - span r) +constexpr bool operator==(span l, span r) { return std::equal(l.begin(), l.end(), r.begin(), r.end()); } template -constexpr bool operator!=(span l, - span r) +constexpr bool operator!=(span l, span r) { return !(l == r); } template -constexpr bool operator<(span l, - span r) +constexpr bool operator<(span l, span r) { return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); } template -constexpr bool operator<=(span l, - span r) +constexpr bool operator<=(span l, span r) { return !(l > r); } template -constexpr bool operator>(span l, - span r) +constexpr bool operator>(span l, span r) { return r < l; } template -constexpr bool operator>=(span l, - span r) +constexpr bool operator>=(span l, span r) { return !(l < r); } @@ -676,13 +674,14 @@ namespace details : std::integral_constant { }; -} +} // namespace details // [span.objectrep], views of object representation template span::value> as_bytes(span s) noexcept { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } @@ -691,6 +690,7 @@ template ::value> as_writeable_bytes(span s) noexcept { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } @@ -698,7 +698,8 @@ as_writeable_bytes(span s) noexcept // make_span() - Utility functions for creating spans // template -constexpr span make_span(ElementType* ptr, typename span::index_type count) +constexpr span make_span(ElementType* ptr, + typename span::index_type count) { return span(ptr, count); } @@ -759,7 +760,7 @@ constexpr ElementType& at(span s, index i) #pragma warning(pop) #endif // _MSC_VER -#if __GNUC__ > 6 +#if __GNUC__ > 6 #pragma GCC diagnostic pop #endif // __GNUC__ > 6 diff --git a/include/gsl/string_span b/include/gsl/string_span index 2a89561..d298039 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -20,6 +20,7 @@ #include // for Ensures, Expects #include // for narrow_cast #include // for operator!=, operator==, dynamic_extent +#include // for not_null #include // for equal, lexicographical_compare #include // for array @@ -32,10 +33,9 @@ #ifdef _MSC_VER #pragma warning(push) -// blanket turn off warnings from CppCoreCheck for now -// so people aren't annoyed by them when running the tool. -// more targeted suppressions will be added in a future update to the GSL -#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495) +// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. +#pragma warning(disable : 26446) // TODO: bug in parser - attributes and templates +#pragma warning(disable : 26481) // TODO: suppress does not work inside templates sometimes #if _MSC_VER < 1910 #pragma push_macro("constexpr") @@ -98,7 +98,7 @@ namespace details return len; } -} +} // namespace details // // ensure_sentinel() @@ -111,7 +111,13 @@ namespace details template span ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX) { + Ensures(seq != nullptr); + + GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work auto cur = seq; + Ensures(cur != nullptr); // workaround for removing the warning + + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // TODO: suppress does not work while ((cur - seq) < max && *cur != Sentinel) ++cur; Ensures(*cur == Sentinel); return {seq, cur - seq}; @@ -131,21 +137,20 @@ span ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRD template span ensure_z(CharT (&sz)[N]) { - return ensure_z(&sz[0], static_cast(N)); + return ensure_z(&sz[0], narrow_cast(N)); } template span::type, dynamic_extent> ensure_z(Cont& cont) { - return ensure_z(cont.data(), static_cast(cont.size())); + return ensure_z(cont.data(), narrow_cast(cont.size())); } template class basic_string_span; -namespace details -{ +namespace details { template struct is_basic_string_span_oracle : std::false_type { @@ -160,7 +165,7 @@ namespace details struct is_basic_string_span : is_basic_string_span_oracle> { }; -} +} // namespace details // // string_span and relatives @@ -197,32 +202,27 @@ public: // All other containers allow 0s within the length, so we do not remove them template constexpr basic_string_span(element_type (&arr)[N]) : span_(remove_z(arr)) - { - } + {} template > constexpr basic_string_span(std::array& arr) noexcept : span_(arr) - { - } + {} template > - constexpr basic_string_span(const std::array& arr) noexcept - : span_(arr) - { - } + constexpr basic_string_span(const std::array& arr) noexcept : span_(arr) + {} // Container signature should work for basic_string after C++17 version exists template + // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr basic_string_span(std::basic_string& str) : span_(&str[0], narrow_cast(str.length())) - { - } + {} template constexpr basic_string_span(const std::basic_string& str) : span_(&str[0], str.length()) - { - } + {} // from containers. Containers must have a pointer type and data() function signatures template ().data())>::value>> constexpr basic_string_span(Container& cont) : span_(cont) - { - } + {} template ().data())>::value>> constexpr basic_string_span(const Container& cont) : span_(cont) - { - } + {} // from string_span template < @@ -252,8 +250,7 @@ public: typename basic_string_span::impl_type, impl_type>::value>> constexpr basic_string_span(basic_string_span other) : span_(other.data(), other.length()) - { - } + {} template constexpr basic_string_span first() const @@ -359,21 +356,22 @@ template std::basic_string::type> to_string(basic_string_span view) { - return {view.data(), static_cast(view.length())}; + return {view.data(), narrow_cast(view.length())}; } template , typename Allocator = std::allocator, typename gCharT, std::ptrdiff_t Extent> std::basic_string to_basic_string(basic_string_span view) { - return {view.data(), static_cast(view.length())}; + return {view.data(), narrow_cast(view.length())}; } template basic_string_span::value> as_bytes(basic_string_span s) noexcept { - return { reinterpret_cast(s.data()), s.size_bytes() }; + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + return {reinterpret_cast(s.data()), s.size_bytes()}; } template ::value> as_writeable_bytes(basic_string_span s) noexcept { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return {reinterpret_cast(s.data()), s.size_bytes()}; } // zero-terminated string span, used to convert // zero-terminated spans to legacy strings template -class basic_zstring_span -{ +class basic_zstring_span { public: using value_type = CharT; using const_value_type = std::add_const_t; @@ -424,10 +422,10 @@ public: constexpr string_span_type as_string_span() const noexcept { - auto sz = span_.size(); - return { span_.data(), sz > 1 ? sz - 1 : 0 }; + const auto sz = span_.size(); + return {span_.data(), sz > 1 ? sz - 1 : 0}; } - constexpr string_span_type ensure_z() const noexcept { return gsl::ensure_z(span_); } + constexpr string_span_type ensure_z() const { return gsl::ensure_z(span_); } constexpr const_zstring_type assume_z() const noexcept { return span_.data(); } @@ -464,7 +462,7 @@ template ::value || std::is_convertible>>::value>> -bool operator==(const gsl::basic_string_span& one, const T& other) noexcept +bool operator==(const gsl::basic_string_span& one, const T& other) { const gsl::basic_string_span> tmp(other); return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); @@ -474,9 +472,9 @@ template ::value && std::is_convertible>>::value>> -bool operator==(const T& one, const gsl::basic_string_span& other) noexcept +bool operator==(const T& one, const gsl::basic_string_span& other) { - gsl::basic_string_span> tmp(one); + const gsl::basic_string_span> tmp(one); return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end()); } @@ -484,7 +482,7 @@ bool operator==(const T& one, const gsl::basic_string_span& other template , Extent>>::value>> -bool operator!=(gsl::basic_string_span one, const T& other) noexcept +bool operator!=(gsl::basic_string_span one, const T& other) { return !(one == other); } @@ -494,7 +492,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator!=(const T& one, gsl::basic_string_span other) noexcept +bool operator!=(const T& one, gsl::basic_string_span other) { return !(one == other); } @@ -503,7 +501,7 @@ bool operator!=(const T& one, gsl::basic_string_span other) noexc template , Extent>>::value>> -bool operator<(gsl::basic_string_span one, const T& other) noexcept +bool operator<(gsl::basic_string_span one, const T& other) { const gsl::basic_string_span, Extent> tmp(other); return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); @@ -514,7 +512,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator<(const T& one, gsl::basic_string_span other) noexcept +bool operator<(const T& one, gsl::basic_string_span other) { gsl::basic_string_span, Extent> tmp(one); return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); @@ -533,7 +531,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator<(gsl::basic_string_span one, const T& other) noexcept +bool operator<(gsl::basic_string_span one, const T& other) { gsl::basic_string_span, Extent> tmp(other); return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); @@ -547,7 +545,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator<(const T& one, gsl::basic_string_span other) noexcept +bool operator<(const T& one, gsl::basic_string_span other) { gsl::basic_string_span, Extent> tmp(one); return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); @@ -558,7 +556,7 @@ bool operator<(const T& one, gsl::basic_string_span other) noexce template , Extent>>::value>> -bool operator<=(gsl::basic_string_span one, const T& other) noexcept +bool operator<=(gsl::basic_string_span one, const T& other) { return !(other < one); } @@ -568,7 +566,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator<=(const T& one, gsl::basic_string_span other) noexcept +bool operator<=(const T& one, gsl::basic_string_span other) { return !(other < one); } @@ -586,7 +584,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator<=(gsl::basic_string_span one, const T& other) noexcept +bool operator<=(gsl::basic_string_span one, const T& other) { return !(other < one); } @@ -599,7 +597,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator<=(const T& one, gsl::basic_string_span other) noexcept +bool operator<=(const T& one, gsl::basic_string_span other) { return !(other < one); } @@ -609,7 +607,7 @@ bool operator<=(const T& one, gsl::basic_string_span other) noexc template , Extent>>::value>> -bool operator>(gsl::basic_string_span one, const T& other) noexcept +bool operator>(gsl::basic_string_span one, const T& other) { return other < one; } @@ -619,7 +617,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator>(const T& one, gsl::basic_string_span other) noexcept +bool operator>(const T& one, gsl::basic_string_span other) { return other < one; } @@ -637,7 +635,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator>(gsl::basic_string_span one, const T& other) noexcept +bool operator>(gsl::basic_string_span one, const T& other) { return other < one; } @@ -650,7 +648,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator>(const T& one, gsl::basic_string_span other) noexcept +bool operator>(const T& one, gsl::basic_string_span other) { return other < one; } @@ -660,7 +658,7 @@ bool operator>(const T& one, gsl::basic_string_span other) noexce template , Extent>>::value>> -bool operator>=(gsl::basic_string_span one, const T& other) noexcept +bool operator>=(gsl::basic_string_span one, const T& other) { return !(one < other); } @@ -670,7 +668,7 @@ template < typename = std::enable_if_t< std::is_convertible, Extent>>::value && !gsl::details::is_basic_string_span::value>> -bool operator>=(const T& one, gsl::basic_string_span other) noexcept +bool operator>=(const T& one, gsl::basic_string_span other) { return !(one < other); } @@ -688,7 +686,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator>=(gsl::basic_string_span one, const T& other) noexcept +bool operator>=(gsl::basic_string_span one, const T& other) { return !(one < other); } @@ -701,7 +699,7 @@ template < std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value>> -bool operator>=(const T& one, gsl::basic_string_span other) noexcept +bool operator>=(const T& one, gsl::basic_string_span other) { return !(one < other); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b5e9bb2..5149d2f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,7 +27,7 @@ else() endif() if (MSVC AND (GSL_CXX_STANDARD EQUAL 17)) - set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus) + set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-) endif() # this interface adds compile options to how the tests are run @@ -49,6 +49,7 @@ target_compile_options(gsl_tests_config INTERFACE -Werror -Wextra -Wno-missing-braces + -Wno-unknown-attributes -Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual @@ -138,6 +139,7 @@ target_compile_options(gsl_tests_config_noexcept INTERFACE -Werror -Wextra -Wno-missing-braces + -Wno-unknown-attributes -Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual diff --git a/tests/algorithm_tests.cpp b/tests/algorithm_tests.cpp index 388d17d..368b53d 100644 --- a/tests/algorithm_tests.cpp +++ b/tests/algorithm_tests.cpp @@ -14,6 +14,12 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch +#endif + #include // for AssertionHandler, StringRef, CHECK, CHE... #include // for copy @@ -29,6 +35,8 @@ struct fail_fast; using namespace std; using namespace gsl; +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("same_type") { // dynamic source and destination span @@ -36,8 +44,8 @@ TEST_CASE("same_type") std::array src{1, 2, 3, 4, 5}; std::array dst{}; - span src_span(src); - span dst_span(dst); + const span src_span(src); + const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -53,8 +61,8 @@ TEST_CASE("same_type") std::array src{1, 2, 3, 4, 5}; std::array dst{}; - span src_span(src); - span dst_span(dst); + const span src_span(src); + const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -70,8 +78,8 @@ TEST_CASE("same_type") std::array src{1, 2, 3, 4, 5}; std::array dst{}; - span src_span(src); - span dst_span(dst); + const span src_span(src); + const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -87,8 +95,8 @@ TEST_CASE("same_type") std::array src{1, 2, 3, 4, 5}; std::array dst{}; - span src_span(src); - span dst_span(dst); + const span src_span(src); + const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -100,6 +108,9 @@ TEST_CASE("same_type") } } + +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("compatible_type") { // dynamic source and destination span @@ -107,8 +118,8 @@ TEST_CASE("compatible_type") std::array src{1, 2, 3, 4, 5}; std::array dst{}; - span src_span(src); - span dst_span(dst); + const span src_span(src); + const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -124,8 +135,8 @@ TEST_CASE("compatible_type") std::array src{1, 2, 3, 4, 5}; std::array dst{}; - span src_span(src); - span dst_span(dst); + const span src_span(src); + const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -141,8 +152,8 @@ TEST_CASE("compatible_type") std::array src{1, 2, 3, 4, 5}; std::array dst{}; - span src_span(src); - span dst_span(dst); + const span src_span(src); + const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -158,8 +169,8 @@ TEST_CASE("compatible_type") std::array src{1, 2, 3, 4, 5}; std::array dst{}; - span src_span(src); - span dst_span(dst); + const span src_span(src); + const span dst_span(dst); copy(src_span, dst_span); copy(src_span, dst_span.subspan(src_span.size())); @@ -195,10 +206,10 @@ TEST_CASE("small_destination_span") std::array src{1, 2, 3, 4}; std::array dst{}; - span src_span_dyn(src); - span src_span_static(src); - span dst_span_dyn(dst); - span dst_span_static(dst); + const span src_span_dyn(src); + const span src_span_static(src); + const span dst_span_dyn(dst); + const span dst_span_static(dst); CHECK_THROWS_AS(copy(src_span_dyn, dst_span_dyn), fail_fast); CHECK_THROWS_AS(copy(src_span_dyn, dst_span_static), fail_fast); diff --git a/tests/assertion_tests.cpp b/tests/assertion_tests.cpp index 25c0089..0c509ad 100644 --- a/tests/assertion_tests.cpp +++ b/tests/assertion_tests.cpp @@ -14,6 +14,12 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch +#endif + #include // for AssertionHandler, StringRef, CHECK, CHECK... #include // for fail_fast (ptr only), Ensures, Expects diff --git a/tests/at_tests.cpp b/tests/at_tests.cpp index 2f9e999..7f07be0 100644 --- a/tests/at_tests.cpp +++ b/tests/at_tests.cpp @@ -14,6 +14,12 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch +#endif + #include // for AssertionHandler, StringRef, CHECK_THROW... #include // for at @@ -23,12 +29,15 @@ #include // for initializer_list #include // for vector + namespace gsl { struct fail_fast; } // namespace gsl using gsl::fail_fast; +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("static_array") { int a[4] = {1, 2, 3, 4}; @@ -45,6 +54,8 @@ TEST_CASE("static_array") CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); } +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("std_array") { std::array a = {1, 2, 3, 4}; @@ -61,6 +72,8 @@ TEST_CASE("std_array") CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); } +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("StdVector") { std::vector a = {1, 2, 3, 4}; @@ -77,9 +90,11 @@ TEST_CASE("StdVector") CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); } +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("InitializerList") { - std::initializer_list a = {1, 2, 3, 4}; + const std::initializer_list a = {1, 2, 3, 4}; for (int i = 0; i < 4; ++i) { CHECK(gsl::at(a, i) == i + 1); @@ -93,6 +108,9 @@ TEST_CASE("InitializerList") } #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute static constexpr bool test_constexpr() { int a1[4] = {1, 2, 3, 4}; @@ -114,3 +132,4 @@ static constexpr bool test_constexpr() static_assert(test_constexpr(), "FAIL"); #endif + diff --git a/tests/bounds_tests.cpp b/tests/bounds_tests.cpp index 1f4b1e2..e586d44 100644 --- a/tests/bounds_tests.cpp +++ b/tests/bounds_tests.cpp @@ -14,6 +14,12 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch +#endif + #include // for AssertionHandler, StringRef, TEST_CASE #include // for static_bounds, static_bounds_dynamic_range_t @@ -32,6 +38,7 @@ namespace void use(std::ptrdiff_t&) {} } +GSL_SUPPRESS(type.1) // NO-FORMAT: attribute TEST_CASE("basic_bounds") { for (auto point : static_bounds{2}) { @@ -44,6 +51,8 @@ TEST_CASE("basic_bounds") } } +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("bounds_basic") { static_bounds<3, 4, 5> b; @@ -53,6 +62,8 @@ TEST_CASE("bounds_basic") x.slice().slice(); } +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("arrayview_iterator") { static_bounds<4, dynamic_range, 2> bounds{3}; @@ -71,6 +82,7 @@ TEST_CASE("arrayview_iterator") #endif } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("bounds_convertible") { static_bounds<7, 4, 2> b1; @@ -97,3 +109,7 @@ TEST_CASE("bounds_convertible") CHECK(b5 == b6); CHECK(b5.size() == b6.size()); } + +#ifdef CONFIRM_COMPILATION_ERRORS +copy(src_span_static, dst_span_static); +#endif diff --git a/tests/byte_tests.cpp b/tests/byte_tests.cpp index 41501ce..d6634bb 100644 --- a/tests/byte_tests.cpp +++ b/tests/byte_tests.cpp @@ -14,6 +14,12 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch +#endif + #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for to_byte, to_integer, byte, operator&, ope... @@ -23,7 +29,6 @@ using namespace gsl; namespace { - TEST_CASE("construction") { { @@ -31,6 +36,7 @@ TEST_CASE("construction") CHECK(static_cast(b) == 4); } + GSL_SUPPRESS(es.49) { const byte b = byte(12); CHECK(static_cast(b) == 12); @@ -46,11 +52,12 @@ TEST_CASE("construction") CHECK(static_cast(b) == 12); } - // waiting for C++17 enum class direct initializer support - //{ - // byte b { 14 }; - // CHECK(static_cast(b) == 14); - //} +#if defined(__cplusplus) && (__cplusplus >= 201703L) + { + const byte b { 14 }; + CHECK(static_cast(b) == 14); + } +#endif } TEST_CASE("bitwise_operations") @@ -114,6 +121,7 @@ int modify_both(gsl::byte & b, int& i) return i; } +GSL_SUPPRESS(type.1) TEST_CASE("aliasing") { int i{0}; @@ -122,3 +130,7 @@ TEST_CASE("aliasing") } } + +#ifdef CONFIRM_COMPILATION_ERRORS +copy(src_span_static, dst_span_static); +#endif diff --git a/tests/multi_span_tests.cpp b/tests/multi_span_tests.cpp index 549dcbe..9c05cb4 100644 --- a/tests/multi_span_tests.cpp +++ b/tests/multi_span_tests.cpp @@ -14,6 +14,13 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch + +#endif + #include // for AssertionHandler, StringRef, CHECK, CHECK... #include // for byte @@ -29,9 +36,10 @@ #include // for string #include // for vector -namespace gsl { +namespace gsl +{ struct fail_fast; -} // namespace gsl +} // namespace gsl using namespace std; using namespace gsl; @@ -44,8 +52,9 @@ struct BaseClass struct DerivedClass : BaseClass { }; -} +} // namespace +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("default_constructor") { { @@ -80,6 +89,7 @@ TEST_CASE("default_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_nullptr_constructor") { { @@ -122,8 +132,8 @@ TEST_CASE("from_nullptr_constructor") } } -TEST_CASE("from_nullptr_length_constructor") -{ +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +TEST_CASE("from_nullptr_length_constructor") { { multi_span s{nullptr, 0}; CHECK((s.length() == 0 && s.data() == nullptr)); @@ -141,25 +151,18 @@ TEST_CASE("from_nullptr_length_constructor") } { -#ifdef CONFIRM_COMPILATION_ERRORS - multi_span s{nullptr, 0}; - CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile -#endif - } - - { - auto workaround_macro = []() { multi_span s{nullptr, 1}; }; + auto workaround_macro = []() { const multi_span s{nullptr, 1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); - auto const_workaround_macro = []() { multi_span cs{nullptr, 1}; }; + auto const_workaround_macro = []() { const multi_span cs{nullptr, 1}; }; CHECK_THROWS_AS(const_workaround_macro(), fail_fast); } { - auto workaround_macro = []() { multi_span s{nullptr, 1}; }; + auto workaround_macro = []() { const multi_span s{nullptr, 1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); - auto const_workaround_macro = []() { multi_span s{nullptr, 1}; }; + auto const_workaround_macro = []() { const multi_span s{nullptr, 1}; }; CHECK_THROWS_AS(const_workaround_macro(), fail_fast); } @@ -170,8 +173,16 @@ TEST_CASE("from_nullptr_length_constructor") multi_span cs{nullptr, 0}; CHECK((cs.length() == 0 && cs.data() == nullptr)); } + + { +#ifdef CONFIRM_COMPILATION_ERRORS + multi_span s{nullptr, 0}; + CHECK((s.length() == 1 && s.data() == nullptr)); // explains why it can't compile +#endif + } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_element_constructor") { int i = 5; @@ -222,6 +233,7 @@ TEST_CASE("from_element_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_pointer_length_constructor") { int arr[4] = {1, 2, 3, 4}; @@ -246,11 +258,12 @@ TEST_CASE("from_pointer_length_constructor") { int* p = nullptr; - auto workaround_macro = [=]() { multi_span s{p, 2}; }; + auto workaround_macro = [=]() { const multi_span s{p, 2}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_pointer_pointer_constructor") { int arr[4] = {1, 2, 3, 4}; @@ -278,29 +291,31 @@ TEST_CASE("from_pointer_pointer_constructor") } { - auto workaround_macro = [&]() { multi_span s{&arr[1], &arr[0]}; }; + auto workaround_macro = [&]() { const multi_span s{&arr[1], &arr[0]}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; - auto workaround_macro = [&]() { multi_span s{&arr[0], p}; }; + auto workaround_macro = [&]() { const multi_span s{&arr[0], p}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; - auto workaround_macro = [&]() { multi_span s{p, p}; }; + auto workaround_macro = [&]() { const multi_span s{p, p}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { int* p = nullptr; - auto workaround_macro = [&]() { multi_span s{&arr[0], p}; }; + auto workaround_macro = [&]() { const multi_span s{&arr[0], p}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("from_array_constructor") { int arr[5] = {1, 2, 3, 4, 5}; @@ -425,6 +440,11 @@ TEST_CASE("from_array_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(i.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("from_dynamic_array_constructor") { double(*arr)[3][4] = new double[100][3][4]; @@ -453,6 +473,7 @@ TEST_CASE("from_dynamic_array_constructor") delete[] arr; } +GSL_SUPPRESS(con.4) // NO-FORMAT: Attribute TEST_CASE("from_std_array_constructor") { std::array arr = {1, 2, 3, 4}; @@ -512,6 +533,7 @@ TEST_CASE("from_std_array_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_const_std_array_constructor") { const std::array arr = {1, 2, 3, 4}; @@ -559,6 +581,7 @@ TEST_CASE("from_const_std_array_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_container_constructor") { std::vector v = {1, 2, 3}; @@ -589,8 +612,7 @@ TEST_CASE("from_container_constructor") multi_span s{cstr}; #endif multi_span cs{cstr}; - CHECK((cs.size() == narrow_cast(cstr.size()) && - cs.data() == cstr.data())); + CHECK((cs.size() == narrow_cast(cstr.size()) && cs.data() == cstr.data())); } { @@ -633,6 +655,8 @@ TEST_CASE("from_container_constructor") } } +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_convertible_span_constructor") { #ifdef CONFIRM_COMPILATION_ERRORS @@ -660,6 +684,7 @@ TEST_CASE("from_convertible_span_constructor") (void) avcd; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("copy_move_and_assignment") { multi_span s1; @@ -688,6 +713,8 @@ void fn(const Bounds&) { static_assert(Bounds::static_size == 60, "static bounds is wrong size"); } + +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_multi_span_reshape") { int a[3][4][5]; @@ -706,11 +733,10 @@ TEST_CASE("as_multi_span_reshape") auto av8 = as_multi_span(av7); CHECK(av8.size() == av6.size()); - for (auto i = 0; i < av8.size(); i++) { - CHECK(av8[i] == 1); - } + for (auto i = 0; i < av8.size(); i++) { CHECK(av8[i] == 1); } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("first") { int arr[5] = {1, 2, 3, 4, 5}; @@ -754,6 +780,7 @@ TEST_CASE("first") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("last") { int arr[5] = {1, 2, 3, 4, 5}; @@ -796,6 +823,7 @@ TEST_CASE("last") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("subspan") { int arr[5] = {1, 2, 3, 4, 5}; @@ -869,6 +897,7 @@ TEST_CASE("subspan") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("rank") { int arr[2] = {1, 2}; @@ -890,6 +919,7 @@ TEST_CASE("rank") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("extent") { { @@ -962,6 +992,7 @@ TEST_CASE("operator_function_call") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("comparison_operators") { { @@ -1074,17 +1105,20 @@ TEST_CASE("comparison_operators") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(i.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("basics") { auto ptr = as_multi_span(new int[10], 10); fill(ptr.begin(), ptr.end(), 99); - for (int num : ptr) { - CHECK(num == 99); - } + for (int num : ptr) { CHECK(num == 99); } delete[] ptr.data(); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST_CASE("bounds_checks") { int arr[10][2]; @@ -1111,25 +1145,24 @@ TEST_CASE("bounds_checks") void overloaded_func(multi_span exp, int expected_value) { - for (auto val : exp) { - CHECK(val == expected_value); - } + for (auto val : exp) { CHECK(val == expected_value); } } void overloaded_func(multi_span exp, char expected_value) { - for (auto val : exp) { - CHECK(val == expected_value); - } + for (auto val : exp) { CHECK(val == expected_value); } } void fixed_func(multi_span exp, int expected_value) { - for (auto val : exp) { - CHECK(val == expected_value); - } + for (auto val : exp) { CHECK(val == expected_value); } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.3) // NO-FORMAT: attribute +GSL_SUPPRESS(r.5) // NO-FORMAT: attribute +GSL_SUPPRESS(r.5) // NO-FORMAT: attribute TEST_CASE("span_parameter_test") { auto data = new int[4][3][5]; @@ -1151,12 +1184,16 @@ TEST_CASE("span_parameter_test") delete[] data; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // false positive, checker does not recognize multi_span yet +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.3) // NO-FORMAT: attribute TEST_CASE("md_access") { auto width = 5, height = 20; auto imgSize = width * height; - auto image_ptr = new int[static_cast(imgSize)][3]; + auto image_ptr = new int[narrow_cast(imgSize)][3]; // size check will be done auto image_view = @@ -1165,8 +1202,10 @@ TEST_CASE("md_access") iota(image_view.begin(), image_view.end(), 1); int expected = 0; - for (auto i = 0; i < height; i++) { - for (auto j = 0; j < width; j++) { + for (auto i = 0; i < height; i++) + { + for (auto j = 0; j < width; j++) + { CHECK(expected + 1 == image_view[i][j][0]); CHECK(expected + 2 == image_view[i][j][1]); CHECK(expected + 3 == image_view[i][j][2]); @@ -1183,6 +1222,11 @@ TEST_CASE("md_access") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute +GSL_SUPPRESS(i.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.3) // NO-FORMAT: attribute TEST_CASE("as_multi_span") { { @@ -1201,6 +1245,7 @@ TEST_CASE("as_multi_span") string str = "ttttttttttttttt"; // size = 15 auto t = str.data(); + GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive (void) t; auto av3 = as_multi_span(str); overloaded_func(as_multi_span(av3, dim(1), dim<3>(), dim<5>()), 't'); @@ -1232,12 +1277,13 @@ TEST_CASE("as_multi_span") auto dv = as_multi_span(vec); (void) dv; -#ifdef CONFIRM_COMPILATION_ERRORS + #ifdef CONFIRM_COMPILATION_ERRORS auto dv2 = as_multi_span(std::move(vec)); -#endif + #endif } } +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST_CASE("empty_spans") { { @@ -1247,7 +1293,8 @@ TEST_CASE("empty_spans") CHECK_THROWS_AS(empty_av[0], fail_fast); CHECK_THROWS_AS(empty_av.begin()[0], fail_fast); CHECK_THROWS_AS(empty_av.cbegin()[0], fail_fast); - for (auto& v : empty_av) { + for (auto& v : empty_av) + { (void) v; CHECK(false); } @@ -1259,17 +1306,25 @@ TEST_CASE("empty_spans") CHECK_THROWS_AS(empty_av[0], fail_fast); CHECK_THROWS_AS(empty_av.begin()[0], fail_fast); CHECK_THROWS_AS(empty_av.cbegin()[0], fail_fast); - for (auto& v : empty_av) { + for (auto& v : empty_av) + { (void) v; CHECK(false); } } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(r.3) // NO-FORMAT: attribute +GSL_SUPPRESS(r.5) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("index_constructor") { auto arr = new int[8]; - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) + { arr[2 * i] = 4 + i; arr[2 * i + 1] = i; } @@ -1291,6 +1346,7 @@ TEST_CASE("index_constructor") delete[] arr; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("index_constructors") { { @@ -1352,17 +1408,18 @@ TEST_CASE("index_constructors") CHECK(i9[0] == 0); } - #ifdef CONFIRM_COMPILATION_ERRORS +#ifdef CONFIRM_COMPILATION_ERRORS { - multi_span_index<3> i1(0, 1); - multi_span_index<3> i2(0, 1, 2, 3); - multi_span_index<3> i3 = {0}; - multi_span_index<3> i4 = {0, 1, 2, 3}; - multi_span_index<1> i5 = {0, 1}; + multi_span_index<3> i1(0, 1); + multi_span_index<3> i2(0, 1, 2, 3); + multi_span_index<3> i3 = {0}; + multi_span_index<3> i4 = {0, 1, 2, 3}; + multi_span_index<1> i5 = {0, 1}; } - #endif +#endif } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("index_operations") { ptrdiff_t a[3] = {0, 1, 2}; @@ -1418,6 +1475,8 @@ TEST_CASE("index_operations") } } +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute void iterate_second_column(multi_span av) { auto length = av.size() / 2; @@ -1426,33 +1485,33 @@ void iterate_second_column(multi_span av) auto section = av.section({0, 1}, {length, 1}); CHECK(section.size() == length); - for (auto i = 0; i < section.size(); ++i) { - CHECK(section[i][0] == av[i][1]); - } + for (auto i = 0; i < section.size(); ++i) { CHECK(section[i][0] == av[i][1]); } - for (auto i = 0; i < section.size(); ++i) { + for (auto i = 0; i < section.size(); ++i) + { auto idx = multi_span_index<2>{i, 0}; // avoid braces inside the CHECK macro CHECK(section[idx] == av[i][1]); } CHECK(section.bounds().index_bounds()[0] == length); CHECK(section.bounds().index_bounds()[1] == 1); - for (auto i = 0; i < section.bounds().index_bounds()[0]; ++i) { - for (auto j = 0; j < section.bounds().index_bounds()[1]; ++j) { + for (auto i = 0; i < section.bounds().index_bounds()[0]; ++i) + { + for (auto j = 0; j < section.bounds().index_bounds()[1]; ++j) + { auto idx = multi_span_index<2>{i, j}; // avoid braces inside the CHECK macro CHECK(section[idx] == av[i][1]); } } auto check_sum = 0; - for (auto i = 0; i < length; ++i) { - check_sum += av[i][1]; - } + for (auto i = 0; i < length; ++i) { check_sum += av[i][1]; } { auto idx = 0; auto sum = 0; - for (auto num : section) { + for (auto num : section) + { CHECK(num == av[idx][1]); sum += num; idx++; @@ -1463,7 +1522,8 @@ void iterate_second_column(multi_span av) { auto idx = length - 1; auto sum = 0; - for (auto iter = section.rbegin(); iter != section.rend(); ++iter) { + for (auto iter = section.rbegin(); iter != section.rend(); ++iter) + { CHECK(*iter == av[idx][1]); sum += *iter; idx--; @@ -1473,6 +1533,7 @@ void iterate_second_column(multi_span av) } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("span_section_iteration") { int arr[4][2] = {{4, 0}, {5, 1}, {6, 2}, {7, 3}}; @@ -1499,15 +1560,18 @@ TEST_CASE("span_section_iteration") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute +GSL_SUPPRESS(r.3) // NO-FORMAT: attribute +GSL_SUPPRESS(r.5) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST_CASE("dynamic_span_section_iteration") { auto height = 4, width = 2; auto size = height * width; - auto arr = new int[static_cast(size)]; - for (auto i = 0; i < size; ++i) { - arr[i] = i; - } + auto arr = new int[narrow_cast(size)]; + for (auto i = 0; i < size; ++i) { arr[i] = i; } auto av = as_multi_span(arr, size); @@ -1531,6 +1595,10 @@ TEST_CASE("dynamic_span_section_iteration") delete[] arr; } +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute +GSL_SUPPRESS(i.11) // NO-FORMAT: attribute TEST_CASE("span_structure_size") { double(*arr)[3][4] = new double[100][3][4]; @@ -1550,6 +1618,7 @@ TEST_CASE("span_structure_size") (void) av2; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("fixed_size_conversions") { int arr[] = {1, 2, 3, 4}; @@ -1631,7 +1700,7 @@ TEST_CASE("fixed_size_conversions") #endif { auto f = [&]() { - multi_span av9 = {arr2, 2}; + const multi_span av9 = {arr2, 2}; (void) av9; }; CHECK_THROWS_AS(f(), fail_fast); @@ -1640,12 +1709,13 @@ TEST_CASE("fixed_size_conversions") // this should fail - we are trying to assign a small dynamic a_v to a fixed_size larger one multi_span av = arr2; auto f = [&]() { - multi_span av2 = av; + const multi_span av2 = av; (void) av2; }; CHECK_THROWS_AS(f(), fail_fast); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_writeable_bytes") { int a[] = {1, 2, 3, 4}; @@ -1674,6 +1744,10 @@ TEST_CASE("as_writeable_bytes") } } + +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("iterator") { int a[] = {1, 2, 3, 4}; @@ -1682,8 +1756,14 @@ TEST_CASE("iterator") multi_span av = a; auto wav = as_writeable_bytes(av); for (auto& b : wav) { +#if defined(__cplusplus) && (__cplusplus >= 201703L) + b = byte{0}; +#else + GSL_SUPPRESS(es.49) b = byte(0); +#endif } + for (std::size_t i = 0; i < 4; ++i) { CHECK(a[i] == 0); } @@ -1699,3 +1779,7 @@ TEST_CASE("iterator") } } } + +#ifdef CONFIRM_COMPILATION_ERRORS +copy(src_span_static, dst_span_static); +#endif \ No newline at end of file diff --git a/tests/no_exception_ensure_tests.cpp b/tests/no_exception_ensure_tests.cpp index 5da021e..3a7f007 100644 --- a/tests/no_exception_ensure_tests.cpp +++ b/tests/no_exception_ensure_tests.cpp @@ -17,10 +17,10 @@ #include // for std::exit #include // for span -int operator_subscript_no_throw() +int operator_subscript_no_throw() noexcept { int arr[10]; - gsl::span sp { arr }; + const gsl::span sp { arr }; return sp[11]; } @@ -30,7 +30,7 @@ void test_terminate() std::exit(0); } -void setup_termination_handler() +void setup_termination_handler() noexcept { #if defined(_MSC_VER) @@ -45,7 +45,7 @@ void setup_termination_handler() } -int main() +int main() noexcept { setup_termination_handler(); operator_subscript_no_throw(); diff --git a/tests/no_exception_throw_tests.cpp b/tests/no_exception_throw_tests.cpp index dd4e994..9c491a6 100644 --- a/tests/no_exception_throw_tests.cpp +++ b/tests/no_exception_throw_tests.cpp @@ -19,7 +19,7 @@ int narrow_no_throw() { - long long bigNumber = 0x0fffffffffffffff; + const long long bigNumber = 0x0fffffffffffffff; return gsl::narrow(bigNumber); } @@ -28,7 +28,7 @@ void test_terminate() std::exit(0); } -void setup_termination_handler() +void setup_termination_handler() noexcept { #if defined(_MSC_VER) diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index 1cb9c10..e522fb5 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -14,6 +14,13 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch + +#endif + #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for not_null, operator<, operator<=, operator> @@ -63,6 +70,7 @@ struct CustomPtr template std::string operator==(CustomPtr const& lhs, CustomPtr const& rhs) { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) == reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -70,6 +78,7 @@ std::string operator==(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator!=(CustomPtr const& lhs, CustomPtr const& rhs) { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) != reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -77,6 +86,7 @@ std::string operator!=(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator<(CustomPtr const& lhs, CustomPtr const& rhs) { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) < reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -84,6 +94,7 @@ std::string operator<(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator>(CustomPtr const& lhs, CustomPtr const& rhs) { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) > reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -91,6 +102,7 @@ std::string operator>(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator<=(CustomPtr const& lhs, CustomPtr const& rhs) { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) <= reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -98,6 +110,7 @@ std::string operator<=(CustomPtr const& lhs, CustomPtr const& rhs) template std::string operator>=(CustomPtr const& lhs, CustomPtr const& rhs) { + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute return reinterpret_cast(lhs.p_) >= reinterpret_cast(rhs.p_) ? "true" : "false"; } @@ -111,9 +124,19 @@ struct NonCopyableNonMovable NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; }; -bool helper(not_null p) { return *p == 12; } -bool helper_const(not_null p) { return *p == 12; } +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +bool helper(not_null p) +{ + return *p == 12; +} +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +bool helper_const(not_null p) +{ + return *p == 12; +} + +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullConstructors") { #ifdef CONFIRM_COMPILATION_ERRORS @@ -143,6 +166,7 @@ TEST_CASE("TestNotNullConstructors") } template +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute void ostream_helper(T v) { not_null p(&v); @@ -173,7 +197,8 @@ TEST_CASE("TestNotNullostream") ostream_helper("string"); } - +GSL_SUPPRESS(type.1) // NO-FORMAT: attribute +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullCasting") { MyBase base; @@ -236,6 +261,7 @@ TEST_CASE("TestNotNullRawPointerComparison") } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullDereferenceOperator") { { @@ -297,6 +323,7 @@ TEST_CASE("TestNotNullSharedPtrComparison") CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullCustomPtrComparison") { int ints[2] = {42, 43}; @@ -331,6 +358,8 @@ TEST_CASE("TestNotNullCustomPtrComparison") #if defined(__cplusplus) && (__cplusplus >= 201703L) + +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestNotNullConstructorTypeDeduction") { { @@ -357,7 +386,7 @@ TEST_CASE("TestNotNullConstructorTypeDeduction") { auto workaround_macro = []() { int* p1 = nullptr; - not_null x{p1}; + const not_null x{p1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } @@ -365,7 +394,7 @@ TEST_CASE("TestNotNullConstructorTypeDeduction") { auto workaround_macro = []() { const int* p1 = nullptr; - not_null x{p1}; + const not_null x{p1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } diff --git a/tests/owner_tests.cpp b/tests/owner_tests.cpp index 94822f5..9fff184 100644 --- a/tests/owner_tests.cpp +++ b/tests/owner_tests.cpp @@ -14,14 +14,25 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch + +#endif + #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for owner using namespace gsl; +GSL_SUPPRESS(f.23) // NO-FORMAT: attribute void f(int* i) { *i += 1; } +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.3) // NO-FORMAT: attribute // TODO: false positive +GSL_SUPPRESS(r.5) // NO-FORMAT: attribute TEST_CASE("basic_test") { owner p = new int(120); diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 67c1b59..081221b 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -14,6 +14,13 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426 26497) // from catch + +#endif + #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for byte @@ -47,6 +54,7 @@ struct DerivedClass : BaseClass }; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("default_constructor") { { @@ -81,6 +89,7 @@ TEST_CASE("default_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("size_optimization") { { @@ -94,56 +103,60 @@ TEST_CASE("size_optimization") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_nullptr_size_constructor") { { - span s{nullptr, static_cast::index_type>(0)}; + span s{nullptr, narrow_cast::index_type>(0)}; CHECK((s.size() == 0 && s.data() == nullptr)); - span cs{nullptr, static_cast::index_type>(0)}; + span cs{nullptr, narrow_cast::index_type>(0)}; CHECK((cs.size() == 0 && cs.data() == nullptr)); } { - span s{nullptr, static_cast::index_type>(0)}; + span s{nullptr, narrow_cast::index_type>(0)}; CHECK((s.size() == 0 && s.data() == nullptr)); - span cs{nullptr, static_cast::index_type>(0)}; + span cs{nullptr, narrow_cast::index_type>(0)}; CHECK((cs.size() == 0 && cs.data() == nullptr)); } { auto workaround_macro = []() { - span s{nullptr, static_cast::index_type>(0)}; + const span s{nullptr, narrow_cast::index_type>(0)}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } { - auto workaround_macro = []() { span s{nullptr, 1}; }; + auto workaround_macro = []() { const span s{nullptr, 1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); - auto const_workaround_macro = []() { span cs{nullptr, 1}; }; + auto const_workaround_macro = []() { const span cs{nullptr, 1}; }; CHECK_THROWS_AS(const_workaround_macro(), fail_fast); } { - auto workaround_macro = []() { span s{nullptr, 1}; }; + auto workaround_macro = []() { const span s{nullptr, 1}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); - auto const_workaround_macro = []() { span s{nullptr, 1}; }; + auto const_workaround_macro = []() { const span s{nullptr, 1}; }; CHECK_THROWS_AS(const_workaround_macro(), fail_fast); } { - span s{nullptr, static_cast::index_type>(0)}; + span s{nullptr, narrow_cast::index_type>(0)}; CHECK((s.size() == 0 && s.data() == nullptr)); - span cs{nullptr, static_cast::index_type>(0)}; + span cs{nullptr, narrow_cast::index_type>(0)}; CHECK((cs.size() == 0 && cs.data() == nullptr)); } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute TEST_CASE("from_pointer_length_constructor") { int arr[4] = {1, 2, 3, 4}; @@ -164,7 +177,7 @@ TEST_CASE("from_pointer_length_constructor") } } { - span s = { &arr[i], 4-i }; + span s = { &arr[i], 4-narrow_cast(i) }; CHECK(s.size() == 4-i); CHECK(s.data() == &arr[i]); CHECK(s.empty() == (4-i == 0)); @@ -186,13 +199,13 @@ TEST_CASE("from_pointer_length_constructor") { int* p = nullptr; - span s{p, static_cast::index_type>(0)}; + span s{p, narrow_cast::index_type>(0)}; CHECK((s.size() == 0 && s.data() == nullptr)); } { int* p = nullptr; - auto workaround_macro = [=]() { span s{p, 2}; }; + auto workaround_macro = [=]() { const span s{p, 2}; }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } @@ -204,7 +217,7 @@ TEST_CASE("from_pointer_length_constructor") { int* p = nullptr; - auto s = make_span(p, static_cast::index_type>(0)); + auto s = make_span(p, narrow_cast::index_type>(0)); CHECK((s.size() == 0 && s.data() == nullptr)); } @@ -215,6 +228,8 @@ TEST_CASE("from_pointer_length_constructor") } } + +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_pointer_pointer_constructor") { int arr[4] = {1, 2, 3, 4}; @@ -291,6 +306,8 @@ 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") { int arr[5] = {1, 2, 3, 4, 5}; @@ -333,7 +350,7 @@ TEST_CASE("from_array_constructor") } #endif { - span s{&(arr2d[0]), 1}; + span s{&arr2d[0], 1}; CHECK((s.size() == 1 && s.data() == &arr2d[0])); } @@ -382,6 +399,10 @@ TEST_CASE("from_array_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute +GSL_SUPPRESS(i.11) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("from_dynamic_array_constructor") { double(*arr)[3][4] = new double[100][3][4]; @@ -399,6 +420,8 @@ TEST_CASE("from_dynamic_array_constructor") delete[] arr; } + +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_std_array_constructor") { std::array arr = {1, 2, 3, 4}; @@ -478,6 +501,7 @@ TEST_CASE("from_std_array_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_const_std_array_constructor") { const std::array arr = {1, 2, 3, 4}; @@ -521,6 +545,7 @@ TEST_CASE("from_const_std_array_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_std_array_const_constructor") { std::array arr = {1, 2, 3, 4}; @@ -561,6 +586,7 @@ TEST_CASE("from_std_array_const_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_container_constructor") { std::vector v = {1, 2, 3}; @@ -653,6 +679,7 @@ TEST_CASE("from_container_constructor") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("from_convertible_span_constructor") { { @@ -690,6 +717,7 @@ TEST_CASE("from_convertible_span_constructor") #endif } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("copy_move_and_assignment") { span s1; @@ -711,6 +739,7 @@ TEST_CASE("copy_move_and_assignment") CHECK((s1.size() == 2 && s1.data() == &arr[1])); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("first") { int arr[5] = {1, 2, 3, 4, 5}; @@ -749,6 +778,7 @@ TEST_CASE("first") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("last") { int arr[5] = {1, 2, 3, 4, 5}; @@ -786,6 +816,7 @@ TEST_CASE("last") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("subspan") { int arr[5] = {1, 2, 3, 4, 5}; @@ -867,6 +898,7 @@ TEST_CASE("subspan") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("at_call") { int arr[4] = {1, 2, 3, 4}; @@ -886,6 +918,7 @@ TEST_CASE("at_call") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("operator_function_call") { int arr[4] = {1, 2, 3, 4}; @@ -905,6 +938,7 @@ TEST_CASE("operator_function_call") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("iterator_default_init") { span::iterator it1; @@ -912,6 +946,7 @@ TEST_CASE("iterator_default_init") CHECK(it1 == it2); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("const_iterator_default_init") { span::const_iterator it1; @@ -919,6 +954,7 @@ TEST_CASE("const_iterator_default_init") CHECK(it1 == it2); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("iterator_conversions") { span::iterator badIt; @@ -941,6 +977,7 @@ TEST_CASE("iterator_conversions") CHECK(cit3 == s.cend()); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("iterator_comparisons") { int a[] = {1, 2, 3, 4}; @@ -988,6 +1025,7 @@ TEST_CASE("iterator_comparisons") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("begin_end") { { @@ -1043,6 +1081,7 @@ TEST_CASE("begin_end") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("cbegin_cend") { { @@ -1095,6 +1134,7 @@ TEST_CASE("cbegin_cend") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("rbegin_rend") { { @@ -1137,6 +1177,7 @@ TEST_CASE("rbegin_rend") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("crbegin_crend") { { @@ -1176,6 +1217,7 @@ TEST_CASE("crbegin_crend") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("comparison_operators") { { @@ -1296,6 +1338,7 @@ TEST_CASE("comparison_operators") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_bytes") { int a[] = {1, 2, 3, 4}; @@ -1326,6 +1369,7 @@ TEST_CASE("as_bytes") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_writeable_bytes") { int a[] = {1, 2, 3, 4}; @@ -1359,6 +1403,7 @@ TEST_CASE("as_writeable_bytes") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("fixed_size_conversions") { int arr[] = {1, 2, 3, 4}; @@ -1389,7 +1434,7 @@ TEST_CASE("fixed_size_conversions") { span s = arr; auto f = [&]() { - span s2 = s; + const span s2 = s; static_cast(s2); }; CHECK_THROWS_AS(f(), fail_fast); @@ -1399,7 +1444,7 @@ TEST_CASE("fixed_size_conversions") // you can convert statically { - const span s2 = {arr, 2}; + const span s2 = {&arr[0], 2}; static_cast(s2); } { @@ -1428,7 +1473,7 @@ TEST_CASE("fixed_size_conversions") #endif { auto f = [&]() { - span _s4 = {arr2, 2}; + const span _s4 = {arr2, 2}; static_cast(_s4); }; CHECK_THROWS_AS(f(), fail_fast); @@ -1437,12 +1482,13 @@ TEST_CASE("fixed_size_conversions") // this should fail - we are trying to assign a small dynamic span to a fixed_size larger one span av = arr2; auto f = [&]() { - span _s4 = av; + const span _s4 = av; static_cast(_s4); }; CHECK_THROWS_AS(f(), fail_fast); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("interop_with_std_regex") { char lat[] = {'1', '2', '3', '4', '5', '6', 'E', 'F', 'G'}; @@ -1466,6 +1512,7 @@ TEST_CASE("interop_with_std_regex") CHECK(match[0].second == (f_it + 1)); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("interop_with_gsl_at") { int arr[5] = {1, 2, 3, 4, 5}; @@ -1479,3 +1526,4 @@ TEST_CASE("default_constructible") CHECK((std::is_default_constructible>::value)); CHECK((!std::is_default_constructible>::value)); } + diff --git a/tests/strided_span_tests.cpp b/tests/strided_span_tests.cpp index 8719336..42eff7a 100644 --- a/tests/strided_span_tests.cpp +++ b/tests/strided_span_tests.cpp @@ -14,6 +14,13 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch + +#endif + #include // for AssertionHandler, StringRef, CHECK, CHECK... #include // for byte @@ -71,6 +78,7 @@ TEST_CASE("span_section") CHECK((av_section_2[{1, 0}] == 34)); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_constructors") { // Check stride constructor @@ -271,6 +279,7 @@ TEST_CASE("strided_span_constructors") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_slice") { std::vector data(5 * 10); @@ -297,6 +306,7 @@ TEST_CASE("strided_span_slice") CHECK(sav[4][9] == 49); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_column_major") { // strided_span may be used to accommodate more peculiar @@ -329,6 +339,7 @@ TEST_CASE("strided_span_column_major") CHECK((cm_sec[{2, 1}] == 15)); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_bounds") { int arr[] = {0, 1, 2, 3}; @@ -445,6 +456,7 @@ TEST_CASE("strided_span_bounds") #endif } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_type_conversion") { int arr[] = {0, 1, 2, 3}; @@ -542,6 +554,8 @@ TEST_CASE("strided_span_type_conversion") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST_CASE("empty_strided_spans") { { @@ -574,6 +588,8 @@ TEST_CASE("empty_strided_spans") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute void iterate_every_other_element(multi_span av) { // pick every other element @@ -599,6 +615,7 @@ void iterate_every_other_element(multi_span av) } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("strided_span_section_iteration") { int arr[8] = {4, 0, 5, 1, 6, 2, 7, 3}; @@ -616,6 +633,11 @@ TEST_CASE("strided_span_section_iteration") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.3) // NO-FORMAT: attribute +GSL_SUPPRESS(r.5) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("dynamic_strided_span_section_iteration") { auto arr = new int[8]; @@ -630,6 +652,9 @@ TEST_CASE("dynamic_strided_span_section_iteration") delete[] arr; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute // TODO: does not work void iterate_second_slice(multi_span av) { const int expected[6] = {2, 3, 10, 11, 18, 19}; @@ -656,6 +681,9 @@ void iterate_second_slice(multi_span(sizeof(int)) * 12 / d2; // convert to 4x12 array of bytes - auto av = as_multi_span(as_bytes(as_multi_span(arr, 4)), dim(d1), dim(d2)); + auto av = as_multi_span(as_bytes(as_multi_span(&arr[0], 4)), dim(d1), dim(d2)); CHECK(av.bounds().index_bounds()[0] == 4); CHECK(av.bounds().index_bounds()[1] == 12); diff --git a/tests/string_span_tests.cpp b/tests/string_span_tests.cpp index c0b5b19..fd3e3e6 100644 --- a/tests/string_span_tests.cpp +++ b/tests/string_span_tests.cpp @@ -14,6 +14,13 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch + +#endif + #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for Expects, fail_fast (ptr only) @@ -37,6 +44,8 @@ namespace generic { template +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute +GSL_SUPPRESS(f.23) // NO-FORMAT: attribute auto strlen(const CharT* s) { auto p = s; @@ -45,13 +54,15 @@ auto strlen(const CharT* s) } template +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute auto strnlen(const CharT* s, std::size_t n) { - return std::find(s, s + n, CharT(0)) - s; + return std::find(s, s + n, CharT{0}) - s; } } // namespace generic +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestLiteralConstruction") { cwstring_span<> v = ensure_z(L"Hello"); @@ -61,6 +72,7 @@ TEST_CASE("TestLiteralConstruction") wstring_span<> v2 = ensure0(L"Hello"); #endif } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConstructFromStdString") { @@ -69,6 +81,7 @@ TEST_CASE("TestConstructFromStdString") CHECK(v.length() == static_cast::index_type>(s.length())); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConstructFromStdVector") { std::vector vec(5, 'h'); @@ -76,6 +89,7 @@ TEST_CASE("TestConstructFromStdVector") CHECK(v.length() == static_cast::index_type>(vec.size())); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestStackArrayConstruction") { wchar_t stack_string[] = L"Hello"; @@ -101,6 +115,7 @@ TEST_CASE("TestStackArrayConstruction") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConstructFromConstCharPointer") { const char* s = "Hello"; @@ -108,6 +123,7 @@ TEST_CASE("TestConstructFromConstCharPointer") CHECK(v.length() == 5); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConversionToConst") { char stack_string[] = "Hello"; @@ -116,6 +132,7 @@ TEST_CASE("TestConversionToConst") CHECK(v.length() == v2.length()); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestConversionFromConst") { char stack_string[] = "Hello"; @@ -127,6 +144,7 @@ TEST_CASE("TestConversionFromConst") #endif } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestToString") { auto s = gsl::to_string(cstring_span<>{}); @@ -139,6 +157,7 @@ TEST_CASE("TestToString") CHECK(s2.length() == 5); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("TestToBasicString") { auto s = gsl::to_basic_string, ::std::allocator>( @@ -152,6 +171,8 @@ TEST_CASE("TestToBasicString") CHECK(s2.length() == 5); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("EqualityAndImplicitConstructors") { { @@ -378,6 +399,8 @@ TEST_CASE("EqualityAndImplicitConstructors") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("ComparisonAndImplicitConstructors") { { @@ -448,6 +471,12 @@ TEST_CASE("ComparisonAndImplicitConstructors") CHECK(span >= string_span<>(vec)); } } + +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(r.11) // NO-FORMAT: attribute +GSL_SUPPRESS(r.3) // NO-FORMAT: attribute +GSL_SUPPRESS(r.5) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("ConstrutorsEnsureZ") { // remove z from literals @@ -478,6 +507,8 @@ TEST_CASE("ConstrutorsEnsureZ") } } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("Constructors") { // creating cstring_span @@ -884,6 +915,8 @@ czstring_span<> CreateTempName(string_span<> span) return {ret}; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("zstring") { @@ -904,7 +937,7 @@ TEST_CASE("zstring") char buf[1]; buf[0] = 'a'; - auto workaround_macro = [&]() { zstring_span<> zspan({buf, 1}); }; + auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } @@ -938,6 +971,8 @@ cwzstring_span<> CreateTempNameW(wstring_span<> span) return {ret}; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("wzstring") { @@ -958,7 +993,7 @@ TEST_CASE("wzstring") wchar_t buf[1]; buf[0] = L'a'; - const auto workaround_macro = [&]() { wzstring_span<> zspan({buf, 1}); }; + const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } @@ -992,6 +1027,8 @@ cu16zstring_span<> CreateTempNameU16(u16string_span<> span) return {ret}; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("u16zstring") { @@ -1012,7 +1049,7 @@ TEST_CASE("u16zstring") char16_t buf[1]; buf[0] = u'a'; - const auto workaround_macro = [&]() { u16zstring_span<> zspan({buf, 1}); }; + const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } @@ -1046,6 +1083,8 @@ cu32zstring_span<> CreateTempNameU32(u32string_span<> span) return {ret}; } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST_CASE("u32zstring") { @@ -1066,7 +1105,7 @@ TEST_CASE("u32zstring") char32_t buf[1]; buf[0] = u'a'; - const auto workaround_macro = [&]() { u32zstring_span<> zspan({buf, 1}); }; + const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); }; CHECK_THROWS_AS(workaround_macro(), fail_fast); } @@ -1090,6 +1129,8 @@ TEST_CASE("Issue305") CHECK(foo["bar"] == 1); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("char16_t type") { gsl::cu16string_span<> ss1 = gsl::ensure_z(u"abc"); @@ -1131,6 +1172,8 @@ TEST_CASE("char16_t type") CHECK(ss8 != ss9); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute TEST_CASE("char32_t type") { gsl::cu32string_span<> ss1 = gsl::ensure_z(U"abc"); @@ -1168,6 +1211,7 @@ TEST_CASE("char32_t type") CHECK(ss8 != ss9); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_bytes") { cwzstring_span<> v(L"qwerty"); @@ -1177,6 +1221,7 @@ TEST_CASE("as_bytes") CHECK(bs.size() == s.size_bytes()); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("as_writeable_bytes") { wchar_t buf[]{L"qwerty"}; diff --git a/tests/test.cpp b/tests/test.cpp index bae194d..dbdebb6 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -15,4 +15,12 @@ /////////////////////////////////////////////////////////////////////////////// #define CATCH_CONFIG_MAIN + +#ifdef _MSC_VER + +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26401 26409 26415 26418 26426 26429 26432 26433 26434 26435 26436 26439 26440 26443 26444 26446 26447 26451 26460 26461 26466 26472 26481 26482 26485 26492 26493 26494 26495 26496 26497) // from catch +#endif // _MSC_VER + #include diff --git a/tests/utils_tests.cpp b/tests/utils_tests.cpp index 587b0a1..05f8d0f 100644 --- a/tests/utils_tests.cpp +++ b/tests/utils_tests.cpp @@ -14,6 +14,13 @@ // /////////////////////////////////////////////////////////////////////////////// +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch + +#endif + #include // for AssertionHandler, StringRef, CHECK, TEST_... #include // for narrow, finally, narrow_cast, narrowing_e... @@ -85,6 +92,7 @@ TEST_CASE("finally_function_ptr") CHECK(j == 1); } +GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST_CASE("narrow_cast") { int n = 120; @@ -96,6 +104,7 @@ TEST_CASE("narrow_cast") CHECK(uc == 44); } +GSL_SUPPRESS(con.5) // NO-FORMAT: attribute TEST_CASE("narrow") { int n = 120; From f1a2e91e4e08a24b1712ee4484ef534f502bead5 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Sun, 12 Aug 2018 21:45:39 -0700 Subject: [PATCH 06/13] fixed typo --- include/gsl/gsl_assert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gsl/gsl_assert b/include/gsl/gsl_assert index 321bf20..3c952e6 100644 --- a/include/gsl/gsl_assert +++ b/include/gsl/gsl_assert @@ -22,7 +22,7 @@ // // make suppress attributes parse for some compilers -// Hopefully temporary until suppresion stardization occurs +// Hopefully temporary until suppresion standardization occurs // #if defined (_MSC_VER) #define GSL_SUPPRESS(x) [[gsl::suppress(x)]] From 831584d94778e360d1616edc8b1562516795a853 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Mon, 13 Aug 2018 02:22:02 -0700 Subject: [PATCH 07/13] Dev/annagrin/make not null (#711) * Added c++17 test configurations for clang5.0 and clang6.0 * Added make_not_null helper to create a not_null Introduction of explicit not_null constructor made it cumbersome to create not_nulls in c++14. Adding make_not_null helper. Usage (see tests): int i = 42; auto x = make_not_null(&i); helper(make_not_null(&i)); helper_const(make_not_null(&i)); * Added std::forward to make_not_null, fixed some code analysis warnings * Fix build break in VS2015 Release configuration * Fix build break in VS2015 Release configuration --- include/gsl/pointers | 5 ++++ tests/notnull_tests.cpp | 61 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/include/gsl/pointers b/include/gsl/pointers index 69499d6..a338856 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -119,6 +119,11 @@ private: T ptr_; }; +template +auto make_not_null(T&& t) { + return gsl::not_null>>{std::forward(t)}; +} + template std::ostream& operator<<(std::ostream& os, const not_null& val) { diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index e522fb5..673eab8 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -19,6 +19,8 @@ // so people aren't annoyed by them when running the tool. #pragma warning(disable : 26440 26426) // from catch +// Fix VS2015 build breaks in Release +#pragma warning(disable : 4702) // unreachable code #endif #include // for AssertionHandler, StringRef, CHECK, TEST_... @@ -32,6 +34,8 @@ #include // for basic_string, operator==, string, operator<< #include // for type_info + + namespace gsl { struct fail_fast; } // namespace gsl @@ -416,4 +420,61 @@ TEST_CASE("TestNotNullConstructorTypeDeduction") } #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) +TEST_CASE("TestMakeNotNull") +{ + { + int i = 42; + + const auto x = make_not_null(&i); + helper(make_not_null(&i)); + helper_const(make_not_null(&i)); + + CHECK(*x == 42); + } + + { + int i = 42; + int* p = &i; + + const auto x = make_not_null(p); + helper(make_not_null(p)); + helper_const(make_not_null(p)); + + CHECK(*x == 42); + } + + { + const auto workaround_macro = []() { + int* p1 = nullptr; + const auto x = make_not_null(p1); + CHECK(*x == 42); + }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + const auto workaround_macro = []() { + const int* p1 = nullptr; + const auto x = make_not_null(p1); + CHECK(*x == 42); + }; + CHECK_THROWS_AS(workaround_macro(), fail_fast); + } + + { + int* p = nullptr; + + CHECK_THROWS_AS(helper(make_not_null(p)), fail_fast); + CHECK_THROWS_AS(helper_const(make_not_null(p)), fail_fast); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + CHECK_THROWS_AS(make_not_null(nullptr), fail_fast); + CHECK_THROWS_AS(helper(make_not_null(nullptr)), fail_fast); + CHECK_THROWS_AS(helper_const(make_not_null(nullptr)), fail_fast); + } +#endif +} + static_assert(std::is_nothrow_move_constructible>::value, "not_null must be no-throw move constructible"); From 6241b3faa6626e6ec735dfd74ae87e92123bf191 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Mon, 13 Aug 2018 09:55:48 -0700 Subject: [PATCH 08/13] Dev/annagrin/sloppy not null (#712) * Added c++17 test configurations for clang5.0 and clang6.0 * added transition helper sloppy_not_null * Moved gsl_transition to a samples folder * Fixed build break and static analysis warnings --- samples/gsl_transition | 120 ++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/no_exception_throw_tests.cpp | 1 + tests/notnull_tests.cpp | 18 ++--- tests/sloppy_notnull_tests.cpp | 124 +++++++++++++++++++++++++++++ 5 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 samples/gsl_transition create mode 100644 tests/sloppy_notnull_tests.cpp diff --git a/samples/gsl_transition b/samples/gsl_transition new file mode 100644 index 0000000..5e713c4 --- /dev/null +++ b/samples/gsl_transition @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_TRANSITION_H +#define GSL_TRANSITION_H + +#include // for Ensures, Expects +#include // for gsl::not_null + +#if defined(_MSC_VER) && _MSC_VER < 1910 +#pragma push_macro("constexpr") +#define constexpr /*constexpr*/ + +#endif // defined(_MSC_VER) && _MSC_VER < 1910 + +namespace gsl_helpers +{ +// +// sloppy_not_null +// +// Restricts a pointer or smart pointer to only hold non-null values, +// +// - provides a sloppy (i.e. no explicit contructor from T) wrapper of gsl::not_null +// - is temporary, only to be used to incrementally transition of code +// using older version of gsl::not_null to the new one that made the constructor explicit +// +// To make the transition: +// +// - replace all occurences of gsl::not_null in your code by sloppy_not_null +// - compile - compilation should be successful +// - replace some sloppy_not_nulls by gsl::not_null, fix compilation erros, +// redesign as needed, compile and test +// - repeat until no sloppy_not_nulls remain +// +template +class sloppy_not_null: public gsl::not_null +{ +public: + + template ::value>> + constexpr sloppy_not_null(U&& u) : + gsl::not_null(std::forward(u)) + {} + + template ::value>> + constexpr sloppy_not_null(T u) : + gsl::not_null(u) + {} + + template ::value>> + constexpr sloppy_not_null(const gsl::not_null& other) : + gsl::not_null(other) + {} + + sloppy_not_null(sloppy_not_null&& other) = default; + sloppy_not_null(const sloppy_not_null& other) = default; + sloppy_not_null& operator=(const sloppy_not_null& other) = default; + sloppy_not_null& operator=(const gsl::not_null& other) + { + gsl::not_null::operator=(other); + return *this; + } + + // prevents compilation when someone attempts to assign a null pointer constant + sloppy_not_null(std::nullptr_t) = delete; + sloppy_not_null& operator=(std::nullptr_t) = delete; + + // unwanted operators...pointers only point to single objects! + sloppy_not_null& operator++() = delete; + sloppy_not_null& operator--() = delete; + sloppy_not_null operator++(int) = delete; + sloppy_not_null operator--(int) = delete; + sloppy_not_null& operator+=(std::ptrdiff_t) = delete; + sloppy_not_null& operator-=(std::ptrdiff_t) = delete; + void operator[](std::ptrdiff_t) const = delete; +}; + +// more unwanted operators +template +std::ptrdiff_t operator-(const sloppy_not_null&, const sloppy_not_null&) = delete; +template +sloppy_not_null operator-(const sloppy_not_null&, std::ptrdiff_t) = delete; +template +sloppy_not_null operator+(const sloppy_not_null&, std::ptrdiff_t) = delete; +template +sloppy_not_null operator+(std::ptrdiff_t, const sloppy_not_null&) = delete; + +} // namespace gsl + +namespace std +{ +template +struct hash> +{ + std::size_t operator()(const gsl_helpers::sloppy_not_null& value) const { return hash{}(value); } +}; + +} // namespace std + +#if defined(_MSC_VER) && _MSC_VER < 1910 +#undef constexpr +#pragma pop_macro("constexpr") + +#endif // defined(_MSC_VER) && _MSC_VER < 1910 + +#endif // GSL_TRANSITION_H + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5149d2f..2d37a51 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -107,6 +107,7 @@ add_gsl_test(utils_tests) add_gsl_test(owner_tests) add_gsl_test(byte_tests) add_gsl_test(algorithm_tests) +add_gsl_test(sloppy_notnull_tests) # No exception tests diff --git a/tests/no_exception_throw_tests.cpp b/tests/no_exception_throw_tests.cpp index 9c491a6..e9f4dac 100644 --- a/tests/no_exception_throw_tests.cpp +++ b/tests/no_exception_throw_tests.cpp @@ -16,6 +16,7 @@ #include // for std::exit #include // for narrow +#include // for get_terminate int narrow_no_throw() { diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index 673eab8..668c0a2 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -25,7 +25,7 @@ #include // for AssertionHandler, StringRef, CHECK, TEST_... -#include // for not_null, operator<, operator<=, operator> +#include // for not_null, operator<, operator<=, operator> #include // for addressof #include // for shared_ptr, make_shared, operator<, opera... @@ -34,11 +34,10 @@ #include // for basic_string, operator==, string, operator<< #include // for type_info - - -namespace gsl { +namespace gsl +{ struct fail_fast; -} // namespace gsl +} // namespace gsl using namespace gsl; @@ -166,7 +165,7 @@ TEST_CASE("TestNotNullConstructors") #ifdef GSL_THROW_ON_CONTRACT_VIOLATION int* pi = nullptr; CHECK_THROWS_AS(not_null(pi), fail_fast); -#endif +#endif } template @@ -262,7 +261,6 @@ TEST_CASE("TestNotNullRawPointerComparison") CHECK((NotNull1(p1) <= NotNull1(p1)) == true); CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); - } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute @@ -272,12 +270,12 @@ TEST_CASE("TestNotNullDereferenceOperator") auto sp1 = std::make_shared(); using NotNullSp1 = not_null; - CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1))); + CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1))); CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1)); } { - int ints[1] = { 42 }; + int ints[1] = {42}; CustomPtr p1(&ints[0]); using NotNull1 = not_null; @@ -360,7 +358,6 @@ TEST_CASE("TestNotNullCustomPtrComparison") CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); } - #if defined(__cplusplus) && (__cplusplus >= 201703L) GSL_SUPPRESS(con.4) // NO-FORMAT: attribute @@ -478,3 +475,4 @@ TEST_CASE("TestMakeNotNull") } static_assert(std::is_nothrow_move_constructible>::value, "not_null must be no-throw move constructible"); + diff --git a/tests/sloppy_notnull_tests.cpp b/tests/sloppy_notnull_tests.cpp new file mode 100644 index 0000000..51983f5 --- /dev/null +++ b/tests/sloppy_notnull_tests.cpp @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +// blanket turn off warnings from CppCoreCheck from catch +// so people aren't annoyed by them when running the tool. +#pragma warning(disable : 26440 26426) // from catch + +// Fix VS2015 build breaks in Release +#pragma warning(disable : 4702) // unreachable code +#endif + +#include // for AssertionHandler, StringRef, CHECK, TEST_... + +#include // for not_null, operator<, operator<=, operator> +#include // for sloppy_not_null + +namespace gsl +{ +struct fail_fast; +} // namespace gsl + +using namespace gsl; +using namespace gsl_helpers; + +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +bool helper(not_null p) { return *p == 12; } +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +bool helper_const(not_null p) { return *p == 12; } + +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +bool sloppy_helper(sloppy_not_null p) { return *p == 12; } +GSL_SUPPRESS(f.4) // NO-FORMAT: attribute +bool sloppy_helper_const(sloppy_not_null p) { return *p == 12; } + +TEST_CASE("TestSloppyNotNull") +{ + { + // raw ptr <-> sloppy_not_null + int x = 42; + + const sloppy_not_null snn = &x; + + sloppy_helper(&x); + sloppy_helper_const(&x); + + CHECK(*snn == 42); + } + + { + // sloppy_not_null -> sloppy_not_null + int x = 42; + + sloppy_not_null snn1{&x}; + const sloppy_not_null snn2{&x}; + + sloppy_helper(snn1); + sloppy_helper_const(snn1); + + CHECK(snn1 == snn2); + } + + { + // sloppy_not_null -> not_null + int x = 42; + + sloppy_not_null snn{&x}; + + const not_null nn1 = snn; + const not_null nn2{snn}; + + helper(snn); + helper_const(snn); + + CHECK(snn == nn1); + CHECK(snn == nn2); + } + + { + // not_null -> sloppy_not_null + int x = 42; + + not_null nn{&x}; + + const sloppy_not_null snn1{nn}; + const sloppy_not_null snn2 = nn; + + sloppy_helper(nn); + sloppy_helper_const(nn); + + CHECK(snn1 == nn); + CHECK(snn2 == nn); + + std::hash> hash_snn; + std::hash> hash_nn; + + CHECK(hash_nn(snn1) == hash_nn(nn)); + CHECK(hash_snn(snn1) == hash_nn(nn)); + CHECK(hash_nn(snn1) == hash_nn(snn2)); + CHECK(hash_snn(snn1) == hash_snn(nn)); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + sloppy_not_null p{nullptr}; + } +#endif +} + +static_assert(std::is_nothrow_move_constructible>::value, + "sloppy_not_null must be no-throw move constructible"); From 5016ce4a4deba4cb577cd836b16a1fc7a991b161 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Fri, 17 Aug 2018 11:36:06 -0700 Subject: [PATCH 09/13] Dev/annagrin/opt neg branch (#721) * Added c++17 test configurations for clang5.0 and clang6.0 * Added optimization that removes a branch from span::operator[] * minor beauty fix * added a better message for the optimization, fixed signed/unsigned warning * better check fir wrap-around possibility --- include/gsl/span | 64 ++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index 3e5a053..b3f4f83 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -46,8 +46,8 @@ #define constexpr /*constexpr*/ #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND -#endif // _MSC_VER < 1910 -#endif // _MSC_VER +#endif // _MSC_VER < 1910 +#endif // _MSC_VER // See if we have enough C++17 power to use a static constexpr data member // without needing an out-of-line definition @@ -142,15 +142,13 @@ namespace details constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept : span_(span), index_(idx) - { - } + {} friend span_iterator; template * = nullptr> constexpr span_iterator(const span_iterator& other) noexcept : span_iterator(other.span_, other.index_) - { - } + {} GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator*() const @@ -332,8 +330,7 @@ namespace details template explicit constexpr extent_type(extent_type ext) : size_(ext.size()) - { - } + {} explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); } @@ -383,35 +380,30 @@ public: // since "std::enable_if_t" is ill-formed when Extent is greater than 0. class = std::enable_if_t<(Dependent || Extent <= 0)>> constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) - { - } + {} constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {} constexpr span(pointer firstElem, pointer lastElem) : storage_(firstElem, std::distance(firstElem, lastElem)) - { - } + {} template constexpr span(element_type (&arr)[N]) noexcept : storage_(KnownNotNull{&arr[0]}, details::extent_type()) - { - } + {} template > // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr span(std::array& arr) noexcept : storage_(&arr[0], details::extent_type()) - { - } + {} template // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr span(const std::array, N>& arr) noexcept : storage_(&arr[0], details::extent_type()) - { - } + {} // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement // on Container to be a contiguous sequence container. @@ -422,8 +414,7 @@ public: std::is_convertible().data())>::value>> constexpr span(Container& cont) : span(cont.data(), narrow(cont.size())) - { - } + {} template ().data())>::value>> constexpr span(const Container& cont) : span(cont.data(), narrow(cont.size())) - { - } + {} constexpr span(const span& other) noexcept = default; @@ -444,8 +434,7 @@ public: details::is_allowed_element_type_conversion::value>> constexpr span(const span& other) : storage_(other.data(), details::extent_type(other.size())) - { - } + {} ~span() noexcept = default; constexpr span& operator=(const span& other) noexcept = default; @@ -506,7 +495,7 @@ public: GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute constexpr reference operator[](index_type idx) const { - Expects(idx >= 0 && idx < storage_.size()); + Expects(CheckRange(idx, storage_.size())); return data()[idx]; } @@ -536,7 +525,7 @@ public: #ifdef _MSC_VER // Tell MSVC how to unwrap spans in range-based-for constexpr pointer _Unchecked_begin() const noexcept { return data(); } - constexpr pointer _Unchecked_end() const noexcept + constexpr pointer _Unchecked_end() const noexcept { GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute return data() + size(); @@ -544,6 +533,29 @@ public: #endif // _MSC_VER private: + static bool CheckRange(index_type idx, index_type size) + { + // Optimization: + // + // idx >= 0 && idx < size + // => + // static_cast(idx) < static_cast(size) + // + // because size >=0 by span construction, and negative idx will + // wrap around to a value always greater than size when casted. + + // check if we have enough space to wrap around + if (narrow_cast(std::numeric_limits::max()) < + narrow_cast(std::numeric_limits::max())) + { + return narrow_cast(idx) < narrow_cast(size); + } + else + { + return idx >= 0 && idx < size; + } + } + // Needed to remove unnecessary null check in subspans struct KnownNotNull { From 55aad0ab6d99158ad7019b9a03db773eabd71c11 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Fri, 17 Aug 2018 11:36:26 -0700 Subject: [PATCH 10/13] Dev/annagrin/explicit notnull transition description (#722) * Added c++17 test configurations for clang5.0 and clang6.0 * Improved description how to make transition to explicit not_null constructor --- samples/gsl_transition | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/samples/gsl_transition b/samples/gsl_transition index 5e713c4..3f5bf6c 100644 --- a/samples/gsl_transition +++ b/samples/gsl_transition @@ -40,6 +40,16 @@ namespace gsl_helpers // To make the transition: // // - replace all occurences of gsl::not_null in your code by sloppy_not_null +// variant: rename gsl::not_null by NotNull by including the following in your code, +// foe example, in a common include file: +// +// template +// using NotNull = gsl::not_null; +// +// compile using old version of GSL +// change GSL version and replace gsl::not_null by gsl_helpers::sloppy_not_null +// in the added code lines above +// // - compile - compilation should be successful // - replace some sloppy_not_nulls by gsl::not_null, fix compilation erros, // redesign as needed, compile and test From 86be2366c73a19b77cc7a6674cc0e3d118efcdf9 Mon Sep 17 00:00:00 2001 From: Stephan Dollberg Date: Fri, 17 Aug 2018 19:47:03 +0100 Subject: [PATCH 11/13] Fix #717 - Add empty() to strided_span (#718) --- include/gsl/multi_span | 2 ++ tests/strided_span_tests.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/include/gsl/multi_span b/include/gsl/multi_span index a7c96ce..c8f4aae 100644 --- a/include/gsl/multi_span +++ b/include/gsl/multi_span @@ -1931,6 +1931,8 @@ public: constexpr pointer data() const noexcept { return data_; } + constexpr bool empty() const noexcept { return this->size() == 0; } + constexpr explicit operator bool() const noexcept { return data_ != nullptr; } constexpr iterator begin() const { return iterator{this, true}; } diff --git a/tests/strided_span_tests.cpp b/tests/strided_span_tests.cpp index 42eff7a..2310f5b 100644 --- a/tests/strided_span_tests.cpp +++ b/tests/strided_span_tests.cpp @@ -67,12 +67,14 @@ TEST_CASE("span_section") const multi_span av = as_multi_span(multi_span{data}, dim<5>(), dim<10>()); const strided_span av_section_1 = av.section({1, 2}, {3, 4}); + CHECK(!av_section_1.empty()); CHECK((av_section_1[{0, 0}] == 12)); CHECK((av_section_1[{0, 1}] == 13)); CHECK((av_section_1[{1, 0}] == 22)); CHECK((av_section_1[{2, 3}] == 35)); const strided_span av_section_2 = av_section_1.section({1, 2}, {2, 2}); + CHECK(!av_section_2.empty()); CHECK((av_section_2[{0, 0}] == 24)); CHECK((av_section_2[{0, 1}] == 25)); CHECK((av_section_2[{1, 0}] == 34)); @@ -563,6 +565,7 @@ TEST_CASE("empty_strided_spans") strided_span empty_sav{empty_av, {0, 1}}; CHECK(empty_sav.bounds().index_bounds() == multi_span_index<1>{0}); + CHECK(empty_sav.empty()); CHECK_THROWS_AS(empty_sav[0], fail_fast); CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); From 585f48ce55c720a3f812f79ef57596e67f52eb89 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Sun, 19 Aug 2018 16:27:30 -0700 Subject: [PATCH 12/13] better check for branch opt (#724) * Added c++17 test configurations for clang5.0 and clang6.0 * Simplified optimization in span::operator[] --- include/gsl/span | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index b3f4f83..a4f9256 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -545,8 +545,7 @@ private: // wrap around to a value always greater than size when casted. // check if we have enough space to wrap around - if (narrow_cast(std::numeric_limits::max()) < - narrow_cast(std::numeric_limits::max())) + if (sizeof(index_type) <= sizeof(size_t)) { return narrow_cast(idx) < narrow_cast(size); } From 1995e86d1ad70519465374fb4876c6ef7c9f8c61 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Sun, 19 Aug 2018 17:10:53 -0700 Subject: [PATCH 13/13] span constructor no address (#723) * Changed &arr[0] to std::array::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 --- include/gsl/span | 7 +++--- tests/span_tests.cpp | 52 ++++++++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index a4f9256..8cb3dbe 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -29,6 +29,7 @@ #include #include // for enable_if_t, declval, is_convertible, inte... #include +#include // for std::addressof #ifdef _MSC_VER #pragma warning(push) @@ -390,19 +391,19 @@ public: template constexpr span(element_type (&arr)[N]) noexcept - : storage_(KnownNotNull{&arr[0]}, details::extent_type()) + : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type()) {} template > // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr span(std::array& arr) noexcept - : storage_(&arr[0], details::extent_type()) + : storage_(arr.data(), details::extent_type()) {} template // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug constexpr span(const std::array, N>& arr) noexcept - : storage_(&arr[0], details::extent_type()) + : storage_(arr.data(), details::extent_type()) {} // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 081221b..07a59c8 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -52,6 +52,10 @@ struct BaseClass struct DerivedClass : BaseClass { }; +struct AddressOverloaded +{ + AddressOverloaded operator&() const { return {}; } +}; } 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") { int arr[5] = {1, 2, 3, 4, 5}; { - span s{arr}; + const span s{arr}; CHECK((s.size() == 5 && s.data() == &arr[0])); } { - span s{arr}; + const span s{arr}; CHECK((s.size() == 5 && s.data() == &arr[0])); } @@ -350,8 +352,8 @@ TEST_CASE("from_array_constructor") } #endif { - span s{&arr2d[0], 1}; - CHECK((s.size() == 1 && s.data() == &arr2d[0])); + const span s{std::addressof(arr2d[0]), 1}; + 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}; @@ -379,24 +381,32 @@ TEST_CASE("from_array_constructor") } #endif { - span s{&arr3d[0], 1}; - CHECK((s.size() == 1 && s.data() == &arr3d[0])); + const span s{std::addressof(arr3d[0]), 1}; + CHECK((s.size() == 1 && s.data() == std::addressof(arr3d[0]))); } { - auto s = make_span(arr); - CHECK((s.size() == 5 && s.data() == &arr[0])); + const auto s = make_span(arr); + CHECK((s.size() == 5 && s.data() == std::addressof(arr[0]))); } { - auto s = make_span(&(arr2d[0]), 1); - CHECK((s.size() == 1 && s.data() == &arr2d[0])); + const auto s = make_span(std::addressof(arr2d[0]), 1); + CHECK((s.size() == 1 && s.data() == std::addressof(arr2d[0]))); } { - auto s = make_span(&arr3d[0], 1); - CHECK((s.size() == 1 && s.data() == &arr3d[0])); + const auto s = make_span(std::addressof(arr3d[0]), 1); + CHECK((s.size() == 1 && s.data() == std::addressof(arr3d[0]))); } + + AddressOverloaded ao_arr[5] = {}; + + { + const span s{ao_arr}; + CHECK((s.size() == 5 && s.data() == std::addressof(ao_arr[0]))); + } + } GSL_SUPPRESS(con.4) // NO-FORMAT: attribute @@ -442,6 +452,13 @@ TEST_CASE("from_std_array_constructor") CHECK((cs.size() == narrow_cast(arr.size()) && cs.data() == arr.data())); } + std::array ao_arr{}; + + { + span fs{ao_arr}; + CHECK((fs.size() == narrow_cast(ao_arr.size()) && ao_arr.data() == fs.data())); + } + #ifdef CONFIRM_COMPILATION_ERRORS { span s{arr}; @@ -516,6 +533,13 @@ TEST_CASE("from_const_std_array_constructor") CHECK((s.size() == narrow_cast(arr.size()) && s.data() == arr.data())); } + const std::array ao_arr{}; + + { + span s{ao_arr}; + CHECK((s.size() == narrow_cast(ao_arr.size()) && s.data() == ao_arr.data())); + } + #ifdef CONFIRM_COMPILATION_ERRORS { span s{arr};