]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Add conditional noexcept to range access functions
authorJonathan Wakely <jwakely@redhat.com>
Mon, 25 Nov 2024 21:22:12 +0000 (21:22 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 26 Nov 2024 08:31:27 +0000 (08:31 +0000)
As an extension, this adds conditional noexcept to std::begin, std::end,
and std::ssize.

libstdc++-v3/ChangeLog:

* include/bits/range_access.h (begin, end, ssize): Add
conditional noexcept.
* testsuite/18_support/initializer_list/range_access.cc: Check
results and noexcept-specifier for std::begin and std::end.
* testsuite/24_iterators/headers/iterator/range_access_c++11.cc:
Check for conditional noexcept on std::begin and std::end.
* testsuite/24_iterators/headers/iterator/range_access_c++14.cc:
Likewise.
* testsuite/24_iterators/headers/iterator/range_access_c++17.cc:
Likewise.
* testsuite/24_iterators/range_access/range_access.cc: Check
conditional noexcept is correct.
* testsuite/24_iterators/range_access/range_access_cpp17.cc:
Check std::size, std::empty and std::data.
* testsuite/24_iterators/range_access/range_access_cpp20.cc:
Check conditional noexcept on std::ssize.

libstdc++-v3/include/bits/range_access.h
libstdc++-v3/testsuite/18_support/initializer_list/range_access.cc
libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++11.cc
libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++14.cc
libstdc++-v3/testsuite/24_iterators/headers/iterator/range_access_c++17.cc
libstdc++-v3/testsuite/24_iterators/range_access/range_access.cc
libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp17.cc
libstdc++-v3/testsuite/24_iterators/range_access/range_access_cpp20.cc

index 2dacbedfa53305eb2372b33d6ab0a1f502c41d0b..ae58710e4a24a3026f2b758a66fa97bb28f3b226 100644 (file)
@@ -51,7 +51,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Container>
     [[__nodiscard__, __gnu__::__always_inline__]]
     inline _GLIBCXX17_CONSTEXPR auto
-    begin(_Container& __cont) -> decltype(__cont.begin())
+    begin(_Container& __cont) noexcept(noexcept(__cont.begin()))
+    -> decltype(__cont.begin())
     { return __cont.begin(); }
 
   /**
@@ -62,7 +63,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Container>
     [[__nodiscard__, __gnu__::__always_inline__]]
     inline _GLIBCXX17_CONSTEXPR auto
-    begin(const _Container& __cont) -> decltype(__cont.begin())
+    begin(const _Container& __cont) noexcept(noexcept(__cont.begin()))
+    -> decltype(__cont.begin())
     { return __cont.begin(); }
 
   /**
@@ -73,7 +75,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Container>
     [[__nodiscard__, __gnu__::__always_inline__]]
     inline _GLIBCXX17_CONSTEXPR auto
-    end(_Container& __cont) -> decltype(__cont.end())
+    end(_Container& __cont) noexcept(noexcept(__cont.end()))
+    -> decltype(__cont.end())
     { return __cont.end(); }
 
   /**
@@ -84,7 +87,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Container>
     [[__nodiscard__, __gnu__::__always_inline__]]
     inline _GLIBCXX17_CONSTEXPR auto
-    end(const _Container& __cont) -> decltype(__cont.end())
+    end(const _Container& __cont) noexcept(noexcept(__cont.end()))
+    -> decltype(__cont.end())
     { return __cont.end(); }
 
   /**
@@ -351,8 +355,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Container>
     [[nodiscard, __gnu__::__always_inline__]]
     constexpr auto
-    ssize(const _Container& __cont)
-    noexcept(noexcept(__cont.size()))
+    ssize(const _Container& __cont) noexcept(noexcept(__cont.size()))
     -> common_type_t<ptrdiff_t, make_signed_t<decltype(__cont.size())>>
     {
       using type = make_signed_t<decltype(__cont.size())>;
index ca572dc25dfec6ecb76563b95b54623c3c7e8bd3..3d4e2fefd3953ef2dfd98f9b079d9bbcbace7b87 100644 (file)
@@ -27,3 +27,13 @@ test01()
   std::begin({1, 2, 3});
   std::end({1, 2, 3});
 }
+
+void
+test02()
+{
+  static constexpr std::initializer_list<int> il{1};
+  static_assert( std::begin(il) == il.begin() );
+  static_assert( std::end(il) == il.end() );
+  static_assert( noexcept(std::begin(il)) );
+  static_assert( noexcept(std::end(il)) );
+}
index 448e86bce2ff196852604e563e38cd3f03a6eb74..89143d5dfa0be65d35daefc91c4efddd9b25f64f 100644 (file)
 
 #include <iterator>
 
+#ifdef _GLIBCXX_RELEASE
+// Conditional noexcept on these functions is a libstdc++ extension
+# define NOTHROW(F) noexcept(noexcept(c.F()))
+#else
+# define NOTHROW(F)
+#endif
+
 namespace std
 {
-  template<class C> auto begin(C& c) -> decltype(c.begin());
-  template<class C> auto begin(const C& c) -> decltype(c.begin());
+  template<class C> auto begin(C& c) NOTHROW(begin) -> decltype(c.begin());
+  template<class C> auto begin(const C& c) NOTHROW(begin) -> decltype(c.begin());
 
-  template<class C> auto end(C& c) -> decltype(c.end());
-  template<class C> auto end(const C& c) -> decltype(c.end());
+  template<class C> auto end(C& c) NOTHROW(end) -> decltype(c.end());
+  template<class C> auto end(const C& c) NOTHROW(end) -> decltype(c.end());
 
   template<class T, size_t N> T* begin(T (&array)[N]) noexcept;
   template<class T, size_t N> T* end(T (&array)[N]) noexcept;
index 1bbe4ad2c59ab6adcb4c2e7e86b50c05ab590b17..2c803dba3e5fe7c9bd6f61697515ed963671dc13 100644 (file)
 
 #include <iterator>
 
+#ifdef _GLIBCXX_RELEASE
+// Conditional noexcept on these functions is a libstdc++ extension
+# define NOTHROW(F) noexcept(noexcept(c.F()))
+#else
+# define NOTHROW(F)
+#endif
+
 namespace std
 {
-  template<class C> auto begin(C& c) -> decltype(c.begin());
-  template<class C> auto begin(const C& c) -> decltype(c.begin());
+  template<class C> auto begin(C& c) NOTHROW(begin) -> decltype(c.begin());
+  template<class C> auto begin(const C& c) NOTHROW(begin) -> decltype(c.begin());
 
-  template<class C> auto end(C& c) -> decltype(c.end());
-  template<class C> auto end(const C& c) -> decltype(c.end());
+  template<class C> auto end(C& c) NOTHROW(end) -> decltype(c.end());
+  template<class C> auto end(const C& c) NOTHROW(end) -> decltype(c.end());
 
   template<class T, size_t N> constexpr T* begin(T (&array)[N]) noexcept;
   template<class T, size_t N> constexpr T* end(T (&array)[N]) noexcept;
index 54e10b5616e98a2d72d16d7c936842cad435cfe2..573d9f9fa7aeb8be939bef9dda66294d66b9c1cf 100644 (file)
 
 #include <iterator>
 
+#ifdef _GLIBCXX_RELEASE
+// Conditional noexcept on these functions is a libstdc++ extension
+# define NOTHROW(F) noexcept(noexcept(c.F()))
+#else
+# define NOTHROW(F)
+#endif
+
 namespace std
 {
-  template<class C> constexpr auto begin(C& c) -> decltype(c.begin());
-  template<class C> constexpr auto begin(const C& c) -> decltype(c.begin());
+  template<class C> constexpr auto begin(C& c) NOTHROW(begin) -> decltype(c.begin());
+  template<class C> constexpr auto begin(const C& c) NOTHROW(begin) -> decltype(c.begin());
 
-  template<class C> constexpr auto end(C& c) -> decltype(c.end());
-  template<class C> constexpr auto end(const C& c) -> decltype(c.end());
+  template<class C> constexpr auto end(C& c) NOTHROW(end) -> decltype(c.end());
+  template<class C> constexpr auto end(const C& c) NOTHROW(end) -> decltype(c.end());
 
   template<class T, size_t N> constexpr T* begin(T (&array)[N]) noexcept;
   template<class T, size_t N> constexpr T* end(T (&array)[N]) noexcept;
index 66994b607a277ae85433ed1d94f4dd1d2dacea64..5ed6bfbd51aec7ae55cd38f8d4a654d7a25fc6b8 100644 (file)
@@ -57,4 +57,22 @@ test02()
   E e;
   require_int( std::end(e) );
   require_long( std::end(const_cast<const E&>(e)) );
+
+  static_assert( ! noexcept(std::begin(b)), "throws" );
+  static_assert( ! noexcept(std::begin(const_cast<const B&>(b))), "throws" );
+  static_assert( ! noexcept(std::end(e)), "throws" );
+  static_assert( ! noexcept(std::end(const_cast<const E&>(e))), "throws" );
+
+  struct S
+  {
+    int* begin() noexcept { return nullptr; }
+    int* begin() const noexcept { return nullptr; }
+    int* end() noexcept { return nullptr; }
+    int* end() const noexcept { return nullptr; }
+  };
+  S s;
+  static_assert( noexcept(std::begin(s)), "nothrow" );
+  static_assert( noexcept(std::begin(const_cast<const S&>(s))), "nothrow" );
+  static_assert( noexcept(std::end(s)), "nothrow" );
+  static_assert( noexcept(std::end(const_cast<const S&>(s))), "nothrow" );
 }
index ea4fb756806d67ef36bc22af6cda6dd8faed4198..50d15c91601fe5bbf9409b3efe0b577df4bcf057 100644 (file)
@@ -68,3 +68,60 @@ test03()
   static_assert( noexcept(std::rbegin(il)),  "LWG 3537" );
   static_assert( noexcept(std::rend(il)),    "LWG 3537" );
 }
+
+void
+test04()
+{
+  static int i[1]{};
+  static_assert( std::size(i) == 1 );
+  static_assert( noexcept(std::size(i)) );
+  static const int ci[2]{};
+  static_assert( std::size(ci) == 2 );
+  static_assert( noexcept(std::size(ci)) );
+  static constexpr std::initializer_list<int> il{1, 2, 3};
+  static_assert( std::size(il) == 3 );
+  struct Cont
+  {
+    constexpr unsigned size() const { return 4; }
+  };
+  constexpr Cont c;
+  static_assert( std::size(c) == 4 );
+}
+
+void
+test05()
+{
+  static int i[1]{};
+  static_assert( std::empty(i) == false );
+  static_assert( noexcept(std::size(i)) );
+  static const int ci[2]{};
+  static_assert( std::empty(ci) == false );
+  static_assert( noexcept(std::size(ci)) );
+  static constexpr std::initializer_list<int> il{1, 2, 3};
+  static_assert( std::empty(il) == false );
+  struct Cont
+  {
+    constexpr bool empty() const { return true; }
+  };
+  constexpr Cont c;
+  static_assert( std::empty(c) == true );
+}
+
+void
+test06()
+{
+  static int i[1]{};
+  static_assert( std::data(i) == i );
+  static_assert( noexcept(std::size(i)) );
+  static const int ci[2]{};
+  static_assert( std::data(ci) == ci );
+  static_assert( noexcept(std::size(ci)) );
+  static constexpr std::initializer_list<int> il{1, 2, 3};
+  static_assert( std::data(il) == il.begin() );
+  struct Cont
+  {
+    constexpr int* data() const { return nullptr; }
+  };
+  constexpr Cont c;
+  static_assert( std::data(c) == nullptr );
+}
index 5b6bc370f0148c279720bd2e2e580983c0842679..8148d6c80ef32494b0076a99e26b54fae8f3c536 100644 (file)
@@ -44,12 +44,16 @@ test03()
 {
   struct Cont
   {
-    constexpr unsigned short size() const { return 3; }
+    constexpr unsigned short size() const noexcept { return 3; }
   };
   constexpr Cont c;
   constexpr auto s = std::ssize(c);
   const std::ptrdiff_t* check_type = &s;
   static_assert(s == 3);
+
+#ifdef _GLIBCXX_RELEASE
+  static_assert( noexcept(std::ssize(c)) ); // This is a libstdc++ extension.
+#endif
 }
 
 void
@@ -63,4 +67,6 @@ test04()
   constexpr auto s = std::ssize(c);
   const long long* check_type = &s;
   static_assert(s == 4);
+
+  static_assert( ! noexcept(std::ssize(c)) );
 }