Commit 61f5cb23 by Jonathan Wakely Committed by Jonathan Wakely

PR libstdc++/89164 enforce constraints for uninitialized algos

The memmove optimizations for std::uninitialized_copy/fill/_n will
compile even if the type is not copy constructible, because std::copy
doesn't require copy construction to work. But the uninitialized
algorithms do require it.

This adds explicit static assertions to ensure we don't allow ill-formed
initializations.

	PR libstdc++/89164
	* include/bits/stl_algobase.h (__copy_move): Give descriptive names
	to template parameters.
	* include/bits/stl_uninitialized.h (uninitialized_copy)
	(uninitialized_fill, uninitialized_fill_n): Add static assertions to
	diagnose invalid uses.
	* testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc:
	Adjust expected error.
	* testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc:
	New test.
	* testsuite/20_util/specialized_algorithms/uninitialized_copy_n/
	89164.cc: New test.
	* testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc:
	New test.
	* testsuite/20_util/specialized_algorithms/uninitialized_fill_n/
	89164.cc: New test.
	* testsuite/23_containers/vector/cons/89164.cc: New test.
	* testsuite/23_containers/vector/cons/89164_c++17.cc: New test.

From-SVN: r275177
parent 815b5368
2019-08-30 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/89164
* include/bits/stl_algobase.h (__copy_move): Give descriptive names
to template parameters.
* include/bits/stl_uninitialized.h (uninitialized_copy)
(uninitialized_fill, uninitialized_fill_n): Add static assertions to
diagnose invalid uses.
* testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc:
Adjust expected error.
* testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc:
New test.
* testsuite/20_util/specialized_algorithms/uninitialized_copy_n/
89164.cc: New test.
* testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc:
New test.
* testsuite/20_util/specialized_algorithms/uninitialized_fill_n/
89164.cc: New test.
* testsuite/23_containers/vector/cons/89164.cc: New test.
* testsuite/23_containers/vector/cons/89164_c++17.cc: New test.
2019-08-29 Jonathan Wakely <jwakely@redhat.com> 2019-08-29 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/91067 PR libstdc++/91067
......
...@@ -359,7 +359,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -359,7 +359,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// (2) If we're using random access iterators, then write the loop as // (2) If we're using random access iterators, then write the loop as
// a for loop with an explicit count. // a for loop with an explicit count.
template<bool, bool, typename> template<bool _IsMove, bool _IsSimple, typename _Category>
struct __copy_move struct __copy_move
{ {
template<typename _II, typename _OI> template<typename _II, typename _OI>
......
...@@ -130,9 +130,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -130,9 +130,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus < 201103L #if __cplusplus < 201103L
const bool __assignable = true; const bool __assignable = true;
#else #else
// trivial types can have deleted assignment // Trivial types can have deleted copy constructor, but the std::copy
// optimization that uses memmove would happily "copy" them anyway.
static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
"result type must be constructible from value type of input range");
typedef typename iterator_traits<_InputIterator>::reference _RefType1; typedef typename iterator_traits<_InputIterator>::reference _RefType1;
typedef typename iterator_traits<_ForwardIterator>::reference _RefType2; typedef typename iterator_traits<_ForwardIterator>::reference _RefType2;
// Trivial types can have deleted assignment, so using std::copy
// would be ill-formed. Require assignability before using std::copy:
const bool __assignable = is_assignable<_RefType2, _RefType1>::value; const bool __assignable = is_assignable<_RefType2, _RefType1>::value;
#endif #endif
...@@ -197,7 +203,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -197,7 +203,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus < 201103L #if __cplusplus < 201103L
const bool __assignable = true; const bool __assignable = true;
#else #else
// trivial types can have deleted assignment // Trivial types can have deleted copy constructor, but the std::fill
// optimization that uses memmove would happily "copy" them anyway.
static_assert(is_constructible<_ValueType, const _Tp&>::value,
"result type must be constructible from input type");
// Trivial types can have deleted assignment, so using std::fill
// would be ill-formed. Require assignability before using std::fill:
const bool __assignable = is_copy_assignable<_ValueType>::value; const bool __assignable = is_copy_assignable<_ValueType>::value;
#endif #endif
...@@ -262,7 +274,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -262,7 +274,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus < 201103L #if __cplusplus < 201103L
const bool __assignable = true; const bool __assignable = true;
#else #else
// trivial types can have deleted assignment // Trivial types can have deleted copy constructor, but the std::fill
// optimization that uses memmove would happily "copy" them anyway.
static_assert(is_constructible<_ValueType, const _Tp&>::value,
"result type must be constructible from input type");
// Trivial types can have deleted assignment, so using std::fill
// would be ill-formed. Require assignability before using std::fill:
const bool __assignable = is_copy_assignable<_ValueType>::value; const bool __assignable = is_copy_assignable<_ValueType>::value;
#endif #endif
return __uninitialized_fill_n<__is_trivial(_ValueType) && __assignable>:: return __uninitialized_fill_n<__is_trivial(_ValueType) && __assignable>::
......
...@@ -34,4 +34,4 @@ test01(T* result) ...@@ -34,4 +34,4 @@ test01(T* result)
T t[1]; T t[1];
std::uninitialized_copy(t, t+1, result); // { dg-error "here" } std::uninitialized_copy(t, t+1, result); // { dg-error "here" }
} }
// { dg-prune-output "use of deleted function" } // { dg-error "constructible from value" "" { target *-*-* } 0 }
// Copyright (C) 2019 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 compile { target c++11 } }
#include <vector>
// PR libstdc++/89164
struct X
{
X() = default;
X(const X&) = delete;
};
void test01()
{
X x[1];
alignas(X) unsigned char buf[sizeof(X)];
X* p = (X*)buf;
std::uninitialized_copy(x, x+1, p); // { dg-error "here" }
}
// { dg-error "must be constructible" "" { target *-*-* } 0 }
// Copyright (C) 2019 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 compile { target c++11 } }
#include <vector>
struct X {
X() = default;
X(const X&) = delete;
};
void test01()
{
X x[1];
alignas(X) unsigned char buf[sizeof(X)];
X* p = (X*)buf;
std::uninitialized_copy_n(x, 1, p); // { dg-error "here" }
}
// { dg-error "must be constructible" "" { target *-*-* } 0 }
// Copyright (C) 2019 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 compile { target c++11 } }
#include <vector>
struct X {
X() = default;
X(const X&) = delete;
};
void f()
{
X x;
alignas(X) unsigned char buf[sizeof(X)];
X* p = (X*)buf;
std::uninitialized_fill(p, p+1, x); // { dg-error "here" }
}
// { dg-error "must be constructible" "" { target *-*-* } 0 }
// Copyright (C) 2019 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 compile { target c++11 } }
#include <vector>
struct X {
X() = default;
X(const X&) = delete;
};
void test01()
{
X x;
alignas(X) unsigned char buf[sizeof(X)];
X* p = (X*)buf;
std::uninitialized_fill_n(p, 1, x); // { dg-error "here" }
}
// { dg-error "must be constructible" "" { target *-*-* } 0 }
// Copyright (C) 2019 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 compile { target c++11 } }
#include <vector>
// PR libstdc++/89164
struct X
{
X() = default;
X(const X&) = delete;
};
void test01()
{
X x[1];
// Should not be able to create vector using uninitialized_copy:
std::vector<X> v1{x, x+1}; // { dg-error "here" }
// Should not be able to create vector using uninitialized_fill_n:
std::vector<X> v2{2u, X{}}; // { dg-error "here" }
}
// { dg-error "constructible from value" "" { target *-*-* } 0 }
// { dg-error "constructible from input" "" { target *-*-* } 0 }
// Copyright (C) 2019 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-options "-std=gnu++17" }
// { dg-do compile { target c++17 } }
#include <vector>
// PR libstdc++/89164
void test01()
{
X x[1];
// Should not be able to create vector using uninitialized_copy:
std::vector<X> v1{x, x+1}; // { dg-error "here" }
// Should not be able to create vector using uninitialized_fill_n:
std::vector<X> v2{2u, X{}}; // { dg-error "here" }
}
void test02()
{
#if __cplusplus >= 201703L
// Can create initializer_list<X> with C++17 guaranteed copy elision,
// but shouldn't be able to copy from it with uninitialized_copy:
std::vector<X> v3{X{}, X{}, X{}}; // { dg-error "here" }
#endif
}
// { dg-error "constructible from value" "" { target *-*-* } 0 }
// { dg-error "constructible from input" "" { target *-*-* } 0 }
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