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.
> +#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
>
>