This ensures we do not optimize a std::copy() of trivial types to memmove() if the unoptimized form would be ill-formed because the type isn't assignable, and similarly does not optimize std::uninitialized_xxx() on trivial types to simple assignment when the type isn't assignable. This fixes the regression with std::vector<std::atomic<int>> v(1).
2013-11-09 Jonathan Wakely <jwakely....@gmail.com> PR libstdc++/58982 * include/bits/stl_algobase.h (__copy_move::__copy_m): Use assertion to prevent using memmove() on non-assignable types. (__copy_move_backward::__copy_move_b): Likewise. * include/bits/stl_uninitialized.h (uninitialized_copy uninitialized_copy_n, uninitialized_fill, uninitialized_fill_n, __uninitialized_default, __uninitialized_default_n): Check for assignable as well as trivial. * testsuite/20_util/specialized_algorithms/uninitialized_copy/ 58982.cc: New. * testsuite/20_util/specialized_algorithms/uninitialized_copy_n/ 58982.cc: New. * testsuite/20_util/specialized_algorithms/uninitialized_fill/ 58982.cc: New. * testsuite/20_util/specialized_algorithms/uninitialized_fill_n/ 58982.cc: New. * testsuite/25_algorithms/copy/58982.cc: New. * testsuite/25_algorithms/copy_n/58982.cc: New. Tested x86_64-linux, committed to trunk.
commit 95e9f1601e94f168cf4594d3d7854c0ed8c285b8 Author: Jonathan Wakely <jwakely....@gmail.com> Date: Sat Nov 9 12:14:00 2013 +0000 PR libstdc++/58982 * include/bits/stl_algobase.h (__copy_move::__copy_m): Use assertion to prevent using memmove() on non-assignable types. (__copy_move_backward::__copy_move_b): Likewise. * include/bits/stl_uninitialized.h (uninitialized_copy uninitialized_copy_n, uninitialized_fill, uninitialized_fill_n, __uninitialized_default, __uninitialized_default_n): Check for assignable as well as trivial. * testsuite/20_util/specialized_algorithms/uninitialized_copy/ 58982.cc: New. * testsuite/20_util/specialized_algorithms/uninitialized_copy_n/ 58982.cc: New. * testsuite/20_util/specialized_algorithms/uninitialized_fill/ 58982.cc: New. * testsuite/20_util/specialized_algorithms/uninitialized_fill_n/ 58982.cc: New. * testsuite/25_algorithms/copy/58982.cc: New. * testsuite/25_algorithms/copy_n/58982.cc: New. diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index a7432da..5c7db5b 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -368,6 +368,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static _Tp* __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result) { +#if __cplusplus >= 201103L + // trivial types can have deleted assignment + static_assert( is_copy_assignable<_Tp>::value, + "type is not assignable" ); +#endif const ptrdiff_t _Num = __last - __first; if (_Num) __builtin_memmove(__result, __first, sizeof(_Tp) * _Num); @@ -563,6 +568,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static _Tp* __copy_move_b(const _Tp* __first, const _Tp* __last, _Tp* __result) { +#if __cplusplus >= 201103L + // trivial types can have deleted assignment + static_assert( is_copy_assignable<_Tp>::value, + "type is not assignable" ); +#endif const ptrdiff_t _Num = __last - __first; if (_Num) __builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num); diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index 310b162..e45046b 100644 --- a/libstdc++-v3/include/bits/stl_uninitialized.h +++ b/libstdc++-v3/include/bits/stl_uninitialized.h @@ -111,9 +111,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _ValueType1; typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType2; +#if __cplusplus < 201103L + const bool __assignable = true; +#else + // trivial types can have deleted assignment + typedef typename iterator_traits<_InputIterator>::reference _RefType; + const bool __assignable = is_assignable<_ValueType1, _RefType>::value; +#endif - return std::__uninitialized_copy<(__is_trivial(_ValueType1) - && __is_trivial(_ValueType2))>:: + return std::__uninitialized_copy<__is_trivial(_ValueType1) + && __is_trivial(_ValueType2) + && __assignable>:: __uninit_copy(__first, __last, __result); } @@ -166,8 +174,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; +#if __cplusplus < 201103L + const bool __assignable = true; +#else + // trivial types can have deleted assignment + const bool __assignable = is_copy_assignable<_ValueType>::value; +#endif - std::__uninitialized_fill<__is_trivial(_ValueType)>:: + std::__uninitialized_fill<__is_trivial(_ValueType) && __assignable>:: __uninit_fill(__first, __last, __x); } @@ -219,8 +233,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; +#if __cplusplus < 201103L + const bool __assignable = true; +#else + // trivial types can have deleted assignment + const bool __assignable = is_copy_assignable<_ValueType>::value; +#endif - std::__uninitialized_fill_n<__is_trivial(_ValueType)>:: + std::__uninitialized_fill_n<__is_trivial(_ValueType) && __assignable>:: __uninit_fill_n(__first, __n, __x); } @@ -526,8 +546,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; + // trivial types can have deleted assignment + const bool __assignable = is_copy_assignable<_ValueType>::value; - std::__uninitialized_default_1<__is_trivial(_ValueType)>:: + std::__uninitialized_default_1<__is_trivial(_ValueType) + && __assignable>:: __uninit_default(__first, __last); } @@ -539,8 +562,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; + // trivial types can have deleted assignment + const bool __assignable = is_copy_assignable<_ValueType>::value; - std::__uninitialized_default_n_1<__is_trivial(_ValueType)>:: + std::__uninitialized_default_n_1<__is_trivial(_ValueType) + && __assignable>:: __uninit_default_n(__first, __n); } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/58982.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/58982.cc new file mode 100644 index 0000000..7e059a3 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/58982.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2013 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/>. + +// 20.7.12 specialized algorithms + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <memory> + +// libstdc++/58982 + +// trivial class that is not assignable +struct T +{ + T() = default; + ~T() = default; + + T& operator=(const T&) = delete; +}; + +void +test01(T* result) +{ + T t[1]; + std::uninitialized_copy(t, t+1, result); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/58982.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/58982.cc new file mode 100644 index 0000000..e10b31a --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/58982.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2013 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/>. + +// 20.7.12 specialized algorithms + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <memory> + +// libstdc++/58982 + +// trivial class that is not assignable +struct T +{ + T() = default; + ~T() = default; + + T& operator=(const T&) = delete; +}; + +void +test01(T* result) +{ + T t[1]; + std::uninitialized_copy_n(t, 1, result); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/58982.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/58982.cc new file mode 100644 index 0000000..012e2c6 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/58982.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2013 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/>. + +// 20.7.12 specialized algorithms + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <memory> + +// libstdc++/58982 + +// trivial class that is not assignable +struct T +{ + T() = default; + ~T() = default; + + T& operator=(const T&) = delete; +}; + +void +test01(T* first, T* last) +{ + T t; + std::uninitialized_fill(first, last, t); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/58982.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/58982.cc new file mode 100644 index 0000000..606c632 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/58982.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2013 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/>. + +// 20.7.12 specialized algorithms + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <memory> + +// libstdc++/58982 + +// trivial class that is not assignable +struct T +{ + T() = default; + ~T() = default; + + T& operator=(const T&) = delete; +}; + +void +test01(T* first) +{ + T t; + std::uninitialized_fill_n(first, 1, t); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/58982.cc b/libstdc++-v3/testsuite/25_algorithms/copy/58982.cc new file mode 100644 index 0000000..58ece1b --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy/58982.cc @@ -0,0 +1,42 @@ +// Copyright (C) 2013 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/>. + +// 25.3.1 copy + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <algorithm> + +// libstdc++/58982 + +// trivial class that is not assignable +struct T +{ + T() = default; + ~T() = default; + + T& operator=(const T&) = delete; +}; + +void +test01(T* result) +{ + T t[1]; + std::copy(t, t+1, result); // { dg-error "here" } +} +// { dg-prune-output "not assignable" } diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/58982.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/58982.cc new file mode 100644 index 0000000..f7dfa59 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/58982.cc @@ -0,0 +1,42 @@ +// Copyright (C) 2013 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/>. + +// 25.3.1 copy + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <algorithm> + +// libstdc++/58982 + +// trivial class that is not assignable +struct T +{ + T() = default; + ~T() = default; + + T& operator=(const T&) = delete; +}; + +void +test01(T* result) +{ + T t[1]; + std::copy_n(t, 1, result); // { dg-error "here" } +} +// { dg-prune-output "not assignable" }