On Tue, 25 Aug 2026, Tomasz Kaminski wrote:

> 
> 
> On Tue, Aug 25, 2026 at 3:12 PM Patrick Palka <[email protected]> wrote:
>       On Tue, 25 Aug 2026, Tomasz Kaminski wrote:
> 
>       >
>       >
>       > On Tue, Aug 25, 2026 at 6:11 AM Patrick Palka <[email protected]> 
> wrote:
>       >       Tested on x86_64-pc-linux-gnu, does this look OK for trunk/16?
>       >
>       >       -- >8 --
>       >
>       >       This implements the [util.smartptr.shared.const] constraints on 
> the
>       >       constructors that take a deleter (which before C++20 were 
> requirements
>       >       rather than constraints).
>       >
>       >               PR libstdc++/126120
>       >
>       >       libstdc++-v3/ChangeLog:
>       >
>       >               * include/bits/shared_ptr.h
>       >               (shared_ptr::shared_ptr(nullptr_t, ...)): Add 
> _Constructible
>       >               constraint to verify __shared_ptr base initialization is
>       >               well-formed.
>       >               * include/bits/shared_ptr_base.h (_ValidDeleter): New 
> __enable_if_t
>       >               constraint.
>       >               (__shared_ptr::__shared_ptr(..., _Deleter, ...)): Remove
>       >               static_assert checking deleter invocability.  Add 
> _ValidDeleter
>       >               constraint.
>       >               * testsuite/20_util/shared_ptr/cons/126120.cc: New test.
>       >       ---
>       >        libstdc++-v3/include/bits/shared_ptr.h        |  5 +--
>       >        libstdc++-v3/include/bits/shared_ptr_base.h   | 29 
> ++++++++---------
>       >        .../20_util/shared_ptr/cons/126120.cc         | 31 
> +++++++++++++++++++
>       >        3 files changed, 49 insertions(+), 16 deletions(-)
>       >        create mode 100644 
> libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc
>       >
>       >       diff --git a/libstdc++-v3/include/bits/shared_ptr.h 
> b/libstdc++-v3/include/bits/shared_ptr.h
>       >       index 8be9aace1711..28b8a3ca8f29 100644
>       >       --- a/libstdc++-v3/include/bits/shared_ptr.h
>       >       +++ b/libstdc++-v3/include/bits/shared_ptr.h
>       >       @@ -225,7 +225,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       >               *
>       >               *  The last owner will call __d(__p)
>       >               */
>       >       -      template<typename _Deleter>
>       >       +      template<typename _Deleter, typename = 
> _Constructible<nullptr_t, _Deleter>>
>       >               shared_ptr(nullptr_t __p, _Deleter __d)
>       >                : __shared_ptr<_Tp>(__p, std::move(__d)) { }
>       >
>       > Could you add example from LWG4110 
> (https://cplusplus.github.io/LWG/lwg-active.html#4110),
>       > I think the resolution requires that we add a dummy parameter (with a 
> default argument).
>       > which type is well-formed when _ValidDeleter is true.
> 
>       Done, like so?
> 
> Yeah, not sure about use of nullptr_t as type of parameter, wonder if that 
> can cause ambiguity
> when argument passed as allocator conflicts with it, but I do not think 
> anybody would pass literal
> 0 as it, so seem to be OK.

Ah yeah, we now have two similar ctors that take three parameters:

   shared_ptr(nullptr_t, _Deleter, _ValidDeleter<_Deleter, nullptr_t>>
   shared_ptr(nullptr_t, _Deleter, _Alloc)

making

  shared_ptr w(nullptr, [](auto pointer) { }, 0)

now ambiguous (since _ValidDeleter resolves to int).  Such a ctor call
will probably always be ill-formed anyway but IIUC we can avoid this
ambiguity by just using a unique empty type instead of int.

Alternatively we could constrain the _Alloc parameters with
_RequireAllocator?  I went with the first approach for now.

Subject: [PATCH] libstdc++: Fix SFINAE with shared_ptr and invalid deleter
 [PR126120]

Tested on x86_64-pc-linux-gnu, does this look OK for trunk/16?

Changes in v3:
  - Make _ValidDeleter return a unique empty type, not int, to avoid
    ambiguity with the corresponding 3-parameter _Alloc constructor.
  - Fix LWG 4110 testcase to use a generic lambda with deduced return
    type, and even in C++11 mode.

Changes in v2:
  - Implement LWG 4110 proposed resolution, encoding the _ValidDeleter
    constraint as a function parameter instead of a template parameter.
  - Remove redundant is_move_constructible constraint in _ValidDeleter
    since the derived class's _Constructible constraint already checks
    it.

-- >8 --

This implements the [util.smartptr.shared.const] constraints on the
constructors that take a deleter (which before C++20 were requirements
rather than constraints).  In passing proactively implement the proposed
resolution of LWG 4110 which relaxes these constraints on the nullptr_t
overloads.

        PR libstdc++/126120

libstdc++-v3/ChangeLog:

        * include/bits/shared_ptr.h
        (shared_ptr::shared_ptr(nullptr_t, ...)): Add _Constructible
        constraint to verify __shared_ptr base initialization is
        well-formed.  Add _ValidDeleter constraint.
        * include/bits/shared_ptr_base.h (_ValidDeleter_type): New.
        (_ValidDeleter): New __enable_if_t constraint.
        (__shared_ptr::__shared_ptr(Yp*, _Deleter, ...)): Remove
        static_assert checking deleter invocability.  Add _ValidDeleter
        constraint.
        * testsuite/20_util/shared_ptr/cons/126120.cc: New test.
---
 libstdc++-v3/include/bits/shared_ptr.h        | 15 +++++--
 libstdc++-v3/include/bits/shared_ptr_base.h   | 23 +++++-----
 .../20_util/shared_ptr/cons/126120.cc         | 45 +++++++++++++++++++
 3 files changed, 67 insertions(+), 16 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc

diff --git a/libstdc++-v3/include/bits/shared_ptr.h 
b/libstdc++-v3/include/bits/shared_ptr.h
index 8be9aace1711..6b9acdcffa94 100644
--- a/libstdc++-v3/include/bits/shared_ptr.h
+++ b/libstdc++-v3/include/bits/shared_ptr.h
@@ -212,6 +212,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        shared_ptr(_Yp* __p, _Deleter __d)
         : __shared_ptr<_Tp>(__p, std::move(__d)) { }
 
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 4110. shared_ptr(nullptr_t, Deleter) is overconstrained, breaking some
+      // sensible deleters
+
       /**
        *  @brief  Construct a %shared_ptr that owns a null pointer
        *          and the deleter @a __d.
@@ -225,8 +229,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  The last owner will call __d(__p)
        */
-      template<typename _Deleter>
-       shared_ptr(nullptr_t __p, _Deleter __d)
+      template<typename _Deleter, typename = _Constructible<nullptr_t, 
_Deleter>>
+       shared_ptr(nullptr_t __p, _Deleter __d,
+                  _ValidDeleter<_Deleter, nullptr_t> = {})
         : __shared_ptr<_Tp>(__p, std::move(__d)) { }
 
       /**
@@ -264,8 +269,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *
        *  The last owner will call __d(__p)
        */
-      template<typename _Deleter, typename _Alloc>
-       shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
+      template<typename _Deleter, typename _Alloc,
+              typename = _Constructible<nullptr_t, _Deleter, _Alloc>>
+       shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a,
+                  _ValidDeleter<_Deleter, nullptr_t> = {})
        : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
 
       // Aliasing constructor
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h 
b/libstdc++-v3/include/bits/shared_ptr_base.h
index c8342b7904a5..e4dc40157c52 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -1469,6 +1469,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
     };
 
