Skip to content

Commit 5c0aebf

Browse files
author
MarcoFalke
committed
Merge #19387: span: update constructors to match c++20 draft spec and add lifetimebound attribute
e3e7446 Add lifetimebound to attributes for general-purpose usage (Cory Fields) 1d58cc7 span: add lifetimebound attribute (Cory Fields) 62733fe span: (almost) match std::span's constructor behavior (Cory Fields) Pull request description: Replaces #19382 with a different approach. See [this comment](bitcoin/bitcoin#19382 (comment)) for the reasoning behind the switch. -- Description from #19382: See [here](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0936r0.pdf) for more detail on lifetimebound. This is implemented using preprocesor macros rather than configure checks in order to keep span.h self-contained. The ```[[clang::lifetimebound]]``` syntax was chosen over ```__attribute__((lifetimebound))``` because the former is more flexible and works to guard ```this``` as well as function parameters, and also because at least for now, it's available only in clang. There are currently no violations in our codebase, but this can easily be tested by inserting one like this somewhere and compiling with a modern clang: ```c++ Span<const int> bad(std::vector<int>{1,2,3}); ``` The result: > warning: temporary whose address is used as value of local variable 'bad' will be destroyed at the end of the full-expression [-Wdangling] Span<const int> bad(std::vector<int>{1,2,3}); ``` ACKs for top commit: sipa: ACK e3e7446 ajtowns: ACK e3e7446 (drive by; only a quick skim of code and some basic sanity checks) MarcoFalke: review ACK e3e7446 🔗 jonatack: ACK e3e7446 change since last review is adding `[[clang::lifetimebound]]` as `LIFETIMEBOUND` to src/attributes.h as suggested in bitcoin/bitcoin#19387 (comment). Tree-SHA512: 05a3440ee595ef0e8d693a2820b360707695c016a68e15df47c20cd8d053646cc6c8cca8addd7db40e72b3fce208879a41c8102ba7ae9223e4366e5de1175211
2 parents afdfd3c + e3e7446 commit 5c0aebf

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

src/attributes.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,14 @@
1919
# endif
2020
#endif
2121

22+
#if defined(__clang__)
23+
# if __has_attribute(lifetimebound)
24+
# define LIFETIMEBOUND [[clang::lifetimebound]]
25+
# else
26+
# define LIFETIMEBOUND
27+
# endif
28+
#else
29+
# define LIFETIMEBOUND
30+
#endif
31+
2232
#endif // BITCOIN_ATTRIBUTES_H

src/span.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@
1818
#define ASSERT_IF_DEBUG(x)
1919
#endif
2020

21+
#if defined(__clang__)
22+
#if __has_attribute(lifetimebound)
23+
#define SPAN_ATTR_LIFETIMEBOUND [[clang::lifetimebound]]
24+
#else
25+
#define SPAN_ATTR_LIFETIMEBOUND
26+
#endif
27+
#else
28+
#define SPAN_ATTR_LIFETIMEBOUND
29+
#endif
30+
2131
/** A Span is an object that can refer to a contiguous sequence of objects.
2232
*
2333
* It implements a subset of C++20's std::span.
@@ -84,6 +94,14 @@ class Span
8494
C* m_data;
8595
std::size_t m_size;
8696

97+
template <class T>
98+
struct is_Span_int : public std::false_type {};
99+
template <class T>
100+
struct is_Span_int<Span<T>> : public std::true_type {};
101+
template <class T>
102+
struct is_Span : public is_Span_int<typename std::remove_cv<T>::type>{};
103+
104+
87105
public:
88106
constexpr Span() noexcept : m_data(nullptr), m_size(0) {}
89107

@@ -134,8 +152,19 @@ class Span
134152
* To prevent surprises, only Spans for constant value types are supported when passing in temporaries.
135153
* Note that this restriction does not exist when converting arrays or other Spans (see above).
136154
*/
137-
template <typename V, typename std::enable_if<(std::is_const<C>::value || std::is_lvalue_reference<V>::value) && std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value && std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, int>::type = 0>
138-
constexpr Span(V&& v) noexcept : m_data(v.data()), m_size(v.size()) {}
155+
template <typename V>
156+
constexpr Span(V& other SPAN_ATTR_LIFETIMEBOUND,
157+
typename std::enable_if<!is_Span<V>::value &&
158+
std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value &&
159+
std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)
160+
: m_data(other.data()), m_size(other.size()){}
161+
162+
template <typename V>
163+
constexpr Span(const V& other SPAN_ATTR_LIFETIMEBOUND,
164+
typename std::enable_if<!is_Span<V>::value &&
165+
std::is_convertible<typename std::remove_pointer<decltype(std::declval<const V&>().data())>::type (*)[], C (*)[]>::value &&
166+
std::is_convertible<decltype(std::declval<const V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)
167+
: m_data(other.data()), m_size(other.size()){}
139168

140169
constexpr C* data() const noexcept { return m_data; }
141170
constexpr C* begin() const noexcept { return m_data; }
@@ -192,9 +221,9 @@ class Span
192221
/** MakeSpan for arrays: */
193222
template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
194223
/** MakeSpan for temporaries / rvalue references, only supporting const output. */
195-
template <typename V> constexpr auto MakeSpan(V&& v) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); }
224+
template <typename V> constexpr auto MakeSpan(V&& v SPAN_ATTR_LIFETIMEBOUND) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); }
196225
/** MakeSpan for (lvalue) references, supporting mutable output. */
197-
template <typename V> constexpr auto MakeSpan(V& v) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
226+
template <typename V> constexpr auto MakeSpan(V& v SPAN_ATTR_LIFETIMEBOUND) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
198227

199228
/** Pop the last element off a span, and return a reference to that element. */
200229
template <typename T>

0 commit comments

Comments
 (0)