Skip to content

Commit 1d58cc7

Browse files
committed
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<const int> sp(std::vector<int>{1,2,3});
1 parent 62733fe commit 1d58cc7

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

src/span.h

Lines changed: 14 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.
@@ -87,14 +97,14 @@ class Span
8797
* Note that this restriction does not exist when converting arrays or other Spans (see above).
8898
*/
8999
template <typename V>
90-
constexpr Span(V& other,
100+
constexpr Span(V& other SPAN_ATTR_LIFETIMEBOUND,
91101
typename std::enable_if<!is_Span<V>::value &&
92102
std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value &&
93103
std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)
94104
: m_data(other.data()), m_size(other.size()){}
95105

96106
template <typename V>
97-
constexpr Span(const V& other,
107+
constexpr Span(const V& other SPAN_ATTR_LIFETIMEBOUND,
98108
typename std::enable_if<!is_Span<V>::value &&
99109
std::is_convertible<typename std::remove_pointer<decltype(std::declval<const V&>().data())>::type (*)[], C (*)[]>::value &&
100110
std::is_convertible<decltype(std::declval<const V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)
@@ -154,9 +164,9 @@ class Span
154164
/** MakeSpan for arrays: */
155165
template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
156166
/** MakeSpan for temporaries / rvalue references, only supporting const output. */
157-
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); }
167+
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); }
158168
/** MakeSpan for (lvalue) references, supporting mutable output. */
159-
template <typename V> constexpr auto MakeSpan(V& v) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
169+
template <typename V> constexpr auto MakeSpan(V& v SPAN_ATTR_LIFETIMEBOUND) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
160170

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

0 commit comments

Comments
 (0)