[libc++] span: Fix incorrect static asserts
authorLouis Dionne <ldionne@apple.com>
Fri, 14 Feb 2020 13:31:15 +0000 (14:31 +0100)
committerLouis Dionne <ldionne@apple.com>
Fri, 14 Feb 2020 13:32:41 +0000 (14:32 +0100)
The static asserts in span<T, N>::front() and span<T, N>::back() are
incorrect as they may be triggered from valid code due to evaluation
of a never taken branch:

    span<int, 0> foo;
    if (!foo.empty()) {
        auto x = foo.front();
    }

The problem is that the branch is always evaluated by the compiler,
creating invalid compile errors for span<T, 0>.

Thanks to Michael Schellenberger Costa for the patch.

Differential Revision: https://reviews.llvm.org/D71995

libcxx/include/span
libcxx/test/std/containers/views/span.elem/back.pass.cpp
libcxx/test/std/containers/views/span.elem/front.pass.cpp

index 82bcbff..1fe1496 100644 (file)
@@ -307,13 +307,13 @@ public:
 
     _LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept
     {
-        static_assert(_Extent > 0, "span<T,N>[].front() on empty span");
+        _LIBCPP_ASSERT(!empty(), "span<T, N>::front() on empty span");
         return __data[0];
     }
 
     _LIBCPP_INLINE_VISIBILITY constexpr reference back() const noexcept
     {
-        static_assert(_Extent > 0, "span<T,N>[].back() on empty span");
+        _LIBCPP_ASSERT(!empty(), "span<T, N>::back() on empty span");
         return __data[size()-1];
     }
 
index f2c0cf6..5bb9631 100644 (file)
@@ -30,7 +30,6 @@ constexpr bool testConstexprSpan(Span sp)
     return std::addressof(sp.back()) == sp.data() + sp.size() - 1;
 }
 
-
 template <typename Span>
 void testRuntimeSpan(Span sp)
 {
@@ -38,6 +37,12 @@ void testRuntimeSpan(Span sp)
     assert(std::addressof(sp.back()) == sp.data() + sp.size() - 1);
 }
 
+template <typename Span>
+void testEmptySpan(Span sp)
+{
+    if (!sp.empty())
+        [[maybe_unused]] auto res = sp.back();
+}
 
 struct A{};
 constexpr int iArr1[] = { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9};
@@ -71,5 +76,8 @@ int main(int, char**)
     testRuntimeSpan(std::span<std::string>   (&s, 1));
     testRuntimeSpan(std::span<std::string, 1>(&s, 1));
 
+    std::span<int, 0> sp;
+    testEmptySpan(sp);
+
     return 0;
 }
index 7f18a24..e17f7dd 100644 (file)
@@ -38,6 +38,12 @@ void testRuntimeSpan(Span sp)
     assert(std::addressof(sp.front()) == sp.data());
 }
 
+template <typename Span>
+void testEmptySpan(Span sp)
+{
+    if (!sp.empty())
+        [[maybe_unused]] auto res = sp.front();
+}
 
 struct A{};
 constexpr int iArr1[] = { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9};
@@ -71,5 +77,8 @@ int main(int, char**)
     testRuntimeSpan(std::span<std::string>   (&s, 1));
     testRuntimeSpan(std::span<std::string, 1>(&s, 1));
 
+    std::span<int, 0> sp;
+    testEmptySpan(sp);
+
     return 0;
 }