+  // Constraint for well-formedness of deleter expression d(p):
+  struct _ValidDeleter_type { };
+  template<typename _Deleter, typename _Up>
+    using _ValidDeleter = __enable_if_t<__is_invocable<_Deleter&, _Up&>::value,
+                                       _ValidDeleter_type>;
+
   template<typename _Tp, _Lock_policy _Lp>
     class __shared_ptr
     : public __shared_ptr_access<_Tp, _Lp>
@@ -1524,24 +1530,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_enable_shared_from_this_with(__p);
        }
 
-      template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>>
+      template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>,
+              typename = _ValidDeleter<_Deleter, _Yp*>>
        __shared_ptr(_Yp* __p, _Deleter __d)
        : _M_ptr(__p), _M_refcount(__p, std::move(__d))
-       {
-         static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
-             "deleter expression d(p) is well-formed");
-         _M_enable_shared_from_this_with(__p);
-       }
+       { _M_enable_shared_from_this_with(__p); }
 
       template<typename _Yp, typename _Deleter, typename _Alloc,
-              typename = _SafeConv<_Yp>>
+              typename = _SafeConv<_Yp>, typename = _ValidDeleter<_Deleter, 
_Yp*>>
        __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
        : _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a))
-       {
-         static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
-             "deleter expression d(p) is well-formed");
-         _M_enable_shared_from_this_with(__p);
-       }
+       { _M_enable_shared_from_this_with(__p); }
 
       template<typename _Deleter>
        __shared_ptr(nullptr_t __p, _Deleter __d)
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc 
b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc
new file mode 100644
index 000000000000..7a82358200e3
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc
@@ -0,0 +1,45 @@
+// PR libstdc++/126120 - is_constructible_v with shared_ptr from an invalid 
deleter
+// { dg-do compile { target c++11 } }
+
+#include <memory>
+#include <type_traits>
+
+struct NonDeleter { };
+
+struct NonMoveableDeleter
+{
+  NonMoveableDeleter() = default;
+  NonMoveableDeleter(const NonMoveableDeleter&) = delete;
+  void operator()(int* p) const { delete p; }
+};
+
+using shared_ptr = std::shared_ptr<int>;
+using Alloc = std::allocator<int>;
+
+// 1. Pointer + Deleter
+static_assert( ! std::is_constructible<shared_ptr, int*, NonDeleter>::value, 
"");
+static_assert( ! std::is_constructible<shared_ptr, int*, 
NonMoveableDeleter>::value, "");
+
+// 2. Pointer + Deleter + Allocator
+static_assert( ! std::is_constructible<shared_ptr, int*, NonDeleter, 
Alloc>::value, "");
+static_assert( ! std::is_constructible<shared_ptr, int*, NonMoveableDeleter, 
Alloc>::value, "");
+
+// 3. nullptr_t + Deleter
+static_assert( ! std::is_constructible<shared_ptr, std::nullptr_t, 
NonDeleter>::value, "");
+static_assert( ! std::is_constructible<shared_ptr, std::nullptr_t, 
NonMoveableDeleter>::value, "");
+
+// 4. nullptr_t + Deleter + Allocator
+static_assert( ! std::is_constructible<shared_ptr, std::nullptr_t, NonDeleter, 
Alloc>::value, "");
+static_assert( ! std::is_constructible<shared_ptr, std::nullptr_t, 
NonMoveableDeleter, Alloc>::value, "");
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++20-extensions" // lambda template
+void
+test_lwg4110()
+{
+  // LWG 4110 - shared_ptr(nullptr_t, Deleter) is overconstrained, breaking 
some sensible deleters
+  auto deleter = []<typename T>(T pointer) { delete pointer; };
+  shared_ptr p(new int, deleter);
+  shared_ptr q(new int, deleter, Alloc{});
+}
+#pragma GCC diagnostic pop
-- 
2.55.0.708.g2c3adbb2c4

