From a12c16de529755cdf4dbc594dd48742107ad349e Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 18 Sep 2018 17:05:36 +0100 Subject: [PATCH] Fix location of invocable check for unique_ptr deleter The deleter only needs to be invocable when the unique_ptr destructor and reset member function are instantiated. In other contexts it might not be possible to pass unique_ptr::pointer to the deleter, if that requires a derived-to-base conversion from T* and T is incomplete. * include/bits/unique_ptr.h (__uniq_ptr_impl): Remove static assertion checking invocable condition. (unique_ptr::~unique_ptr, unique_ptr::reset): Restore static assertion here, where types must be complete. Pass pointer to deleter as an rvalue. * testsuite/20_util/unique_ptr/requirements/incomplete.cc: New test. From-SVN: r264399 --- libstdc++-v3/ChangeLog | 9 +++++ libstdc++-v3/include/bits/unique_ptr.h | 10 +++--- .../unique_ptr/requirements/incomplete.cc | 33 +++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/unique_ptr/requirements/incomplete.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 6e4fffc343f..0ed4bafbb77 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,12 @@ +2018-09-18 Jonathan Wakely + + * include/bits/unique_ptr.h (__uniq_ptr_impl): Remove static assertion + checking invocable condition. + (unique_ptr::~unique_ptr, unique_ptr::reset): Restore static assertion + here, where types must be complete. Pass pointer to deleter as an + rvalue. + * testsuite/20_util/unique_ptr/requirements/incomplete.cc: New test. + 2018-09-13 Jonathan Wakely * include/std/variant (variant) [__clang__]: Limit workaround to diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index ddc6ae0e233..0717c1e2728 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -142,8 +142,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert( !is_rvalue_reference<_Dp>::value, "unique_ptr's deleter type must be a function object type" " or an lvalue reference type" ); - static_assert( __is_invocable<_Dp&, pointer&>::value, - "unique_ptr's deleter must be invocable with a pointer" ); __uniq_ptr_impl() = default; __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; } @@ -282,9 +280,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Destructor, invokes the deleter if the stored pointer is not null. ~unique_ptr() noexcept { + static_assert(__is_invocable::value, + "unique_ptr's deleter must be invocable with a pointer"); auto& __ptr = _M_t._M_ptr(); if (__ptr != nullptr) - get_deleter()(__ptr); + get_deleter()(std::move(__ptr)); __ptr = pointer(); } @@ -389,10 +389,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void reset(pointer __p = pointer()) noexcept { + static_assert(__is_invocable::value, + "unique_ptr's deleter must be invocable with a pointer"); using std::swap; swap(_M_t._M_ptr(), __p); if (__p != pointer()) - get_deleter()(__p); + get_deleter()(std::move(__p)); } /// Exchange the pointer and deleter with another object. diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/incomplete.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/incomplete.cc new file mode 100644 index 00000000000..96e02e4c903 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/requirements/incomplete.cc @@ -0,0 +1,33 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do compile { target c++11 } } + +#include + +struct Base; // incomplete + +struct BaseDeleter { + void operator()(Base*) const; +}; + +struct Derived; // incomplete + +struct X { + std::unique_ptr p; + ~X(); // defined elsewhere, where Derived is complete +}; -- 2.30.2