Is this failing test that adds zero to a null pointer undefined behaviour, a compiler bug, or something else?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
7
down vote

favorite












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: https://godbolt.org/z/TpnE8o



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. :-/










share|improve this question



























    up vote
    7
    down vote

    favorite












    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: https://godbolt.org/z/TpnE8o



    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. :-/










    share|improve this question

























      up vote
      7
      down vote

      favorite









      up vote
      7
      down vote

      favorite











      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: https://godbolt.org/z/TpnE8o



      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. :-/










      share|improve this question















      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: https://godbolt.org/z/TpnE8o



      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. :-/







      c++ c++14 undefined-behavior compiler-bug






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 43 mins ago

























      asked 1 hour ago









      Charles L Wilcox

      540214




      540214






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          5
          down vote













          I think that this is definitely a bug in the way MSVC evaluates constant expressions, since GCC and Clang have no issues with the code, and the standard is clear that adding 0 to a null pointer yields a null pointer ([expr.add]/7).






          share|improve this answer




















            Your Answer





            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52808357%2fis-this-failing-test-that-adds-zero-to-a-null-pointer-undefined-behaviour-a-com%23new-answer', 'question_page');

            );

            Post as a guest






























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            5
            down vote













            I think that this is definitely a bug in the way MSVC evaluates constant expressions, since GCC and Clang have no issues with the code, and the standard is clear that adding 0 to a null pointer yields a null pointer ([expr.add]/7).






            share|improve this answer
























              up vote
              5
              down vote













              I think that this is definitely a bug in the way MSVC evaluates constant expressions, since GCC and Clang have no issues with the code, and the standard is clear that adding 0 to a null pointer yields a null pointer ([expr.add]/7).






              share|improve this answer






















                up vote
                5
                down vote










                up vote
                5
                down vote









                I think that this is definitely a bug in the way MSVC evaluates constant expressions, since GCC and Clang have no issues with the code, and the standard is clear that adding 0 to a null pointer yields a null pointer ([expr.add]/7).






                share|improve this answer












                I think that this is definitely a bug in the way MSVC evaluates constant expressions, since GCC and Clang have no issues with the code, and the standard is clear that adding 0 to a null pointer yields a null pointer ([expr.add]/7).







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 1 hour ago









                Brian

                61.3k791175




                61.3k791175



























                     

                    draft saved


                    draft discarded















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52808357%2fis-this-failing-test-that-adds-zero-to-a-null-pointer-undefined-behaviour-a-com%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Comments

                    Popular posts from this blog

                    What does second last employer means? [closed]

                    Installing NextGIS Connect into QGIS 3?

                    One-line joke