>  
> 
>       Subject: [PATCH] libstdc++: Fix SFINAE with shared_ptr and invalid 
> deleter
>        [PR126120]
> 
>       Tested on x86_64-pc-linux-gnu, does this look OK for trunk/16?
> 
>       Changes in v2:
>         - Implement LWG 4110 proposed resolution, encoding the _ValidDeleter
>           constraint as a function parameter instead of a template parameter.
>         - Remove redundant is_move_constructible constraint in _ValidDeleter
>           since the derived class's _Constructible constraint already checks
>           it.
> 
>       -- >8 --
> 
>       This implements the [util.smartptr.shared.const] constraints on the
>       constructors that take a deleter (which before C++20 were requirements
>       rather than constraints).  In passing proactively implement the proposed
>       resolution of LWG 4110.
> 
>               PR libstdc++/126120
> 
>       libstdc++-v3/ChangeLog:
> 
>               * include/bits/shared_ptr.h
>               (shared_ptr::shared_ptr(nullptr_t, ...)): Add _Constructible
>               constraint to verify __shared_ptr base initialization is
>               well-formed.  Add _ValidDeleter constraint.
>               * include/bits/shared_ptr_base.h (_ValidDeleter): New 
> __enable_if_t
>               constraint.
>               (__shared_ptr::__shared_ptr(Yp*, _Deleter, ...)): Remove
>               static_assert checking deleter invocability.  Add _ValidDeleter
>               constraint.
>               * testsuite/20_util/shared_ptr/cons/126120.cc: New test.
>       ---
>        libstdc++-v3/include/bits/shared_ptr.h        | 15 +++++--
>        libstdc++-v3/include/bits/shared_ptr_base.h   | 21 ++++-----
>        .../20_util/shared_ptr/cons/126120.cc         | 45 +++++++++++++++++++
>        3 files changed, 65 insertions(+), 16 deletions(-)
>        create mode 100644 
> libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc
> 
>       diff --git a/libstdc++-v3/include/bits/shared_ptr.h 
> b/libstdc++-v3/include/bits/shared_ptr.h
>       index 8be9aace1711..6b9acdcffa94 100644
>       --- a/libstdc++-v3/include/bits/shared_ptr.h
>       +++ b/libstdc++-v3/include/bits/shared_ptr.h
>       @@ -212,6 +212,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>               shared_ptr(_Yp* __p, _Deleter __d)
>                : __shared_ptr<_Tp>(__p, std::move(__d)) { }
> 
>       +      // _GLIBCXX_RESOLVE_LIB_DEFECTS
>       +      // 4110. shared_ptr(nullptr_t, Deleter) is overconstrained, 
> breaking some
>       +      // sensible deleters
>       +
>              /**
>               *  @brief  Construct a %shared_ptr that owns a null pointer
>               *          and the deleter @a __d.
>       @@ -225,8 +229,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>               *
>               *  The last owner will call __d(__p)
>               */
>       -      template<typename _Deleter>
>       -       shared_ptr(nullptr_t __p, _Deleter __d)
>       +      template<typename _Deleter, typename = _Constructible<nullptr_t, 
> _Deleter>>
>       +       shared_ptr(nullptr_t __p, _Deleter __d,
>       +                  _ValidDeleter<_Deleter, nullptr_t> = {})
>                : __shared_ptr<_Tp>(__p, std::move(__d)) { }
> 
>              /**
>       @@ -264,8 +269,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>               *
>               *  The last owner will call __d(__p)
>               */
>       -      template<typename _Deleter, typename _Alloc>
>       -       shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
>       +      template<typename _Deleter, typename _Alloc,
>       +              typename = _Constructible<nullptr_t, _Deleter, _Alloc>>
>       +       shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a,
>       +                  _ValidDeleter<_Deleter, nullptr_t> = {})
>               : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
> 
>              // Aliasing constructor
>       diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h 
> b/libstdc++-v3/include/bits/shared_ptr_base.h
>       index c8342b7904a5..7c1f965f0bb1 100644
>       --- a/libstdc++-v3/include/bits/shared_ptr_base.h
>       +++ b/libstdc++-v3/include/bits/shared_ptr_base.h
>       @@ -1469,6 +1469,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>              { return static_cast<const __shared_ptr<_Tp, 
> _Lp>*>(this)->get(); }
>            };
> 
>       +  // Constraint for well-formedness of deleter expression d(p):
>       +  template<typename _Deleter, typename _Up>
>       +    using _ValidDeleter = __enable_if_t<__is_invocable<_Deleter&, 
> _Up&>::value, int>;
>       +
>          template<typename _Tp, _Lock_policy _Lp>
>            class __shared_ptr
>            : public __shared_ptr_access<_Tp, _Lp>
>       @@ -1524,24 +1528,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>                 _M_enable_shared_from_this_with(__p);
>               }
> 
>       -      template<typename _Yp, typename _Deleter, typename = 
> _SafeConv<_Yp>>
>       +      template<typename _Yp, typename _Deleter, typename = 
> _SafeConv<_Yp>,
>       +              typename = _ValidDeleter<_Deleter, _Yp*>>
>               __shared_ptr(_Yp* __p, _Deleter __d)
>               : _M_ptr(__p), _M_refcount(__p, std::move(__d))
>       -       {
>       -         static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
>       -             "deleter expression d(p) is well-formed");
>       -         _M_enable_shared_from_this_with(__p);
>       -       }
>       +       { _M_enable_shared_from_this_with(__p); }
> 
>              template<typename _Yp, typename _Deleter, typename _Alloc,
>       -              typename = _SafeConv<_Yp>>
>       +              typename = _SafeConv<_Yp>, typename = 
> _ValidDeleter<_Deleter, _Yp*>>
>               __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
>               : _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a))
>       -       {
>       -         static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
>       -             "deleter expression d(p) is well-formed");
>       -         _M_enable_shared_from_this_with(__p);
>       -       }
>       +       { _M_enable_shared_from_this_with(__p); }
> 
>              template<typename _Deleter>
>               __shared_ptr(nullptr_t __p, _Deleter __d)
>       diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc 
> b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc
>       new file mode 100644
>       index 000000000000..0d3f84e2e779
>       --- /dev/null
>       +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc
>       @@ -0,0 +1,45 @@
>       +// PR libstdc++/126120 - is_constructible_v with shared_ptr from an 
> invalid deleter
>       +// { dg-do compile { target c++11 } }
>       +
>       +#include <memory>
>       +#include <type_traits>
>       +
>       +struct NonDeleter { };
>       +
>       +struct NonMoveableDeleter
>       +{
>       +  NonMoveableDeleter() = default;
>       +  NonMoveableDeleter(const NonMoveableDeleter&) = delete;
>       +  void operator()(int*) const;
>       +};
>       +
>       +using shared_ptr = std::shared_ptr<int>;
>       +using Alloc = std::allocator<int>;
>       +
>       +// 1. Pointer + Deleter
>       +static_assert( ! std::is_constructible<shared_ptr, int*, 
> NonDeleter>::value, "");
>       +static_assert( ! std::is_constructible<shared_ptr, int*, 
> NonMoveableDeleter>::value, "");
>       +
>       +// 2. Pointer + Deleter + Allocator
>       +static_assert( ! std::is_constructible<shared_ptr, int*, NonDeleter, 
> Alloc>::value, "");
>       +static_assert( ! std::is_constructible<shared_ptr, int*, 
> NonMoveableDeleter, Alloc>::value, "");
>       +
>       +// 3. nullptr_t + Deleter
>       +static_assert( ! std::is_constructible<shared_ptr, std::nullptr_t, 
> NonDeleter>::value, "");
>       +static_assert( ! std::is_constructible<shared_ptr, std::nullptr_t, 
> NonMoveableDeleter>::value, "");
>       +
>       +// 4. nullptr_t + Deleter + Allocator
>       +static_assert( ! std::is_constructible<shared_ptr, std::nullptr_t, 
> NonDeleter, Alloc>::value, "");
>       +static_assert( ! std::is_constructible<shared_ptr, std::nullptr_t, 
> NonMoveableDeleter, Alloc>::value, "");
>       +
>       +struct GenericDeleter {
>       +  template<typename T> void operator()(T*) const; 
> 
>       +};
>       +
>       +void
>       +test01()
>       +{
>       +  // LWG 4110 - shared_ptr(nullptr_t, Deleter) is overconstrained, 
> breaking some sensible deleters
>       +  shared_ptr p(new int, GenericDeleter{});
>       +  shared_ptr q(new int, GenericDeleter{}, Alloc{});
> 
> I do not think that above example reproduces problem from the issue, checking 
> is invocable
> <GenericDeleter, nullptr> is simply true. The lambda with auto was important, 
> as checking is
> invocable triggered return type deduction, which instantiated delete with 
> nullptr, that was ill-formed.
>       +}
>       --
>       2.55.0.708.g2c3adbb2c4
> 
> 
> 
>       >
>       >  
>       >
>       >       @@ -264,7 +264,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       >               *
>       >               *  The last owner will call __d(__p)
>       >               */
>       >       -      template<typename _Deleter, typename _Alloc>
>       >       +      template<typename _Deleter, typename _Alloc,
>       >       +              typename = _Constructible<nullptr_t, _Deleter, 
> _Alloc>>
>       >               shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
>       >              : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) 
> { }
>       >
>       >
>       >
>       >       diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h 
> b/libstdc++-v3/include/bits/shared_ptr_base.h
>       >       index c8342b7904a5..2eb3436183ee 100644
>       >       --- a/libstdc++-v3/include/bits/shared_ptr_base.h
>       >       +++ b/libstdc++-v3/include/bits/shared_ptr_base.h
>       >       @@ -1469,6 +1469,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       >              { return static_cast<const __shared_ptr<_Tp, 
> _Lp>*>(this)->get(); }
>       >            };
>       >
>       >       +  // Constraint for well-formedness of deleter expression d(p):
>       >       +  template<typename _Deleter, typename _Up>
>       >       +    using _ValidDeleter = __enable_if_t<__and_<
>       >       +      is_move_constructible<_Deleter>,
>       >       +      __is_invocable<_Deleter&, _Up&>
>       >       +      >::value>;
>       >       +
>       >          template<typename _Tp, _Lock_policy _Lp>
>       >            class __shared_ptr
>       >            : public __shared_ptr_access<_Tp, _Lp>
>       >       @@ -1524,31 +1531,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       >                 _M_enable_shared_from_this_with(__p);
>       >               }
>       >
>       >       -      template<typename _Yp, typename _Deleter, typename = 
> _SafeConv<_Yp>>
>       >       +      template<typename _Yp, typename _Deleter, typename = 
> _SafeConv<_Yp>,
>       >       +              typename = _ValidDeleter<_Deleter, _Yp*>>
>       >               __shared_ptr(_Yp* __p, _Deleter __d)
>       >               : _M_ptr(__p), _M_refcount(__p, std::move(__d))
>       >       -       {
>       >       -         static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
>       >       -             "deleter expression d(p) is well-formed");
>       >       -         _M_enable_shared_from_this_with(__p);
>       >       -       }
>       >       +       { _M_enable_shared_from_this_with(__p); }
>       >
>       >              template<typename _Yp, typename _Deleter, typename 
> _Alloc,
>       >       -              typename = _SafeConv<_Yp>>
>       >       +              typename = _SafeConv<_Yp>, typename = 
> _ValidDeleter<_Deleter, _Yp*>>
>       >               __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
>       >               : _M_ptr(__p), _M_refcount(__p, std::move(__d), 
> std::move(__a))
>       >       -       {
>       >       -         static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
>       >       -             "deleter expression d(p) is well-formed");
>       >       -         _M_enable_shared_from_this_with(__p);
>       >       -       }
>       >       +       { _M_enable_shared_from_this_with(__p); }
>       >
>       >       -      template<typename _Deleter>
>       >       +      template<typename _Deleter, typename = 
> _ValidDeleter<_Deleter, nullptr_t>>
>       >               __shared_ptr(nullptr_t __p, _Deleter __d)
>       >               : _M_ptr(0), _M_refcount(__p, std::move(__d))
>       >               { }
>       >
>       >       -      template<typename _Deleter, typename _Alloc>
>       >       +      template<typename _Deleter, typename _Alloc,
>       >       +              typename = _ValidDeleter<_Deleter, nullptr_t>>
>       >                __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
>       >               : _M_ptr(0), _M_refcount(__p, std::move(__d), 
> std::move(__a))
>       >               { }
>       >       diff --git 
> a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc 
> b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc
>       >       new file mode 100644
>       >       index 000000000000..a5a29597e078
>       >       --- /dev/null
>       >       +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/126120.cc
>       >       @@ -0,0 +1,31 @@
>       >       +// PR libstdc++/126120 - is_constructible_v with shared_ptr 
> from an invalid deleter
>       >       +// { dg-do compile { target c++11 } }
>       >       +
>       >       +#include <memory>
>       >       +#include <type_traits>
>       >       +
>       >       +struct NonDeleter { };
>       >       +
>       >       +struct NonMoveableDeleter {
>       >       +  NonMoveableDeleter() = default;
>       >       +  NonMoveableDeleter(const NonMoveableDeleter&) = delete;
>       >       +  void operator()(int* p) const { delete p; }
>       >       +};
>       >       +
>       >       +using Alloc = std::allocator<int>;
>       >       +
>       >       +// 1. Pointer + Deleter
>       >       +static_assert( ! std::is_constructible<std::shared_ptr<int>, 
> int*, NonDeleter>::value, "");
>       >       +static_assert( ! std::is_constructible<std::shared_ptr<int>, 
> int*, NonMoveableDeleter>::value, "");
>       >       +
>       >       +// 2. Pointer + Deleter + Allocator
>       >       +static_assert( ! std::is_constructible<std::shared_ptr<int>, 
> int*, NonDeleter, Alloc>::value, "");
>       >       +static_assert( ! std::is_constructible<std::shared_ptr<int>, 
> int*, NonMoveableDeleter, Alloc>::value, "");
>       >       +
>       >       +// 3. nullptr_t + Deleter
>       >       +static_assert( ! std::is_constructible<std::shared_ptr<int>, 
> std::nullptr_t, NonDeleter>::value, "");
>       >       +static_assert( ! std::is_constructible<std::shared_ptr<int>, 
> std::nullptr_t, NonMoveableDeleter>::value, "");
>       >       +
>       >       +// 4. nullptr_t + Deleter + Allocator
>       >       +static_assert( ! std::is_constructible<std::shared_ptr<int>, 
> std::nullptr_t, NonDeleter, Alloc>::value, "");
>       >       +static_assert( ! std::is_constructible<std::shared_ptr<int>, 
> std::nullptr_t, NonMoveableDeleter, Alloc>::value, "");
>       >       --
>       >       2.55.0.669.g593c42fe07
>       >
>       >
>       >
> 
> 
> 

Reply via email to