aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2018-05-09 14:28:11 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2018-05-09 14:28:11 +0100
commit88b1e41c2d9d2e9f5c0ae2d1a09da41d76184280 (patch)
treee898f8b7f1c15e8de320cf1d3b76ec85331873c8
parenta296d6d3bdd83a617e789641b828ff53f65a4ec6 (diff)
downloadgcc-88b1e41c2d9d2e9f5c0ae2d1a09da41d76184280.zip
gcc-88b1e41c2d9d2e9f5c0ae2d1a09da41d76184280.tar.gz
gcc-88b1e41c2d9d2e9f5c0ae2d1a09da41d76184280.tar.bz2
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
-rw-r--r--libstdc++-v3/ChangeLog8
-rw-r--r--libstdc++-v3/include/bits/std_function.h17
-rw-r--r--libstdc++-v3/testsuite/20_util/function/cons/non_copyconstructible.cc39
3 files changed, 57 insertions, 7 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 25430fd..5d6d6eb 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,11 @@
+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.
diff --git a/libstdc++-v3/include/bits/std_function.h b/libstdc++-v3/include/bits/std_function.h
index 9626135..ee94d1c 100644
--- a/libstdc++-v3/include/bits/std_function.h
+++ b/libstdc++-v3/include/bits/std_function.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
diff --git a/libstdc++-v3/testsuite/20_util/function/cons/non_copyconstructible.cc b/libstdc++-v3/testsuite/20_util/function/cons/non_copyconstructible.cc
new file mode 100644
index 0000000..d2a9992
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function/cons/non_copyconstructible.cc
@@ -0,0 +1,39 @@
+// 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);
+}