[3/3] libstdc++: Remove non-concepts fallback for std::make_shared_for_overwrite

Message ID 20260505150351.209503-3-jwakely@redhat.com
State New
Headers
Series [1/3] libstdc++: Replace uses of EBO with [[no_unique_address]] |

Commit Message

Jonathan Wakely May 5, 2026, 3:03 p.m. UTC
  Clang 10 added support for concepts, so we no longer need to support
C++20 compilers that don't define __cpp_concepts.

libstdc++-v3/ChangeLog:

	* include/bits/shared_ptr.h (_UnboundedArray, _BoundedArray)
	(_NotUnboundedArray): Remove fallback definition for C++20
	compilers that don't define __cpp_concepts.
	* include/bits/shared_ptr_base.h (_Sp_counted_ptr_inplace):
	Remove fallback declaration of _Sp_overwrite_tag partial
	specialization.
---

Tested x86_64-linux.

 libstdc++-v3/include/bits/shared_ptr.h      | 18 ------------------
 libstdc++-v3/include/bits/shared_ptr_base.h |  5 -----
 2 files changed, 23 deletions(-)
  

Comments

Tomasz Kamiński May 6, 2026, 7:57 a.m. UTC | #1
On Tue, May 5, 2026 at 5:04 PM Jonathan Wakely <jwakely@redhat.com> wrote:

> Clang 10 added support for concepts, so we no longer need to support
> C++20 compilers that don't define __cpp_concepts.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/shared_ptr.h (_UnboundedArray, _BoundedArray)
>         (_NotUnboundedArray): Remove fallback definition for C++20
>         compilers that don't define __cpp_concepts.
>         * include/bits/shared_ptr_base.h (_Sp_counted_ptr_inplace):
>         Remove fallback declaration of _Sp_overwrite_tag partial
>         specialization.
> ---
>
> Tested x86_64-linux.
>
>  libstdc++-v3/include/bits/shared_ptr.h      | 18 ------------------
>  libstdc++-v3/include/bits/shared_ptr_base.h |  5 -----
>  2 files changed, 23 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/shared_ptr.h
> b/libstdc++-v3/include/bits/shared_ptr.h
> index fd00384df223..ada32d3d3cb9 100644
> --- a/libstdc++-v3/include/bits/shared_ptr.h
> +++ b/libstdc++-v3/include/bits/shared_ptr.h
> @@ -114,38 +114,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
>  #if __glibcxx_shared_ptr_arrays >= 201707L
>    // Constraint for overloads taking array types with unknown bound, U[].
> -#if __cpp_concepts
>    template<typename _Tp>
>      requires is_array_v<_Tp> && (extent_v<_Tp> == 0)
>      using _UnboundedArray = _Tp;
>
Could we replace this constrained alias with requires/concept on the
function?
that are using it? This version was always deductible, so shouldn't make
difference.
May however change mangling.

