On Fri, Sep 18, 2026 at 10:17 AM Tomasz Kaminski <[email protected]> wrote:
> > > On Thu, Sep 17, 2026 at 7:55 PM Jonathan Wakely <[email protected]> > wrote: > >> We can use deleted functions in C++98 mode if we use pragmas to disable >> the -Wc++11-extensions diagnostics. This works with both GCC and Clang. >> >> In some cases this makes the code more robust in C++98 mode because we >> were previously not making types copyable at all (e.g., >> _Reuse_or_alloc_node in bits/stl_tree.h) and just relying on testing in >> C++11 and later to know we didn't use those functions. In other cases it >> gives better diagnostics because we were defining copy constructors and >> assignment operators as private >> >> libstdc++-v3/ChangeLog: >> >> * config/io/basic_file_stdio.h (__basic_file::operator=): Define >> deleted copy assignment operator for C++98. >> * include/bits/stl_bvector.h (vector<bool, A>::data): Define as >> deleted for C++98. >> * include/bits/stl_tree.h (_Reuse_or_alloc_node): Define copy >> constructor as deleted for C++98. >> * include/bits/stl_vector.h (_Asan<allocator<T>>::_Reinit): >> Define copy constructor and copy assignment operator as deleted >> for C++98. >> (_Asan<allocator<T>>::_Grow): Likewise. >> * testsuite/util/replacement_memory_operators.h >> (__gnu_test::counter::scope): Likewise. >> * testsuite/util/testsuite_iterators.h (operator,, operator&) >> (operator+=, operator-=, operator[]): Define deleted operators >> for C++98. >> --- >> >> This is sort of an RFC. Should we do this? >> > I think we should, there isn't a big benefit in this specific cases.| > But, I like having a clear guidance that we can use = delete in > C++98. I think it will be useful, but I'm not exactly sure where. > >> >> I like having fewer #if conditions and just using the same code >> consistently for all -std modes. The extra pragmas are a bit ugly, but >> we have them all over the code already. >> > There were already ifdefs there, so we do not need to. > >> >> Tested x86_64-linux. >> >> libstdc++-v3/config/io/basic_file_stdio.h | 6 +++- >> libstdc++-v3/include/bits/stl_bvector.h | 8 ++--- >> libstdc++-v3/include/bits/stl_tree.h | 5 +-- >> libstdc++-v3/include/bits/stl_vector.h | 8 ++--- >> .../util/replacement_memory_operators.h | 14 ++++---- >> .../testsuite/util/testsuite_iterators.h | 32 ++++--------------- >> 6 files changed, 27 insertions(+), 46 deletions(-) >> >> diff --git a/libstdc++-v3/config/io/basic_file_stdio.h >> b/libstdc++-v3/config/io/basic_file_stdio.h >> index 5e06fd378eab..87e0ed6d2252 100644 >> --- a/libstdc++-v3/config/io/basic_file_stdio.h >> +++ b/libstdc++-v3/config/io/basic_file_stdio.h >> @@ -70,7 +70,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> __rv._M_cfile_created = false; >> } >> >> - __basic_file& operator=(const __basic_file&) = delete; >> __basic_file& operator=(__basic_file&&) = delete; >> > We do not need to delete the move constructor if we delete the copy > constructor, > but I think that is more readable. > >> >> void >> @@ -81,6 +80,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> } >> #endif >> >> +#pragma GCC diagnostic push >> +#pragma GCC diagnostic ignored "-Wc++11-extensions" >> + __basic_file& operator=(const __basic_file&) = delete; >> > You should delete the copy constructor, which was deleted in C++11+ mode, > due to move ctor/assigment. And move it before C++11 block. > And deleting only the copy assignment operator does not affect the copy constructor, so it is still not deleted in C++98. However, with deleted copy operations, you no longer need to delete move ones, so would remove them. > +#pragma GCC diagnostic pop >> + >> __basic_file* >> open(const char* __name, ios_base::openmode __mode, int __prot = >> 0664); >> >> diff --git a/libstdc++-v3/include/bits/stl_bvector.h >> b/libstdc++-v3/include/bits/stl_bvector.h >> index d792f7077860..3cdb48f3983c 100644 >> --- a/libstdc++-v3/include/bits/stl_bvector.h >> +++ b/libstdc++-v3/include/bits/stl_bvector.h >> @@ -1763,12 +1763,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER >> // DR 464. Suggestion for new member functions in standard >> containers. >> // N.B. DR 464 says nothing about vector<bool> but we need >> something >> // here due to the using-declaration in __gnu_debug::vector. >> - // vector class. >> -#if __cplusplus >= 201103L >> +#pragma GCC diagnostic push >> +#pragma GCC diagnostic ignored "-Wc++11-extensions" >> void data() = delete; >> -#else >> - void data() { } >> -#endif >> +#pragma GCC diagnostic pop >> }; >> >> _GLIBCXX_END_NAMESPACE_CONTAINER >> diff --git a/libstdc++-v3/include/bits/stl_tree.h >> b/libstdc++-v3/include/bits/stl_tree.h >> index 313ee8160023..da1fbd304c0c 100644 >> --- a/libstdc++-v3/include/bits/stl_tree.h >> +++ b/libstdc++-v3/include/bits/stl_tree.h >> @@ -1057,9 +1057,10 @@ namespace __rb_tree >> _M_nodes = _Base_ptr(); >> } >> >> -#if __cplusplus >= 201103L >> +#pragma GCC diagnostic push >> +#pragma GCC diagnostic ignored "-Wc++11-extensions" >> _Reuse_or_alloc_node(const _Reuse_or_alloc_node&) = delete; >> -#endif >> +#pragma GCC diagnostic pop >> >> ~_Reuse_or_alloc_node() >> { >> diff --git a/libstdc++-v3/include/bits/stl_vector.h >> b/libstdc++-v3/include/bits/stl_vector.h >> index 9ddf35502e69..73fee5c07a1d 100644 >> --- a/libstdc++-v3/include/bits/stl_vector.h >> +++ b/libstdc++-v3/include/bits/stl_vector.h >> @@ -173,6 +173,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER >> #endif >> >> #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR >> +#pragma GCC diagnostic push >> +#pragma GCC diagnostic ignored "-Wc++11-extensions" // deleted functions >> template<typename = _Tp_alloc_type> >> struct _Asan >> { >> @@ -249,10 +251,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER >> >> _Vector_impl& _M_impl; >> >> -#if __cplusplus >= 201103L >> _Reinit(const _Reinit&) = delete; >> _Reinit& operator=(const _Reinit&) = delete; >> -#endif >> }; >> >> // Tell ASan when unused capacity is initialized to be valid. >> @@ -269,15 +269,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER >> _GLIBCXX20_CONSTEXPR >> void _M_grew(size_type __n) { _M_n -= __n; } >> >> -#if __cplusplus >= 201103L >> _Grow(const _Grow&) = delete; >> _Grow& operator=(const _Grow&) = delete; >> -#endif >> + >> private: >> _Vector_impl& _M_impl; >> size_type _M_n; >> }; >> }; >> +#pragma GCC diagnostic pop >> >> #define _GLIBCXX_ASAN_ANNOTATE_REINIT \ >> typename _Base::_Vector_impl::template _Asan<>::_Reinit const \ >> diff --git a/libstdc++-v3/testsuite/util/replacement_memory_operators.h >> b/libstdc++-v3/testsuite/util/replacement_memory_operators.h >> index c6485b571e56..53837cabecbf 100644 >> --- a/libstdc++-v3/testsuite/util/replacement_memory_operators.h >> +++ b/libstdc++-v3/testsuite/util/replacement_memory_operators.h >> @@ -87,16 +87,14 @@ namespace __gnu_test >> ~scope() >> { counter::get()._M_count = _M_count; } >> >> - private: >> - std::size_t _M_count; >> - >> -#if __cplusplus >= 201103L >> +#pragma GCC diagnostic push >> +#pragma GCC diagnostic ignored "-Wc++11-extensions" >> scope(const scope&) = delete; >> scope& operator=(const scope&) = delete; >> -#else >> - scope(const scope&); >> - scope& operator=(const scope&); >> -#endif >> +#pragma GCC diagnostic pop >> + >> + private: >> + std::size_t _M_count; >> }; >> }; >> >> diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h >> b/libstdc++-v3/testsuite/util/testsuite_iterators.h >> index ca022e5d0f9c..8aefd7b11204 100644 >> --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h >> +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h >> @@ -47,6 +47,9 @@ >> #define ITERATOR_VERIFY(x) VERIFY(x) >> #endif >> >> +#pragma GCC diagnostic push >> +#pragma GCC diagnostic ignored "-Wc++11-extensions" // deleted functions >> + >> namespace __gnu_test >> { >> /** >> @@ -193,24 +196,14 @@ namespace __gnu_test >> return tmp; >> } >> >> -#if __cplusplus >= 201103L >> template<typename U> >> void operator,(const U&) const = delete; >> >> void operator&() const = delete; >> -#else >> - private: >> - template<typename U> >> - void operator,(const U&) const; >> - >> - void operator&() const; >> -#endif >> }; >> >> -#if __cplusplus >= 201103L >> template<typename T, typename U> >> void operator,(const T&, const output_iterator_wrapper<U>&) = delete; >> -#endif >> >> #if __cplusplus >= 201103L >> using std::remove_cv; >> @@ -331,24 +324,14 @@ namespace __gnu_test >> return tmp; >> } >> >> -#if __cplusplus >= 201103L >> template<typename U> >> void operator,(const U&) const = delete; >> >> void operator&() const = delete; >> -#else >> - private: >> - template<typename U> >> - void operator,(const U&) const; >> - >> - void operator&() const; >> -#endif >> }; >> >> -#if __cplusplus >= 201103L >> template<typename T, typename U> >> void operator,(const T&, const input_iterator_wrapper<U>&) = delete; >> -#endif >> >> /** >> * @brief forward_iterator wrapper for pointer >> @@ -607,11 +590,11 @@ namespace __gnu_test >> T& operator[](std::ptrdiff_t n) const >> { return *(*this + n); } >> >> -#if __cplusplus >= 201103L >> // Ensure that the iterator's difference_type is always used. >> template<typename D> void operator+=(D) = delete; >> template<typename D> void operator-=(D) = delete; >> template<typename D> void operator[](D) const = delete; >> +#if __cplusplus >= 201103L >> template<typename D> >> typename std::enable_if<std::is_integral<D>::value>::type >> operator-(D) const = delete; >> @@ -655,13 +638,11 @@ namespace __gnu_test >> operator+(std::ptrdiff_t n, random_access_iterator_wrapper<T> it) >> { return it += n; } >> >> -#if __cplusplus >= 201103L >> // Ensure that the iterator's difference_type is always used. >> template<typename T, typename D> >> void operator+(random_access_iterator_wrapper<T>, D) = delete; >> template<typename T, typename D> >> void operator+(D, random_access_iterator_wrapper<T>) = delete; >> -#endif >> >> >> template<typename T> >> @@ -809,11 +790,11 @@ namespace __gnu_test >> return tmp; >> } >> >> -#if __cplusplus >= 201103L >> // Ensure that the iterator's difference_type is always used. >> template<typename D> void operator+=(D) = delete; >> template<typename D> void operator-=(D) = delete; >> template<typename D> void operator[](D) const = delete; >> +#if __cplusplus >= 201103L >> template<typename D> >> typename std::enable_if<std::is_integral<D>::value>::type >> operator-(D) const = delete; >> @@ -857,13 +838,11 @@ namespace __gnu_test >> operator+(std::ptrdiff_t n, proxy_random_access_iterator_wrapper<T> >> it) >> { return it += n; } >> >> -#if __cplusplus >= 201103L >> // Ensure that the iterator's difference_type is always used. >> template<typename T, typename D> >> void operator+(proxy_random_access_iterator_wrapper<T>, D) = >> delete; >> template<typename T, typename D> >> void operator+(D, proxy_random_access_iterator_wrapper<T>) = >> delete; >> -#endif >> >> /** >> * @brief A container-type class for holding iterator wrappers >> @@ -1292,4 +1271,5 @@ namespace __gnu_test >> >> #endif // C++20 >> } // namespace __gnu_test >> +#pragma GCC diagnostic pop >> #endif // _TESTSUITE_ITERATORS >> -- >> 2.55.0 >> >>
