From 62733fee874bfe7e833e71380eb8efd6a3126fbd Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 26 Jun 2020 13:21:13 -0400 Subject: [PATCH 1/3] span: (almost) match std::span's constructor behavior c++20's draft of std::span no longer includes move constructors. --- src/span.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/span.h b/src/span.h index 4931507719..78c30fa553 100644 --- a/src/span.h +++ b/src/span.h @@ -28,6 +28,14 @@ class Span C* m_data; std::size_t m_size; + template + struct is_Span_int : public std::false_type {}; + template + struct is_Span_int> : public std::true_type {}; + template + struct is_Span : public is_Span_int::type>{}; + + public: constexpr Span() noexcept : m_data(nullptr), m_size(0) {} @@ -78,8 +86,19 @@ public: * To prevent surprises, only Spans for constant value types are supported when passing in temporaries. * Note that this restriction does not exist when converting arrays or other Spans (see above). */ - template ::value || std::is_lvalue_reference::value) && std::is_convertible().data())>::type (*)[], C (*)[]>::value && std::is_convertible().size()), std::size_t>::value, int>::type = 0> - constexpr Span(V&& v) noexcept : m_data(v.data()), m_size(v.size()) {} + template + constexpr Span(V& other, + typename std::enable_if::value && + std::is_convertible().data())>::type (*)[], C (*)[]>::value && + std::is_convertible().size()), std::size_t>::value, std::nullptr_t>::type = nullptr) + : m_data(other.data()), m_size(other.size()){} + + template + constexpr Span(const V& other, + typename std::enable_if::value && + std::is_convertible().data())>::type (*)[], C (*)[]>::value && + std::is_convertible().size()), std::size_t>::value, std::nullptr_t>::type = nullptr) + : m_data(other.data()), m_size(other.size()){} constexpr C* data() const noexcept { return m_data; } constexpr C* begin() const noexcept { return m_data; } From 1d58cc7cb040a70f768b632f294db4e0797d3a34 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 25 Jun 2020 17:25:31 -0400 Subject: [PATCH 2/3] span: add lifetimebound attribute See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0936r0.pdf for reference. This helps to guard against dangling references caused by construction from temporaries such as: Span sp(std::vector{1,2,3}); --- src/span.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/span.h b/src/span.h index 78c30fa553..d5d7ebccc4 100644 --- a/src/span.h +++ b/src/span.h @@ -18,6 +18,16 @@ #define ASSERT_IF_DEBUG(x) #endif +#if defined(__clang__) +#if __has_attribute(lifetimebound) +#define SPAN_ATTR_LIFETIMEBOUND [[clang::lifetimebound]] +#else +#define SPAN_ATTR_LIFETIMEBOUND +#endif +#else +#define SPAN_ATTR_LIFETIMEBOUND +#endif + /** A Span is an object that can refer to a contiguous sequence of objects. * * It implements a subset of C++20's std::span. @@ -87,14 +97,14 @@ public: * Note that this restriction does not exist when converting arrays or other Spans (see above). */ template - constexpr Span(V& other, + constexpr Span(V& other SPAN_ATTR_LIFETIMEBOUND, typename std::enable_if::value && std::is_convertible().data())>::type (*)[], C (*)[]>::value && std::is_convertible().size()), std::size_t>::value, std::nullptr_t>::type = nullptr) : m_data(other.data()), m_size(other.size()){} template - constexpr Span(const V& other, + constexpr Span(const V& other SPAN_ATTR_LIFETIMEBOUND, typename std::enable_if::value && std::is_convertible().data())>::type (*)[], C (*)[]>::value && std::is_convertible().size()), std::size_t>::value, std::nullptr_t>::type = nullptr) @@ -154,9 +164,9 @@ public: /** MakeSpan for arrays: */ template Span constexpr MakeSpan(A (&a)[N]) { return Span(a, N); } /** MakeSpan for temporaries / rvalue references, only supporting const output. */ -template constexpr auto MakeSpan(V&& v) -> typename std::enable_if::value, Span::type>>::type { return std::forward(v); } +template constexpr auto MakeSpan(V&& v SPAN_ATTR_LIFETIMEBOUND) -> typename std::enable_if::value, Span::type>>::type { return std::forward(v); } /** MakeSpan for (lvalue) references, supporting mutable output. */ -template constexpr auto MakeSpan(V& v) -> Span::type> { return v; } +template constexpr auto MakeSpan(V& v SPAN_ATTR_LIFETIMEBOUND) -> Span::type> { return v; } /** Pop the last element off a span, and return a reference to that element. */ template From e3e7446305329ce96e9cf5f5161658eb2e1ea888 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 8 Jul 2020 12:52:14 -0400 Subject: [PATCH 3/3] Add lifetimebound to attributes for general-purpose usage Co-authored-by: practicalswift --- src/attributes.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/attributes.h b/src/attributes.h index 45099bd8b8..9d5c1d44a0 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -19,4 +19,14 @@ # endif #endif +#if defined(__clang__) +# if __has_attribute(lifetimebound) +# define LIFETIMEBOUND [[clang::lifetimebound]] +# else +# define LIFETIMEBOUND +# endif +#else +# define LIFETIMEBOUND +#endif + #endif // BITCOIN_ATTRIBUTES_H