Commit 88b1e41c by Jonathan Wakely Committed by Jonathan Wakely

Make std::function tolerate semantically non-CopyConstructible objects

To satisfy the CopyConstructible requirement a callable object stored in
a std::function must behave the same when copied from a const or
non-const source. If copying a non-const object doesn't produce an
equivalent copy then the behaviour is undefined. But we can make our
std::function more tolerant of such objects by ensuring we always copy
from a const lvalue.

Additionally use an if constexpr statement in the _M_get_pointer
function to avoid unnecessary instantiations in the discarded branch.

	* include/bits/std_function.h (_Base_manager::_M_get_pointer):
	Use constexpr if in C++17 mode.
	(_Base_manager::_M_clone(_Any_data&, const _Any_data&, true_type)):
	Copy from const object.
	* testsuite/20_util/function/cons/non_copyconstructible.cc: New.

From-SVN: r260080
parent a296d6d3
2018-05-09 Jonathan Wakely <jwakely@redhat.com>
* include/bits/std_function.h (_Base_manager::_M_get_pointer):
Use constexpr if in C++17 mode.
(_Base_manager::_M_clone(_Any_data&, const _Any_data&, true_type)):
Copy from const object.
* testsuite/20_util/function/cons/non_copyconstructible.cc: New.
2018-05-08 François Dumont <fdumont@gcc.gnu.org>
* src/c++11/debug.cc [_GLIBCXX_HAVE_EXECINFO_H]: Include execinfo.h.
......
......@@ -131,8 +131,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
class _Function_base
{
public:
static const std::size_t _M_max_size = sizeof(_Nocopy_types);
static const std::size_t _M_max_align = __alignof__(_Nocopy_types);
static const size_t _M_max_size = sizeof(_Nocopy_types);
static const size_t _M_max_align = __alignof__(_Nocopy_types);
template<typename _Functor>
class _Base_manager
......@@ -150,10 +150,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static _Functor*
_M_get_pointer(const _Any_data& __source)
{
const _Functor* __ptr =
__stored_locally? std::__addressof(__source._M_access<_Functor>())
/* have stored a pointer */ : __source._M_access<_Functor*>();
return const_cast<_Functor*>(__ptr);
if _GLIBCXX17_CONSTEXPR (__stored_locally)
{
const _Functor& __f = __source._M_access<_Functor>();
return const_cast<_Functor*>(std::__addressof(__f));
}
else // have stored a pointer
return __source._M_access<_Functor*>();
}
// Clone a location-invariant function object that fits within
......@@ -170,7 +173,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_clone(_Any_data& __dest, const _Any_data& __source, false_type)
{
__dest._M_access<_Functor*>() =
new _Functor(*__source._M_access<_Functor*>());
new _Functor(*__source._M_access<const _Functor*>());
}
// Destroying a location-invariant object may still require
......
// 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
// <http://www.gnu.org/licenses/>.
// { dg-do run { target c++11 } }
#include <functional>
// This type is not CopyConstructible because copying a non-const lvalue
// will call the throwing constructor.
struct A
{
A() = default;
A(const A&) { } // not trivial, so allocated on the heap by std::function
A(A&) { throw 1; }
void operator()() const { }
};
int main()
{
const A a{};
// Undefined, because std::function requires CopyConstructible:
std::function<void()> f(a);
// This will throw if the object is copied as non-const:
std::function<void()> g(f);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment