Decorate string_view members with nonnull attribute

Message ID 20180613163030.GA23501@redhat.com
State New
Headers show
Series
  • Decorate string_view members with nonnull attribute
Related show

Commit Message

Jonathan Wakely June 13, 2018, 4:30 p.m.
The C++ committee has confirmed that passing a null pointer to the
unary basic_string_view constructor is undefined. This removes the check
from our implementation, and adds the nonnull attribute to warn when the
compiler can detect undefined input.

Any objections to this change?
commit 05d33d556eaabb3c81f4db15b9818c465b359c15
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jun 13 16:54:47 2018 +0100

    Decorate string_view members with nonnull attribute
    
    The C++ committee has confirmed that passing a null pointer to the
    unary basic_string_view constructor is undefined. This removes the check
    from our implementation, and adds the nonnull attribute to warn when the
    compiler can detect undefined input.
    
            * include/std/string_view (basic_string_view(const CharT*)): Remove
            check for null pointer and add nonnull attribute.
            (compare(const CharT*), compare(size_type, size_type, const CharT*))
            (find(const CharT*, size_type), rfind(const CharT*, size_type))
            (find_first_of(const CharT*, size_type))
            (find_last_of(const CharT*, size_type))
            (find_first_not_of(const CharT*, size_type))
            (find_last_not_of(const CharT*, size_type)): Add nonnull attribute.
            * testsuite/21_strings/basic_string_view/cons/char/nonnull.cc: New.
            * testsuite/21_strings/basic_string_view/operations/compare/char/
            nonnull.cc: New.
            * testsuite/21_strings/basic_string_view/operations/find/char/
            nonnull.cc: New.
            * testsuite/21_strings/basic_string_view/operations/rfind/char/
            nonnull.cc: New.

Comments

Martin Sebor June 14, 2018, 4:46 p.m. | #1
On 06/13/2018 10:30 AM, Jonathan Wakely wrote:
> The C++ committee has confirmed that passing a null pointer to the
> unary basic_string_view constructor is undefined. This removes the check
> from our implementation, and adds the nonnull attribute to warn when the
> compiler can detect undefined input.
>
> Any objections to this change?

I have a general question about using the new C++ attributes in
libstdc++ (standard or otherwise): what does C++ have to say about
programs that define macros with the same names?  E.g., is this
a valid program?

   #define nonnull "..."
   ...
   #include <string_view>

How about:

   #define noreturn "..."
   ...
   #include <string_view>

The view in WG14 is that the corresponding C programs (if C2X
were to adopt the proposed C++ attributes) would be valid and
that it's up to implementations to make it work.

Martin
Jonathan Wakely June 14, 2018, 4:51 p.m. | #2
On 14/06/18 10:46 -0600, Martin Sebor wrote:
>On 06/13/2018 10:30 AM, Jonathan Wakely wrote:
>>The C++ committee has confirmed that passing a null pointer to the
>>unary basic_string_view constructor is undefined. This removes the check
>>from our implementation, and adds the nonnull attribute to warn when the
>>compiler can detect undefined input.
>>
>>Any objections to this change?
>
>I have a general question about using the new C++ attributes in
>libstdc++ (standard or otherwise): what does C++ have to say about
>programs that define macros with the same names?  E.g., is this
>a valid program?
>
>  #define nonnull "..."
>  ...
>  #include <string_view>
>
>How about:
>
>  #define noreturn "..."
>  ...
>  #include <string_view>
>
>The view in WG14 is that the corresponding C programs (if C2X
>were to adopt the proposed C++ attributes) would be valid and
>that it's up to implementations to make it work.

Good point, I suppose I have to use __attribute__((__nonnull__))
instead. The reason I didn't is that I find the grammar for the
position of C++11 attributes much easier to understand. But in this
instance the same location works for either.
Ville Voutilainen June 14, 2018, 4:54 p.m. | #3
On 14 June 2018 at 19:51, Jonathan Wakely <jwakely@redhat.com> wrote:
> On 14/06/18 10:46 -0600, Martin Sebor wrote:
>>
>> On 06/13/2018 10:30 AM, Jonathan Wakely wrote:
>>>
>>> The C++ committee has confirmed that passing a null pointer to the
>>> unary basic_string_view constructor is undefined. This removes the check
>>> from our implementation, and adds the nonnull attribute to warn when the
>>> compiler can detect undefined input.
>>>
>>> Any objections to this change?
>>
>>
>> I have a general question about using the new C++ attributes in
>> libstdc++ (standard or otherwise): what does C++ have to say about
>> programs that define macros with the same names?  E.g., is this
>> a valid program?
>>
>>  #define nonnull "..."
>>  ...
>>  #include <string_view>
>>
>> How about:
>>
>>  #define noreturn "..."
>>  ...
>>  #include <string_view>
>>
>> The view in WG14 is that the corresponding C programs (if C2X
>> were to adopt the proposed C++ attributes) would be valid and
>> that it's up to implementations to make it work.
>
>
> Good point, I suppose I have to use __attribute__((__nonnull__))
> instead. The reason I didn't is that I find the grammar for the
> position of C++11 attributes much easier to understand. But in this
> instance the same location works for either.

[macro.names]/2 forbids #defining macros with the same names as the
standard attributes.
The programs Martin shows as examples are not valid.
Jonathan Wakely June 14, 2018, 4:57 p.m. | #4
On 14/06/18 19:54 +0300, Ville Voutilainen wrote:
>On 14 June 2018 at 19:51, Jonathan Wakely <jwakely@redhat.com> wrote:
>> On 14/06/18 10:46 -0600, Martin Sebor wrote:
>>>
>>> On 06/13/2018 10:30 AM, Jonathan Wakely wrote:
>>>>
>>>> The C++ committee has confirmed that passing a null pointer to the
>>>> unary basic_string_view constructor is undefined. This removes the check
>>>> from our implementation, and adds the nonnull attribute to warn when the
>>>> compiler can detect undefined input.
>>>>
>>>> Any objections to this change?
>>>
>>>
>>> I have a general question about using the new C++ attributes in
>>> libstdc++ (standard or otherwise): what does C++ have to say about
>>> programs that define macros with the same names?  E.g., is this
>>> a valid program?
>>>
>>>  #define nonnull "..."
>>>  ...
>>>  #include <string_view>
>>>
>>> How about:
>>>
>>>  #define noreturn "..."
>>>  ...
>>>  #include <string_view>
>>>
>>> The view in WG14 is that the corresponding C programs (if C2X
>>> were to adopt the proposed C++ attributes) would be valid and
>>> that it's up to implementations to make it work.
>>
>>
>> Good point, I suppose I have to use __attribute__((__nonnull__))
>> instead. The reason I didn't is that I find the grammar for the
>> position of C++11 attributes much easier to understand. But in this
>> instance the same location works for either.
>
>[macro.names]/2 forbids #defining macros with the same names as the
>standard attributes.
>The programs Martin shows as examples are not valid.

But nonnull isn't a standard attribute though. So we can't use
[[gnu::xxx]] attributes in libstdc++ and have to use __attribute__
instead.

[[sad_face]]
Ville Voutilainen June 14, 2018, 5:02 p.m. | #5
On 14 June 2018 at 19:57, Jonathan Wakely <jwakely@redhat.com> wrote:
>> [macro.names]/2 forbids #defining macros with the same names as the
>> standard attributes.
>> The programs Martin shows as examples are not valid.
>
>
> But nonnull isn't a standard attribute though. So we can't use
> [[gnu::xxx]] attributes in libstdc++ and have to use __attribute__
> instead.

Oops, indeed. But for gnu-attributes, surely we can decide whatever we
want about what's
valid and what's not?
Jonathan Wakely June 14, 2018, 5:08 p.m. | #6
On 14/06/18 20:02 +0300, Ville Voutilainen wrote:
>On 14 June 2018 at 19:57, Jonathan Wakely <jwakely@redhat.com> wrote:
>>> [macro.names]/2 forbids #defining macros with the same names as the
>>> standard attributes.
>>> The programs Martin shows as examples are not valid.
>>
>>
>> But nonnull isn't a standard attribute though. So we can't use
>> [[gnu::xxx]] attributes in libstdc++ and have to use __attribute__
>> instead.
>
>Oops, indeed. But for gnu-attributes, surely we can decide whatever we
>want about what's
>valid and what's not?

We could say that #defining 'nonnull' and/or 'gnu' as a macro is
undefined, but then programs that the standard says are valid would
fail to compile, and we'd be a non-conforming implementation.

We can use __attribute__(__nonnull__)) so that we accept those
programs (and be a conforming implementation). Why would we choose to
be non-conforming when we don't have to?

We can use [[gnu::__nonnull__]] but that would still reject programs
that #define gnu so maybe we want the front-end to also recognise
__gnu__ as our attribute namespace.
Ville Voutilainen June 14, 2018, 5:21 p.m. | #7
On 14 June 2018 at 20:08, Jonathan Wakely <jwakely@redhat.com> wrote:
>> Oops, indeed. But for gnu-attributes, surely we can decide whatever we
>> want about what's
>> valid and what's not?
>
>
> We could say that #defining 'nonnull' and/or 'gnu' as a macro is
> undefined, but then programs that the standard says are valid would
> fail to compile, and we'd be a non-conforming implementation.
>
> We can use __attribute__(__nonnull__)) so that we accept those
> programs (and be a conforming implementation). Why would we choose to
> be non-conforming when we don't have to?

I can read the specification liberally enough that it might give us
the freedom to disallow programs
that #define names that our implementation uses for vendor attributes.
Ville Voutilainen June 14, 2018, 5:27 p.m. | #8
On 14 June 2018 at 20:21, Ville Voutilainen <ville.voutilainen@gmail.com> wrote:
> On 14 June 2018 at 20:08, Jonathan Wakely <jwakely@redhat.com> wrote:
>>> Oops, indeed. But for gnu-attributes, surely we can decide whatever we
>>> want about what's
>>> valid and what's not?
>>
>>
>> We could say that #defining 'nonnull' and/or 'gnu' as a macro is
>> undefined, but then programs that the standard says are valid would
>> fail to compile, and we'd be a non-conforming implementation.
>>
>> We can use __attribute__(__nonnull__)) so that we accept those
>> programs (and be a conforming implementation). Why would we choose to
>> be non-conforming when we don't have to?
>
> I can read the specification liberally enough that it might give us
> the freedom to disallow programs
> that #define names that our implementation uses for vendor attributes.

Namely "For an attribute-token (including an attribute-scoped-token)
not specified in this document, the behavior is
implementation-defined.", aka [dcl.attr.grammar]/6.
Jonathan Wakely June 14, 2018, 5:40 p.m. | #9
On 14/06/18 20:27 +0300, Ville Voutilainen wrote:
>On 14 June 2018 at 20:21, Ville Voutilainen <ville.voutilainen@gmail.com> wrote:
>> On 14 June 2018 at 20:08, Jonathan Wakely <jwakely@redhat.com> wrote:
>>>> Oops, indeed. But for gnu-attributes, surely we can decide whatever we
>>>> want about what's
>>>> valid and what's not?
>>>
>>>
>>> We could say that #defining 'nonnull' and/or 'gnu' as a macro is
>>> undefined, but then programs that the standard says are valid would
>>> fail to compile, and we'd be a non-conforming implementation.
>>>
>>> We can use __attribute__(__nonnull__)) so that we accept those
>>> programs (and be a conforming implementation). Why would we choose to
>>> be non-conforming when we don't have to?
>>
>> I can read the specification liberally enough that it might give us
>> the freedom to disallow programs
>> that #define names that our implementation uses for vendor attributes.
>
>Namely "For an attribute-token (including an attribute-scoped-token)
>not specified in this document, the behavior is
>implementation-defined.", aka [dcl.attr.grammar]/6.

As I said on IRC, if the user does

#define gnu R"(
 ,= ,-_-. =.
 ((_/)o o(\_))
  `-'(. .)`-'
      \_/
)"

then the attribute-scoped-token isn't even valid, and so the behaviour
of the implementation-defined gnu::nonnull attribute doesn't matter.
The code doesn't contain such an attribute.

This seems like an unnecessary discussion: we should just use the
__attribute__ form instead.
Ville Voutilainen June 14, 2018, 5:47 p.m. | #10
On 14 June 2018 at 20:40, Jonathan Wakely <jwakely@redhat.com> wrote:
>> Namely "For an attribute-token (including an attribute-scoped-token)
>> not specified in this document, the behavior is
>> implementation-defined.", aka [dcl.attr.grammar]/6.
>
>
> As I said on IRC, if the user does
>
> #define gnu R"(
> ,= ,-_-. =.
> ((_/)o o(\_))
>  `-'(. .)`-'
>      \_/
> )"
>
> then the attribute-scoped-token isn't even valid, and so the behaviour
> of the implementation-defined gnu::nonnull attribute doesn't matter.
> The code doesn't contain such an attribute.
>
> This seems like an unnecessary discussion: we should just use the
> __attribute__ form instead.

That may well be, but deciding to handle preprocessor definitions of
vendor attributes
in a particular way doesn't make us non-conforming. The behaviour of a
gnu::nonnull
would, as far as I understand it, possibly include restrictions on
what the preprocessor
can do with it, just like the specification for standard attributes
does. The preprocessor
is part of the implementation, not a magical separate step that can do
whatever it pleases.

Conformance being a moot point, I'd prefer using the standard
attribute syntax if we can,
instead of using the gnuattribute syntax, but that's not a strong preference.
Martin Sebor June 15, 2018, 1:51 a.m. | #11
On 06/14/2018 10:54 AM, Ville Voutilainen wrote:
> On 14 June 2018 at 19:51, Jonathan Wakely <jwakely@redhat.com> wrote:
>> On 14/06/18 10:46 -0600, Martin Sebor wrote:
>>>
>>> On 06/13/2018 10:30 AM, Jonathan Wakely wrote:
>>>>
>>>> The C++ committee has confirmed that passing a null pointer to the
>>>> unary basic_string_view constructor is undefined. This removes the check
>>>> from our implementation, and adds the nonnull attribute to warn when the
>>>> compiler can detect undefined input.
>>>>
>>>> Any objections to this change?
>>>
>>>
>>> I have a general question about using the new C++ attributes in
>>> libstdc++ (standard or otherwise): what does C++ have to say about
>>> programs that define macros with the same names?  E.g., is this
>>> a valid program?
>>>
>>>  #define nonnull "..."
>>>  ...
>>>  #include <string_view>
>>>
>>> How about:
>>>
>>>  #define noreturn "..."
>>>  ...
>>>  #include <string_view>
>>>
>>> The view in WG14 is that the corresponding C programs (if C2X
>>> were to adopt the proposed C++ attributes) would be valid and
>>> that it's up to implementations to make it work.
>>
>>
>> Good point, I suppose I have to use __attribute__((__nonnull__))
>> instead. The reason I didn't is that I find the grammar for the
>> position of C++11 attributes much easier to understand. But in this
>> instance the same location works for either.
>
> [macro.names]/2 forbids #defining macros with the same names as the
> standard attributes.
> The programs Martin shows as examples are not valid.

Okay, that's good to know about the one that uses the standard
attribute (and thanks for the reference).  WG14 should consider
this when integrating attributes into C2X.

FWIW, the problem I suspect will come up in WG14 is that C tries
hard to avoid introducing new reserved words into the public
namespace.  At the same time, two of the biggest selling points
of the C++ attribute syntax proposal in WG14 (i.e., the double
brackets, as opposed to something more C-ish like _Attribute())
are a) compatibility and interoperability with C++ and b) being
able to avoid relying on preprocessor conditionals and macros
to use attributes in portable code.  If C2X programs (and
libraries) are going to continue to be allowed to #define macros
with the same names as even standard attributes, we (i.e., both
WG14 and to an extent even WG21) will have failed to deliver on
these goals.  To avoid name clashes, mixed C/C++ programs will
still have to use #ifdefs and macros in both languages to make
use of attributes because the spelling of the "private" attribute
names (like __noreturn__) is not specified.  Even if C2X were to
impose the same restriction on macros as C++, there likely are
C headers out there today that do just that, and not all those
headers will necessarily migrate to C2X.

Martin
Jonathan Wakely June 15, 2018, 4:47 p.m. | #12
On 14/06/18 17:51 +0100, Jonathan Wakely wrote:
>On 14/06/18 10:46 -0600, Martin Sebor wrote:
>>On 06/13/2018 10:30 AM, Jonathan Wakely wrote:
>>>The C++ committee has confirmed that passing a null pointer to the
>>>unary basic_string_view constructor is undefined. This removes the check
>>>from our implementation, and adds the nonnull attribute to warn when the
>>>compiler can detect undefined input.
>>>
>>>Any objections to this change?
>>
>>I have a general question about using the new C++ attributes in
>>libstdc++ (standard or otherwise): what does C++ have to say about
>>programs that define macros with the same names?  E.g., is this
>>a valid program?
>>
>> #define nonnull "..."
>> ...
>> #include <string_view>
>>
>>How about:
>>
>> #define noreturn "..."
>> ...
>> #include <string_view>
>>
>>The view in WG14 is that the corresponding C programs (if C2X
>>were to adopt the proposed C++ attributes) would be valid and
>>that it's up to implementations to make it work.
>
>Good point, I suppose I have to use __attribute__((__nonnull__))
>instead. The reason I didn't is that I find the grammar for the
>position of C++11 attributes much easier to understand. But in this
>instance the same location works for either.

