I wrote a lightweight string_view wrapper for a C++14 project, and with MSVC 2017 it is triggering a static_assert at compile-time, yet the same code at run-time is passes the regular assert.  My question is, is this a compiler bug, manifest undefined behaviour, or something else entirely?
Here's the distilled code:
#include <cassert> // assert
#include <cstddef> // size_t
class String_View
{
    char const* m_data;
    std::size_t m_size;
public:
    constexpr String_View()
      : m_data( nullptr ),
        m_size( 0u )
    {}
    constexpr char const* begin() const noexcept
    { return m_data; }
    constexpr char const* end() const noexcept
    { return m_data + m_size; }
};
void static_foo()
{
    constexpr String_View sv;
//    static_assert( sv.begin() == sv.end() ); // this errors
    static_assert( sv.begin() == nullptr );
//    static_assert( sv.end() == nullptr ); // this errors
}
void dynamic_foo()
{
    String_View const sv;
    assert( sv.begin() == sv.end() ); // this compiles & is optimized away
    assert( sv.begin() == nullptr );
    assert( sv.end() == nullptr ); // this compiles & is optimized away
}
Here's a Compiler Explorer link that I used to replicate the problem.
From what I can tell, adding or subtracting 0 from any pointer value is always valid:
- c++ - Is the behavior of subtracting two NULL pointers defined? - Stack Overflow, last blockquote
- Additive operators - cppreference.com, last bullet of the last bullet-list
- libstdc++: string_view Source File, implementation of end()etc.
Workaround:
If I change my end method to the following, the failing static_asserts will pass.
constexpr char const* end() const noexcept
{ return ( m_data == nullptr
           ? m_data
           : m_data + m_size ); }
Tinkering:
I thought maybe the expression m_data + m_size itself is UB, before the fact that m_size == 0 is evaluated.  Yet, if I replace the implementation of end with the nonsensical return m_data + 0;, this still generates the two static_assert errors.  :-/
Update:
This does appear to be a compiler bug that was fixed between 15.7 and 15.8.
 
     
    