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
>>
>>

Reply via email to