Nobody's objected to the patch in princple, so I'll commit this
version, using __attribute__((__nonnull__)) instead of
[[gnu::nonnull].
commit 5a1626332e84b64adc049b7ce13c2ed8917a7fa3
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jun 13 16:54:47 2018 +0100

    Decorate string_view members with nonnull attribute
    
    The C++ committee has confirmed that passing a null pointer to the
    unary basic_string_view constructor is undefined. This removes the check
    from our implementation, and adds the nonnull attribute to warn when the
    compiler can detect undefined input.
    
            * include/std/string_view (basic_string_view(const CharT*)): Remove
            check for null pointer and add nonnull attribute.
            (compare(const CharT*), compare(size_type, size_type, const CharT*))
            (find(const CharT*, size_type), rfind(const CharT*, size_type))
            (find_first_of(const CharT*, size_type))
            (find_last_of(const CharT*, size_type))
            (find_first_not_of(const CharT*, size_type))
            (find_last_not_of(const CharT*, size_type)): Add nonnull attribute.
            * testsuite/21_strings/basic_string_view/cons/char/nonnull.cc: New.
            * testsuite/21_strings/basic_string_view/operations/compare/char/
            nonnull.cc: New.
            * testsuite/21_strings/basic_string_view/operations/find/char/
            nonnull.cc: New.
            * testsuite/21_strings/basic_string_view/operations/rfind/char/
            nonnull.cc: New.

diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index 9f39df853e8..f84664ca286 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -96,8 +96,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       constexpr basic_string_view(const basic_string_view&) noexcept = default;
 
-      constexpr basic_string_view(const _CharT* __str) noexcept
-      : _M_len{__str == nullptr ? 0 : traits_type::length(__str)},
+      __attribute__((__nonnull__)) constexpr
+      basic_string_view(const _CharT* __str) noexcept
+      : _M_len{traits_type::length(__str)},
 	_M_str{__str}
       { }
 
@@ -270,11 +271,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return this->substr(__pos1, __n1).compare(__str.substr(__pos2, __n2));
       }
 
-      constexpr int
+      __attribute__((__nonnull__)) constexpr int
       compare(const _CharT* __str) const noexcept
       { return this->compare(basic_string_view{__str}); }
 
-      constexpr int
+      __attribute__((__nonnull__)) constexpr int
       compare(size_type __pos1, size_type __n1, const _CharT* __str) const
       { return this->substr(__pos1, __n1).compare(basic_string_view{__str}); }
 