> -#else
> -  template<typename _Tp>
> -    using _UnboundedArray
> -      = __enable_if_t<__is_array_unknown_bounds<_Tp>::value, _Tp>;
> -#endif
>
>    // Constraint for overloads taking array types with known bound, U[N].
> -#if __cpp_concepts
>    template<typename _Tp>
>      requires (extent_v<_Tp> != 0)
>      using _BoundedArray = _Tp;
> -#else
> -  template<typename _Tp>
> -    using _BoundedArray
> -      = __enable_if_t<__is_array_known_bounds<_Tp>::value, _Tp>;
> -#endif
>
>  #if __glibcxx_smart_ptr_for_overwrite
>    // Constraint for overloads taking either non-array or bounded array,
> U[N].
> -#if __cpp_concepts
>    template<typename _Tp>
>      requires (!is_array_v<_Tp>) || (extent_v<_Tp> != 0)
>      using _NotUnboundedArray = _Tp;
> -#else
> -  template<typename _Tp>
> -    using _NotUnboundedArray
> -      = __enable_if_t<!__is_array_unknown_bounds<_Tp>::value, _Tp>;
> -#endif
>  #endif // smart_ptr_for_overwrite
>  #endif // shared_ptr_arrays
>
> diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h
> b/libstdc++-v3/include/bits/shared_ptr_base.h
> index cf1be953af2c..a64131bb9e12 100644
> --- a/libstdc++-v3/include/bits/shared_ptr_base.h
> +++ b/libstdc++-v3/include/bits/shared_ptr_base.h
> @@ -696,14 +696,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>    // Partial specialization used for
> make_shared_for_overwrite<non-array>().
>    // This partial specialization is used when the allocator's value type
>    // is the special _Sp_overwrite_tag type.
> -#if __cpp_concepts
>    template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
>      requires is_same_v<typename _Alloc::value_type, _Sp_overwrite_tag>
>      class _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> final
> -#else
> -  template<typename _Tp, template<typename> class _Alloc, _Lock_policy
> _Lp>
> -    class _Sp_counted_ptr_inplace<_Tp, _Alloc<_Sp_overwrite_tag>, _Lp>
> final
> -#endif
>      : public _Sp_counted_base<_Lp>
>      {
>        [[no_unique_address]] _Alloc _M_alloc;
> --
> 2.54.0
>
>
  
Jonathan Wakely May 6, 2026, 9:01 a.m. UTC | #2
On Wed, 6 May 2026 at 08:57, Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>
>
>
> On Tue, May 5, 2026 at 5:04 PM Jonathan Wakely <jwakely@redhat.com> wrote:
>>
>> Clang 10 added support for concepts, so we no longer need to support
>> C++20 compilers that don't define __cpp_concepts.
>>
>> libstdc++-v3/ChangeLog:
>>
>>         * include/bits/shared_ptr.h (_UnboundedArray, _BoundedArray)
>>         (_NotUnboundedArray): Remove fallback definition for C++20
>>         compilers that don't define __cpp_concepts.
>>         * include/bits/shared_ptr_base.h (_Sp_counted_ptr_inplace):
>>         Remove fallback declaration of _Sp_overwrite_tag partial
>>         specialization.
>> ---
>>
>> Tested x86_64-linux.
>>
>>  libstdc++-v3/include/bits/shared_ptr.h      | 18 ------------------
>>  libstdc++-v3/include/bits/shared_ptr_base.h |  5 -----
>>  2 files changed, 23 deletions(-)
>>
>> diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h
>> index fd00384df223..ada32d3d3cb9 100644
>> --- a/libstdc++-v3/include/bits/shared_ptr.h
>> +++ b/libstdc++-v3/include/bits/shared_ptr.h
>> @@ -114,38 +114,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>
>>  #if __glibcxx_shared_ptr_arrays >= 201707L
>>    // Constraint for overloads taking array types with unknown bound, U[].
>> -#if __cpp_concepts
>>    template<typename _Tp>
>>      requires is_array_v<_Tp> && (extent_v<_Tp> == 0)
>>      using _UnboundedArray = _Tp;
>
> Could we replace this constrained alias with requires/concept on the function?
> that are using it? This version was always deductible, so shouldn't make difference.

I wanted to do that, but just above this diff we have:

  // Constraint for overloads taking non-array types.
#if __cpp_concepts && __glibcxx_type_trait_variable_templates
  template<typename _Tp>
    requires (!is_array_v<_Tp>)
    using _NonArray = _Tp;
#else
  template<typename _Tp>
    using _NonArray = __enable_if_t<!is_array<_Tp>::value, _Tp>;
#endif

That *can't* use a requires-clause, it has to continue using a
constrained alias for C++11 mode.

That means that std::make_shared and std::allocate_shared are
constrained using the alias:

  template<typename _Yp, typename _Alloc, typename... _Args>
    friend shared_ptr<_NonArray<_Yp>>
    allocate_shared(const _Alloc&, _Args&&...);

  template<typename _Yp, typename... _Args>
    friend shared_ptr<_NonArray<_Yp>>
    make_shared(_Args&&...);

So for consistency I didn't want to change how the C++20 overloads are defined:

  template<typename _Yp, typename _Alloc>
    friend shared_ptr<_UnboundedArray<_Yp>>
    allocate_shared(const _Alloc&, size_t);

  template<typename _Yp>
    friend shared_ptr<_UnboundedArray<_Yp>>
    make_shared(size_t);

We could do it for the C++20 ones. I think it would still work
correctly to have the C++11 overloads constrained using the alias and
the later ones constrained using a requires-clause. The conditions
that enable each overload are mutually exclusive, so there would be no
concerns about the interaction between the different types of
constraints on overload resolution. There would still be exactly one
viable candidate for any given call.

For make_shared_for_overwrite we don't have to worry about the
interaction with the C++11 overload, because there is no C++11
overload. So we could change that to use a requires-clause, but it
would still look inconsistent with the related (not "_for_overwrite")
function templates.

Also, because these make_shared* and allocate_shared* function
templates are all friends, if we use a requires-clause it needs to be
repeated in two places.

So yes, it would be possible. I considered it, and decided to keep the
aliases (at least for now).
  
Tomasz Kamiński May 6, 2026, 9:59 a.m. UTC | #3
On Wed, May 6, 2026 at 11:01 AM Jonathan Wakely <jwakely@redhat.com> wrote:

> On Wed, 6 May 2026 at 08:57, Tomasz Kaminski <tkaminsk@redhat.com> wrote:
> >
> >
> >
> > On Tue, May 5, 2026 at 5:04 PM Jonathan Wakely <jwakely@redhat.com>
> wrote:
> >>
> >> Clang 10 added support for concepts, so we no longer need to support
> >> C++20 compilers that don't define __cpp_concepts.
> >>
> >> libstdc++-v3/ChangeLog:
> >>
> >>         * include/bits/shared_ptr.h (_UnboundedArray, _BoundedArray)
> >>         (_NotUnboundedArray): Remove fallback definition for C++20
> >>         compilers that don't define __cpp_concepts.
> >>         * include/bits/shared_ptr_base.h (_Sp_counted_ptr_inplace):
> >>         Remove fallback declaration of _Sp_overwrite_tag partial
> >>         specialization.
> >> ---
> >>
> >> Tested x86_64-linux.
> >>
> >>  libstdc++-v3/include/bits/shared_ptr.h      | 18 ------------------
> >>  libstdc++-v3/include/bits/shared_ptr_base.h |  5 -----
> >>  2 files changed, 23 deletions(-)
> >>
> >> diff --git a/libstdc++-v3/include/bits/shared_ptr.h
> b/libstdc++-v3/include/bits/shared_ptr.h
> >> index fd00384df223..ada32d3d3cb9 100644
> >> --- a/libstdc++-v3/include/bits/shared_ptr.h
> >> +++ b/libstdc++-v3/include/bits/shared_ptr.h
> >> @@ -114,38 +114,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >>
> >>  #if __glibcxx_shared_ptr_arrays >= 201707L
> >>    // Constraint for overloads taking array types with unknown bound,
> U[].
> >> -#if __cpp_concepts
> >>    template<typename _Tp>
> >>      requires is_array_v<_Tp> && (extent_v<_Tp> == 0)
> >>      using _UnboundedArray = _Tp;
> >
> > Could we replace this constrained alias with requires/concept on the
> function?
> > that are using it? This version was always deductible, so shouldn't make
> difference.
>
> I wanted to do that, but just above this diff we have:
>
>   // Constraint for overloads taking non-array types.
> #if __cpp_concepts && __glibcxx_type_trait_variable_templates
>   template<typename _Tp>
>     requires (!is_array_v<_Tp>)
>     using _NonArray = _Tp;
> #else
>   template<typename _Tp>
>     using _NonArray = __enable_if_t<!is_array<_Tp>::value, _Tp>;
> #endif
>
> That *can't* use a requires-clause, it has to continue using a
> constrained alias for C++11 mode.
>
> That means that std::make_shared and std::allocate_shared are
> constrained using the alias:
>
>   template<typename _Yp, typename _Alloc, typename... _Args>
>     friend shared_ptr<_NonArray<_Yp>>
>     allocate_shared(const _Alloc&, _Args&&...);
>
>   template<typename _Yp, typename... _Args>
>     friend shared_ptr<_NonArray<_Yp>>
>     make_shared(_Args&&...);
>
> So for consistency I didn't want to change how the C++20 overloads are
> defined:
>
>   template<typename _Yp, typename _Alloc>
>     friend shared_ptr<_UnboundedArray<_Yp>>
>     allocate_shared(const _Alloc&, size_t);
>
>   template<typename _Yp>
>     friend shared_ptr<_UnboundedArray<_Yp>>
>     make_shared(size_t);
>
> We could do it for the C++20 ones. I think it would still work
> correctly to have the C++11 overloads constrained using the alias and
> the later ones constrained using a requires-clause. The conditions
> that enable each overload are mutually exclusive, so there would be no
> concerns about the interaction between the different types of
> constraints on overload resolution. There would still be exactly one
> viable candidate for any given call.
>
> For make_shared_for_overwrite we don't have to worry about the
> interaction with the C++11 overload, because there is no C++11
> overload. So we could change that to use a requires-clause, but it
> would still look inconsistent with the related (not "_for_overwrite")
> function templates.
>
> Also, because these make_shared* and allocate_shared* function
> templates are all friends, if we use a requires-clause it needs to be
> repeated in two places.
>
> So yes, it would be possible. I considered it, and decided to keep the
> aliases (at least for now).
>
That makes sense, thanks for the detailed explanation.
  

Patch

diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h
index fd00384df223..ada32d3d3cb9 100644
--- a/libstdc++-v3/include/bits/shared_ptr.h
+++ b/libstdc++-v3/include/bits/shared_ptr.h
@@ -114,38 +114,20 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __glibcxx_shared_ptr_arrays >= 201707L
   // Constraint for overloads taking array types with unknown bound, U[].
-#if __cpp_concepts
   template<typename _Tp>
     requires is_array_v<_Tp> && (extent_v<_Tp> == 0)
     using _UnboundedArray = _Tp;
-#else
-  template<typename _Tp>
-    using _UnboundedArray
-      = __enable_if_t<__is_array_unknown_bounds<_Tp>::value, _Tp>;
-#endif
 
   // Constraint for overloads taking array types with known bound, U[N].
-#if __cpp_concepts
   template<typename _Tp>
     requires (extent_v<_Tp> != 0)
     using _BoundedArray = _Tp;
-#else
-  template<typename _Tp>
-    using _BoundedArray
-      = __enable_if_t<__is_array_known_bounds<_Tp>::value, _Tp>;
-#endif
 
 #if __glibcxx_smart_ptr_for_overwrite
   // Constraint for overloads taking either non-array or bounded array, U[N].
-#if __cpp_concepts
   template<typename _Tp>
     requires (!is_array_v<_Tp>) || (extent_v<_Tp> != 0)
     using _NotUnboundedArray = _Tp;
-#else
-  template<typename _Tp>
-    using _NotUnboundedArray
-      = __enable_if_t<!__is_array_unknown_bounds<_Tp>::value, _Tp>;
-#endif
 #endif // smart_ptr_for_overwrite
 #endif // shared_ptr_arrays
 
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index cf1be953af2c..a64131bb9e12 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -696,14 +696,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Partial specialization used for make_shared_for_overwrite<non-array>().
   // This partial specialization is used when the allocator's value type
   // is the special _Sp_overwrite_tag type.
-#if __cpp_concepts
   template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
     requires is_same_v<typename _Alloc::value_type, _Sp_overwrite_tag>
     class _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> final
-#else
-  template<typename _Tp, template<typename> class _Alloc, _Lock_policy _Lp>
-    class _Sp_counted_ptr_inplace<_Tp, _Alloc<_Sp_overwrite_tag>, _Lp> final
-#endif
     : public _Sp_counted_base<_Lp>
     {
       [[no_unique_address]] _Alloc _M_alloc;