Index: libcxx/trunk/include/memory =================================================================== --- libcxx/trunk/include/memory +++ libcxx/trunk/include/memory @@ -1609,10 +1609,16 @@ _LIBCPP_INLINE_VISIBILITY static void - __construct_forward(allocator_type& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __begin2) + __construct_forward_with_exception_guarantees(allocator_type& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __begin2) { for (; __begin1 != __end1; ++__begin1, (void) ++__begin2) - construct(__a, _VSTD::__to_raw_pointer(__begin2), _VSTD::move_if_noexcept(*__begin1)); + construct(__a, _VSTD::__to_raw_pointer(__begin2), +#ifdef _LIBCPP_NO_EXCEPTIONS + _VSTD::move(*__begin1) +#else + _VSTD::move_if_noexcept(*__begin1) +#endif + ); } template @@ -1625,7 +1631,7 @@ is_trivially_move_constructible<_Tp>::value, void >::type - __construct_forward(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2) + __construct_forward_with_exception_guarantees(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2) { ptrdiff_t _Np = __end1 - __begin1; if (_Np > 0) @@ -1672,12 +1678,18 @@ _LIBCPP_INLINE_VISIBILITY static void - __construct_backward(allocator_type& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __end2) + __construct_backward_with_exception_guarantees(allocator_type& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __end2) { while (__end1 != __begin1) { - construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1)); - --__end2; + construct(__a, _VSTD::__to_raw_pointer(__end2 - 1), +#ifdef _LIBCPP_NO_EXCEPTIONS + _VSTD::move(*--__end1) +#else + _VSTD::move_if_noexcept(*--__end1) +#endif + ); + --__end2; } } @@ -1691,7 +1703,7 @@ is_trivially_move_constructible<_Tp>::value, void >::type - __construct_backward(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __end2) + __construct_backward_with_exception_guarantees(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __end2) { ptrdiff_t _Np = __end1 - __begin1; __end2 -= _Np; Index: libcxx/trunk/include/vector =================================================================== --- libcxx/trunk/include/vector +++ libcxx/trunk/include/vector @@ -948,7 +948,8 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) { __annotate_delete(); - __alloc_traits::__construct_backward(this->__alloc(), this->__begin_, this->__end_, __v.__begin_); + __alloc_traits::__construct_backward_with_exception_guarantees( + this->__alloc(), this->__begin_, this->__end_, __v.__begin_); _VSTD::swap(this->__begin_, __v.__begin_); _VSTD::swap(this->__end_, __v.__end_); _VSTD::swap(this->__end_cap(), __v.__end_cap()); @@ -963,8 +964,10 @@ { __annotate_delete(); pointer __r = __v.__begin_; - __alloc_traits::__construct_backward(this->__alloc(), this->__begin_, __p, __v.__begin_); - __alloc_traits::__construct_forward(this->__alloc(), __p, this->__end_, __v.__end_); + __alloc_traits::__construct_backward_with_exception_guarantees( + this->__alloc(), this->__begin_, __p, __v.__begin_); + __alloc_traits::__construct_forward_with_exception_guarantees( + this->__alloc(), __p, this->__end_, __v.__end_); _VSTD::swap(this->__begin_, __v.__begin_); _VSTD::swap(this->__end_, __v.__end_); _VSTD::swap(this->__end_cap(), __v.__end_cap()); Index: libcxx/trunk/test/libcxx/containers/sequences/vector/exception_safety_exceptions_disabled.sh.cpp =================================================================== --- libcxx/trunk/test/libcxx/containers/sequences/vector/exception_safety_exceptions_disabled.sh.cpp +++ libcxx/trunk/test/libcxx/containers/sequences/vector/exception_safety_exceptions_disabled.sh.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// RUN: %build -fno-exceptions +// RUN: %run + +// UNSUPPORTED: c++98, c++03 + +// + +// Test that vector always moves elements when exceptions are disabled. +// vector is allowed to move or copy elements while resizing, so long as +// it still provides the strong exception safety guarantee. + +#include +#include + +#include "test_macros.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +#error exceptions should be disabled. +#endif + +bool allow_moves = false; + +class A { +public: + A() {} + A(A&&) { assert(allow_moves); } + explicit A(int) {} + A(A const&) { assert(false); } +}; + +int main(int, char**) { + std::vector v; + + // Create a vector containing some number of elements that will + // have to be moved when it is resized. + v.reserve(10); + size_t old_cap = v.capacity(); + for (int i = 0; i < v.capacity(); ++i) { + v.emplace_back(42); + } + assert(v.capacity() == old_cap); + assert(v.size() == v.capacity()); + + // The next emplace back should resize. + allow_moves = true; + v.emplace_back(42); + + return 0; +}