@@ -296,7 +297,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr size_type
       find(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
 
-      constexpr size_type
+      __attribute__((__nonnull__)) constexpr size_type
       find(const _CharT* __str, size_type __pos = 0) const noexcept
       { return this->find(__str, __pos, traits_type::length(__str)); }
 
@@ -310,7 +311,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr size_type
       rfind(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
 
-      constexpr size_type
+      __attribute__((__nonnull__)) constexpr size_type
       rfind(const _CharT* __str, size_type __pos = npos) const noexcept
       { return this->rfind(__str, __pos, traits_type::length(__str)); }
 
@@ -323,9 +324,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return this->find(__c, __pos); }
 
       constexpr size_type
-      find_first_of(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
+      find_first_of(const _CharT* __str, size_type __pos,
+		    size_type __n) const noexcept;
 
-      constexpr size_type
+      __attribute__((__nonnull__)) constexpr size_type
       find_first_of(const _CharT* __str, size_type __pos = 0) const noexcept
       { return this->find_first_of(__str, __pos, traits_type::length(__str)); }
 
@@ -342,7 +344,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       find_last_of(const _CharT* __str, size_type __pos,
 		   size_type __n) const noexcept;
 
-      constexpr size_type
+      __attribute__((__nonnull__)) constexpr size_type
       find_last_of(const _CharT* __str, size_type __pos = npos) const noexcept
       { return this->find_last_of(__str, __pos, traits_type::length(__str)); }
 
@@ -358,7 +360,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       find_first_not_of(const _CharT* __str,
 			size_type __pos, size_type __n) const noexcept;
 
-      constexpr size_type
+      __attribute__((__nonnull__)) constexpr size_type
       find_first_not_of(const _CharT* __str, size_type __pos = 0) const noexcept
       {
 	return this->find_first_not_of(__str, __pos,
@@ -377,7 +379,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       find_last_not_of(const _CharT* __str,
 		       size_type __pos, size_type __n) const noexcept;
 
-      constexpr size_type
+      __attribute__((__nonnull__)) constexpr size_type
       find_last_not_of(const _CharT* __str,
 		       size_type __pos = npos) const noexcept
       {
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/nonnull.cc
new file mode 100644
index 00000000000..463ece718bd
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/nonnull.cc
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+void
+test01()
+{
+  std::string_view s((const char*)nullptr); // { dg-warning "null arg" }
+  std::string_view t((char*)nullptr);	    // { dg-warning "null arg" }
+  std::string_view u(nullptr);		    // { dg-warning "null arg" }
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/nonnull.cc
new file mode 100644
index 00000000000..8df61427a49
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/nonnull.cc
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+void
+test01()
+{
+  std::wstring_view s((const wchar_t*)nullptr);	// { dg-warning "null arg" }
+  std::wstring_view t((wchar_t*)nullptr);	// { dg-warning "null arg" }
+  std::wstring_view u(nullptr);			// { dg-warning "null arg" }
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/compare/char/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/compare/char/nonnull.cc
new file mode 100644
index 00000000000..1d12b700d88
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/compare/char/nonnull.cc
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+int
+test01()
+{
+  std::string_view s = "abcd";
+  return s.compare((const char*)nullptr);	// { dg-warning "null arg" }
+  return s.compare(0, 2, (const char*)nullptr);	// { dg-warning "null arg" }
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/find/char/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/find/char/nonnull.cc
new file mode 100644
index 00000000000..69f1850d9dc
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/find/char/nonnull.cc
@@ -0,0 +1,33 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+int
+test01()
+{
+  std::string_view s = "abcd";
+  return s.find((const char*)nullptr);		// { dg-warning "null arg" }
+  return s.find((const char*)nullptr, 1);	// { dg-warning "null arg" }
+  return s.find_first_of((const char*)nullptr);	// { dg-warning "null arg" }
+  return s.find_first_of((const char*)nullptr, 1); // { dg-warning "null arg" }
+  return s.find_first_not_of((const char*)nullptr); // { dg-warning "null arg" }
+  return s.find_first_not_of((const char*)nullptr, 1); // { dg-warning "null arg" }
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/rfind/char/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/rfind/char/nonnull.cc
new file mode 100644
index 00000000000..ca8527afa58
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/rfind/char/nonnull.cc
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+int
+test01()
+{
+  std::string_view s = "abcd";
+  return s.rfind((const char*)nullptr);		// { dg-warning "null arg" }
+  return s.rfind((const char*)nullptr, 1);	// { dg-warning "null arg" }
+}

Patch

diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index 9f39df853e8..4de484a96ba 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -96,8 +96,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       constexpr basic_string_view(const basic_string_view&) noexcept = default;
 
-      constexpr basic_string_view(const _CharT* __str) noexcept
-      : _M_len{__str == nullptr ? 0 : traits_type::length(__str)},
+      [[gnu::nonnull]] constexpr
+      basic_string_view(const _CharT* __str) noexcept
+      : _M_len{traits_type::length(__str)},
 	_M_str{__str}
       { }
 
@@ -270,11 +271,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return this->substr(__pos1, __n1).compare(__str.substr(__pos2, __n2));
       }
 
-      constexpr int
+      [[gnu::nonnull]] constexpr int
       compare(const _CharT* __str) const noexcept
       { return this->compare(basic_string_view{__str}); }
 
-      constexpr int
+      [[gnu::nonnull]] constexpr int
       compare(size_type __pos1, size_type __n1, const _CharT* __str) const
       { return this->substr(__pos1, __n1).compare(basic_string_view{__str}); }
 
@@ -296,7 +297,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr size_type
       find(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
 
-      constexpr size_type
+      [[gnu::nonnull]] constexpr size_type
       find(const _CharT* __str, size_type __pos = 0) const noexcept
       { return this->find(__str, __pos, traits_type::length(__str)); }
 
@@ -310,7 +311,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr size_type
       rfind(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
 
-      constexpr size_type
+      [[gnu::nonnull]] constexpr size_type
       rfind(const _CharT* __str, size_type __pos = npos) const noexcept
       { return this->rfind(__str, __pos, traits_type::length(__str)); }
 
@@ -323,9 +324,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return this->find(__c, __pos); }
 
       constexpr size_type
-      find_first_of(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
+      find_first_of(const _CharT* __str, size_type __pos,
+		    size_type __n) const noexcept;
 
-      constexpr size_type
+      [[gnu::nonnull]] constexpr size_type
       find_first_of(const _CharT* __str, size_type __pos = 0) const noexcept
       { return this->find_first_of(__str, __pos, traits_type::length(__str)); }
 
@@ -342,7 +344,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       find_last_of(const _CharT* __str, size_type __pos,
 		   size_type __n) const noexcept;
 
-      constexpr size_type
+      [[gnu::nonnull]] constexpr size_type
       find_last_of(const _CharT* __str, size_type __pos = npos) const noexcept
       { return this->find_last_of(__str, __pos, traits_type::length(__str)); }
 
@@ -358,7 +360,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       find_first_not_of(const _CharT* __str,
 			size_type __pos, size_type __n) const noexcept;
 
-      constexpr size_type
+      [[gnu::nonnull]] constexpr size_type
       find_first_not_of(const _CharT* __str, size_type __pos = 0) const noexcept
       {
 	return this->find_first_not_of(__str, __pos,
@@ -377,7 +379,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       find_last_not_of(const _CharT* __str,
 		       size_type __pos, size_type __n) const noexcept;
 
-      constexpr size_type
+      [[gnu::nonnull]] constexpr size_type
       find_last_not_of(const _CharT* __str,
 		       size_type __pos = npos) const noexcept
       {
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/nonnull.cc
new file mode 100644
index 00000000000..463ece718bd
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/char/nonnull.cc
@@ -0,0 +1,29 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+void
+test01()
+{
+  std::string_view s((const char*)nullptr); // { dg-warning "null arg" }
+  std::string_view t((char*)nullptr);	    // { dg-warning "null arg" }
+  std::string_view u(nullptr);		    // { dg-warning "null arg" }
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/nonnull.cc
new file mode 100644
index 00000000000..8df61427a49
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/cons/wchar_t/nonnull.cc
@@ -0,0 +1,29 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+void
+test01()
+{
+  std::wstring_view s((const wchar_t*)nullptr);	// { dg-warning "null arg" }
+  std::wstring_view t((wchar_t*)nullptr);	// { dg-warning "null arg" }
+  std::wstring_view u(nullptr);			// { dg-warning "null arg" }
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/compare/char/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/compare/char/nonnull.cc
new file mode 100644
index 00000000000..1d12b700d88
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/compare/char/nonnull.cc
@@ -0,0 +1,29 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+int
+test01()
+{
+  std::string_view s = "abcd";
+  return s.compare((const char*)nullptr);	// { dg-warning "null arg" }
+  return s.compare(0, 2, (const char*)nullptr);	// { dg-warning "null arg" }
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/find/char/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/find/char/nonnull.cc
new file mode 100644
index 00000000000..69f1850d9dc
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/find/char/nonnull.cc
@@ -0,0 +1,33 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+int
+test01()
+{
+  std::string_view s = "abcd";
+  return s.find((const char*)nullptr);		// { dg-warning "null arg" }
+  return s.find((const char*)nullptr, 1);	// { dg-warning "null arg" }
+  return s.find_first_of((const char*)nullptr);	// { dg-warning "null arg" }
+  return s.find_first_of((const char*)nullptr, 1); // { dg-warning "null arg" }
+  return s.find_first_not_of((const char*)nullptr); // { dg-warning "null arg" }
+  return s.find_first_not_of((const char*)nullptr, 1); // { dg-warning "null arg" }
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/rfind/char/nonnull.cc b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/rfind/char/nonnull.cc
new file mode 100644
index 00000000000..ca8527afa58
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string_view/operations/rfind/char/nonnull.cc
@@ -0,0 +1,29 @@ 
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -Wnonnull" }
+// { dg-do compile { target c++17 } }
+
+#include <string_view>
+
+int
+test01()
+{
+  std::string_view s = "abcd";
+  return s.rfind((const char*)nullptr);		// { dg-warning "null arg" }
+  return s.rfind((const char*)nullptr, 1);	// { dg-warning "null arg" }
+}