From f061d690d8e15512540127dd43eb6f0bcf37cbb3 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 24 Oct 2019 13:54:58 +0100 Subject: [PATCH] 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. Backport from mainline 2019-08-30 Jonathan Wakely 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: r277388 --- libstdc++-v3/ChangeLog | 22 ++++++++ libstdc++-v3/include/bits/stl_algobase.h | 2 +- libstdc++-v3/include/bits/stl_uninitialized.h | 24 +++++++-- .../uninitialized_copy/1.cc | 2 +- .../uninitialized_copy/89164.cc | 38 ++++++++++++++ .../uninitialized_copy_n/89164.cc | 35 +++++++++++++ .../uninitialized_fill/89164.cc | 35 +++++++++++++ .../uninitialized_fill_n/89164.cc | 35 +++++++++++++ .../23_containers/vector/cons/89164.cc | 40 +++++++++++++++ .../23_containers/vector/cons/89164_c++17.cc | 50 +++++++++++++++++++ 10 files changed, 278 insertions(+), 5 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index fe6c649aece6..65b387329d02 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,27 @@ 2019-10-24 Jonathan Wakely + Backport from mainline + 2019-08-30 Jonathan Wakely + + 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. + Backport from mainline 2019-10-22 Jonathan Wakely diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 3b1139401ee0..6e9316a24cd9 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -301,7 +301,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // (2) If we're using random access iterators, then write the loop as // a for loop with an explicit count. - template + template struct __copy_move { template diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index 0d42b253df18..f5ca74329e2d 100644 --- a/libstdc++-v3/include/bits/stl_uninitialized.h +++ b/libstdc++-v3/include/bits/stl_uninitialized.h @@ -122,9 +122,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus < 201103L const bool __assignable = true; #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<_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; #endif @@ -186,7 +192,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus < 201103L const bool __assignable = true; #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; #endif @@ -248,7 +260,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus < 201103L const bool __assignable = true; #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; #endif return __uninitialized_fill_n<__is_trivial(_ValueType) && __assignable>:: diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc index d3b82107217b..22b9805612f2 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc @@ -34,4 +34,4 @@ test01(T* result) T t[1]; std::uninitialized_copy(t, t+1, result); // { dg-error "here" } } -// { dg-prune-output "use of deleted function" } +// { dg-error "constructible from value" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc new file mode 100644 index 000000000000..fa1ae59e6640 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc @@ -0,0 +1,38 @@ +// 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 +// . + +// { dg-do compile { target c++11 } } + +#include + +// 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 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc new file mode 100644 index 000000000000..361a7989bbf9 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc @@ -0,0 +1,35 @@ +// 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 +// . + +// { dg-do compile { target c++11 } } + +#include + +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 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc new file mode 100644 index 000000000000..8634c8044aa6 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc @@ -0,0 +1,35 @@ +// 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 +// . + +// { dg-do compile { target c++11 } } + +#include + +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 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc new file mode 100644 index 000000000000..a2d7dc7a3388 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc @@ -0,0 +1,35 @@ +// 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 +// . + +// { dg-do compile { target c++11 } } + +#include + +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 } diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc new file mode 100644 index 000000000000..e280731403b7 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc @@ -0,0 +1,40 @@ +// 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 +// . + +// { dg-do compile { target c++11 } } + +#include + +// 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 v1{x, x+1}; // { dg-error "here" } + + // Should not be able to create vector using uninitialized_fill_n: + std::vector v2{2u, X{}}; // { dg-error "here" } +} +// { dg-error "constructible from value" "" { target *-*-* } 0 } +// { dg-error "constructible from input" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc new file mode 100644 index 000000000000..db7d8d5c8501 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc @@ -0,0 +1,50 @@ +// 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 +// . + +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++17 } } + +#include + +// 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 v1{x, x+1}; // { dg-error "here" } + + // Should not be able to create vector using uninitialized_fill_n: + std::vector v2{2u, X{}}; // { dg-error "here" } +} + +void test02() +{ +#if __cplusplus >= 201703L + // Can create initializer_list with C++17 guaranteed copy elision, + // but shouldn't be able to copy from it with uninitialized_copy: + std::vector v3{X{}, X{}, X{}}; // { dg-error "here" } +#endif +} +// { dg-error "constructible from value" "" { target *-*-* } 0 } +// { dg-error "constructible from input" "" { target *-*-* } 0 } -- 2.47.2