aboutsummaryrefslogtreecommitdiff
path: root/src/span.h
diff options
context:
space:
mode:
authorCory Fields <cory-nospam-@coryfields.com>2020-06-25 17:25:31 -0400
committerCory Fields <cory-nospam-@coryfields.com>2020-06-29 15:15:34 -0400
commit1d58cc7cb040a70f768b632f294db4e0797d3a34 (patch)
tree1bd97392c39ccfffa509613f6b133b9df58b0dce /src/span.h
parent62733fee874bfe7e833e71380eb8efd6a3126fbd (diff)
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});
Diffstat (limited to 'src/span.h')
-rw-r--r--src/span.h18
1 files 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 <typename V>
- constexpr Span(V& other,
+ constexpr Span(V& other SPAN_ATTR_LIFETIMEBOUND,
typename std::enable_if<!is_Span<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, std::nullptr_t>::type = nullptr)
: m_data(other.data()), m_size(other.size()){}
template <typename V>
- constexpr Span(const V& other,
+ constexpr Span(const V& other SPAN_ATTR_LIFETIMEBOUND,
typename std::enable_if<!is_Span<V>::value &&
std::is_convertible<typename std::remove_pointer<decltype(std::declval<const V&>().data())>::type (*)[], C (*)[]>::value &&
std::is_convertible<decltype(std::declval<const V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr)
@@ -154,9 +164,9 @@ public:
/** MakeSpan for arrays: */
template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
/** MakeSpan for temporaries / rvalue references, only supporting const output. */
-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); }
+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); }
/** MakeSpan for (lvalue) references, supporting mutable output. */
-template <typename V> constexpr auto MakeSpan(V& v) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
+template <typename V> constexpr auto MakeSpan(V& v SPAN_ATTR_LIFETIMEBOUND) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
/** Pop the last element off a span, and return a reference to that element. */
template <typename T>