https://gcc.gnu.org/g:9ed070220ec1c837149f7b2eff7227f2e6b503e3

commit r15-2306-g9ed070220ec1c837149f7b2eff7227f2e6b503e3
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Mon Jul 22 20:40:17 2024 +0100

    libstdc++: Use concepts to simplify std::optional base classes
    
    In C++20 mode we can simplify some of the std::optional base class
    hierarchy using concepts. We can overload the destructor and copy
    constructor and move constructor with a trivial defaulted version and a
    constrained non-trivial version. This allows us to remove some class
    template partial specializations that were used to conditionally define
    those special members as trivial or non-trivial. This should not change
    any semantics, but should be less work for the compiler, due to not
    needing to match partial specializations, and completely removing one
    level of the inheritance hierarchy.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/optional (_Optional_payload_base::_Storage)
            [C++20]: Define constrained non-trivial destructor.
            (_Optional_payload_base::_Storage<U, false>) [C++20]: Do not
            define partial specialization when primary template has
            constrained destructor.
            (_Optional_base) [C++20]: Define constrained trivial copy and
            move cons and move constructors. Define payload accessors here
            instead of inheriting them from _Optional_base_impl.
            (_Optional_base_impl, _Optional_base<T, false, true>)
            (_Optional_base<T, true, false>, _Optional_base<T, true, true>)
            [C++20]: Do not define.

Diff:
---
 libstdc++-v3/include/std/optional | 166 +++++++++++++++++++++++++++-----------
 1 file changed, 121 insertions(+), 45 deletions(-)

diff --git a/libstdc++-v3/include/std/optional 
b/libstdc++-v3/include/std/optional
index 9ed7ab501402..344be5e44d3e 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -226,10 +226,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            { }
 #endif
 
+#if __cpp_concepts >= 202002L // Conditionally trivial special member functions
+         ~_Storage() = default;
+
+         // User-provided destructor is needed when _Up has non-trivial dtor.
+         _GLIBCXX20_CONSTEXPR
+         ~_Storage() requires (!is_trivially_destructible_v<_Up>)
+         { }
+
+         _Storage(const _Storage&) = default;
+         _Storage(_Storage&&) = default;
+         _Storage& operator=(const _Storage&) = default;
+         _Storage& operator=(_Storage&&) = default;
+#endif
+
          _Empty_byte _M_empty;
          _Up _M_value;
        };
 
+#if __cpp_concepts < 202002L
       template<typename _Up>
        union _Storage<_Up, false>
        {
@@ -259,9 +274,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          // User-provided destructor is needed when _Up has non-trivial dtor.
          _GLIBCXX20_CONSTEXPR ~_Storage() { }
 
+         _Storage(const _Storage&) = default;
+         _Storage(_Storage&&) = default;
+         _Storage& operator=(const _Storage&) = default;
+         _Storage& operator=(_Storage&&) = default;
+
          _Empty_byte _M_empty;
          _Up _M_value;
        };
+#endif
 
       _Storage<_Stored_type> _M_payload;
 
@@ -438,47 +459,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _GLIBCXX20_CONSTEXPR ~_Optional_payload() { this->_M_reset(); }
     };
 
-  // Common base class for _Optional_base<T> to avoid repeating these
-  // member functions in each specialization.
-  template<typename _Tp, typename _Dp>
-    class _Optional_base_impl
-    {
-    protected:
-      using _Stored_type = remove_const_t<_Tp>;
-
-      // The _M_construct operation has !_M_engaged as a precondition
-      // while _M_destruct has _M_engaged as a precondition.
-      template<typename... _Args>
-       constexpr void
-       _M_construct(_Args&&... __args)
-       noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
-       {
-         static_cast<_Dp*>(this)->_M_payload._M_construct(
-           std::forward<_Args>(__args)...);
-       }
-
-      constexpr void
-      _M_destruct() noexcept
-      { static_cast<_Dp*>(this)->_M_payload._M_destroy(); }
-
-      // _M_reset is a 'safe' operation with no precondition.
-      constexpr void
-      _M_reset() noexcept
-      { static_cast<_Dp*>(this)->_M_payload._M_reset(); }
-
-      constexpr bool _M_is_engaged() const noexcept
-      { return static_cast<const _Dp*>(this)->_M_payload._M_engaged; }
-
-      // The _M_get operations have _M_engaged as a precondition.
-      constexpr _Tp&
-      _M_get() noexcept
-      { return static_cast<_Dp*>(this)->_M_payload._M_get(); }
-
-      constexpr const _Tp&
-      _M_get() const noexcept
-      { return static_cast<const _Dp*>(this)->_M_payload._M_get(); }
-    };
-
   /**
     * @brief Class template that provides copy/move constructors of optional.
     *
@@ -501,7 +481,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
           bool = is_trivially_copy_constructible_v<_Tp>,
           bool = is_trivially_move_constructible_v<_Tp>>
     struct _Optional_base
-    : _Optional_base_impl<_Tp, _Optional_base<_Tp>>
     {
       // Constructors for disengaged optionals.
       constexpr _Optional_base() = default;
@@ -528,6 +507,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Copy and move constructors.
       constexpr
       _Optional_base(const _Optional_base& __other)
+      noexcept(is_nothrow_copy_constructible_v<_Tp>)
       : _M_payload(__other._M_payload._M_engaged, __other._M_payload)
       { }
 
@@ -538,15 +518,110 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                   std::move(__other._M_payload))
       { }
 
+#if __cpp_concepts >= 202002L // Conditionally trivial special member functions
+      // Define these in the primary template if possible, so that we don't
+      // need to use partial specializations of this class template.
+      constexpr _Optional_base(const _Optional_base&)
+       requires is_trivially_copy_constructible_v<_Tp> = default;
+
+      constexpr _Optional_base(_Optional_base&&)
+       requires is_trivially_move_constructible_v<_Tp> = default;
+#endif
+
       // Assignment operators.
       _Optional_base& operator=(const _Optional_base&) = default;
       _Optional_base& operator=(_Optional_base&&) = default;
 
       _Optional_payload<_Tp> _M_payload;
+
+    protected:
+      // For the primary template, we define these functions here.
+      using _Stored_type = remove_const_t<_Tp>;
+
+      // The _M_construct operation has !_M_engaged as a precondition
+      // while _M_destruct has _M_engaged as a precondition.
+      template<typename... _Args>
+       constexpr void
+       _M_construct(_Args&&... __args)
+       noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
+       {
+         _M_payload._M_construct(std::forward<_Args>(__args)...);
+       }
+
+      constexpr void
+      _M_destruct() noexcept
+      { _M_payload._M_destroy(); }
+
+      // _M_reset is a 'safe' operation with no precondition.
+      constexpr void
+      _M_reset() noexcept
+      { _M_payload._M_reset(); }
+
+      constexpr bool _M_is_engaged() const noexcept
+      { return _M_payload._M_engaged; }
+
+      // The _M_get operations have _M_engaged as a precondition.
+      constexpr _Tp&
+      _M_get() noexcept
+      { return _M_payload._M_get(); }
+
+      constexpr const _Tp&
+      _M_get() const noexcept
+      { return _M_payload._M_get(); }
+    };
+
+#if __cpp_concepts < 202002L
+  // If P0848R3 "Conditionally Trivial Special Member Functions" is not
+  // supported (as determined from the __cpp_concepts macro value), the
+  // _Optional_base primary template only has non-trivial copy and move
+  // constructors. Use partial specializations of _Optional_base<T, C, M>
+  // that have a trivial copy and/or move constructor.
+
+  // Common base class for _Optional_base<T> to avoid repeating these
+  // member functions in each partial specialization.
+  // Only used if P0848R3 "Conditionally Trivial Special Member Functions"
+  // is not supported, as indicated by the __cpp_concepts value.
+  template<typename _Tp, typename _Dp>
+    class _Optional_base_impl
+    {
+    protected:
+      using _Stored_type = remove_const_t<_Tp>;
+
+      // The _M_construct operation has !_M_engaged as a precondition
+      // while _M_destruct has _M_engaged as a precondition.
+      template<typename... _Args>
+       constexpr void
+       _M_construct(_Args&&... __args)
+       noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
+       {
+         static_cast<_Dp*>(this)->_M_payload._M_construct(
+           std::forward<_Args>(__args)...);
+       }
+
+      constexpr void
+      _M_destruct() noexcept
+      { static_cast<_Dp*>(this)->_M_payload._M_destroy(); }
+
+      // _M_reset is a 'safe' operation with no precondition.
+      constexpr void
+      _M_reset() noexcept
+      { static_cast<_Dp*>(this)->_M_payload._M_reset(); }
+
+      constexpr bool _M_is_engaged() const noexcept
+      { return static_cast<const _Dp*>(this)->_M_payload._M_engaged; }
+
+      // The _M_get operations have _M_engaged as a precondition.
+      constexpr _Tp&
+      _M_get() noexcept
+      { return static_cast<_Dp*>(this)->_M_payload._M_get(); }
+
+      constexpr const _Tp&
+      _M_get() const noexcept
+      { return static_cast<const _Dp*>(this)->_M_payload._M_get(); }
     };
 
   template<typename _Tp>
-    struct _Optional_base<_Tp, false, true>
+    struct _Optional_base<_Tp, false, true> // trivial move ctor
     : _Optional_base_impl<_Tp, _Optional_base<_Tp>>
     {
       // Constructors for disengaged optionals.
@@ -586,7 +661,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   template<typename _Tp>
-    struct _Optional_base<_Tp, true, false>
+    struct _Optional_base<_Tp, true, false> // trivial copy ctor
     : _Optional_base_impl<_Tp, _Optional_base<_Tp>>
     {
       // Constructors for disengaged optionals.
@@ -629,7 +704,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   template<typename _Tp>
-    struct _Optional_base<_Tp, true, true>
+    struct _Optional_base<_Tp, true, true> // trivial copy and move ctors
     : _Optional_base_impl<_Tp, _Optional_base<_Tp>>
     {
       // Constructors for disengaged optionals.
@@ -664,6 +739,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Optional_payload<_Tp> _M_payload;
     };
+#endif // __cpp_concepts
 
   template<typename _Tp>
   class optional;

Reply via email to