Fix exception safety bug in vector::push_back

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@172250 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/memory b/include/memory
index 4c12ad9..f80d699 100644
--- a/include/memory
+++ b/include/memory
@@ -1571,7 +1571,10 @@
         __construct_backward(allocator_type& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __end2)
         {
             while (__end1 != __begin1)
-                construct(__a, _VSTD::__to_raw_pointer(--__end2), _VSTD::move_if_noexcept(*--__end1));
+            {
+                construct(__a, _VSTD::__to_raw_pointer(__end2-1), _VSTD::move_if_noexcept(*--__end1));
+                --__end2;
+            }
         }
 
     template <class _Tp>
diff --git a/include/vector b/include/vector
index 0c28068..876b7e5 100644
--- a/include/vector
+++ b/include/vector
@@ -1458,7 +1458,8 @@
     allocator_type& __a = this->__alloc();
     __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), __a);
     // __v.push_back(_VSTD::forward<_Up>(__x));
-    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_++), _VSTD::forward<_Up>(__x));
+    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_), _VSTD::forward<_Up>(__x));
+    __v.__end_++;
     __swap_out_circular_buffer(__v);
 }
 
@@ -1505,7 +1506,8 @@
     allocator_type& __a = this->__alloc();
     __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), __a);
 //    __v.emplace_back(_VSTD::forward<_Args>(__args)...);
-    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_++), _VSTD::forward<_Args>(__args)...);
+    __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(__v.__end_), _VSTD::forward<_Args>(__args)...);
+    __v.__end_++;
     __swap_out_circular_buffer(__v);
 }
 
diff --git a/test/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp b/test/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
new file mode 100644
index 0000000..d1aeee6
--- /dev/null
+++ b/test/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// void push_back(const value_type& x);
+
+#include <deque>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+	public: CMyClass();
+	public: CMyClass(const CMyClass& iOther);
+	public: ~CMyClass();
+
+	private: int fMagicValue;
+
+	private: static int kStartedConstructionMagicValue;
+	private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// If requested, throw an exception _before_ setting fMagicValue to kFinishedConstructionMagicValue
+	if (gCopyConstructorShouldThow) {
+		throw std::exception();
+	}
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+	// Only instances for which the constructor has finished running should be destructed
+	assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+	CMyClass instance;
+	std::deque<CMyClass> vec;
+
+	vec.push_back(instance);
+
+	gCopyConstructorShouldThow = true;
+	try {
+		vec.push_back(instance);
+	}
+	catch (...) {
+	}
+}
diff --git a/test/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp b/test/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
new file mode 100644
index 0000000..aa1d354
--- /dev/null
+++ b/test/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// void push_front(const value_type& x);
+
+#include <deque>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+	public: CMyClass();
+	public: CMyClass(const CMyClass& iOther);
+	public: ~CMyClass();
+
+	private: int fMagicValue;
+
+	private: static int kStartedConstructionMagicValue;
+	private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// If requested, throw an exception _before_ setting fMagicValue to kFinishedConstructionMagicValue
+	if (gCopyConstructorShouldThow) {
+		throw std::exception();
+	}
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+	// Only instances for which the constructor has finished running should be destructed
+	assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+	CMyClass instance;
+	std::deque<CMyClass> vec;
+
+	vec.push_front(instance);
+
+	gCopyConstructorShouldThow = true;
+	try {
+		vec.push_front(instance);
+	}
+	catch (...) {
+	}
+}
diff --git a/test/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp b/test/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp
new file mode 100644
index 0000000..1624ed6
--- /dev/null
+++ b/test/containers/sequences/forwardlist/forwardlist.modifiers/push_front_exception_safety.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <forward_list>
+
+// void push_front(const value_type& x);
+
+#include <forward_list>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+	public: CMyClass();
+	public: CMyClass(const CMyClass& iOther);
+	public: ~CMyClass();
+
+	private: int fMagicValue;
+
+	private: static int kStartedConstructionMagicValue;
+	private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// If requested, throw an exception _before_ setting fMagicValue to kFinishedConstructionMagicValue
+	if (gCopyConstructorShouldThow) {
+		throw std::exception();
+	}
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+	// Only instances for which the constructor has finished running should be destructed
+	assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+	CMyClass instance;
+	std::forward_list<CMyClass> vec;
+
+	vec.push_front(instance);
+
+	gCopyConstructorShouldThow = true;
+	try {
+		vec.push_front(instance);
+	}
+	catch (...) {
+	}
+}
diff --git a/test/containers/sequences/list/list.modifiers/push_back_exception_safety.pass.cpp b/test/containers/sequences/list/list.modifiers/push_back_exception_safety.pass.cpp
new file mode 100644
index 0000000..bdb6af3
--- /dev/null
+++ b/test/containers/sequences/list/list.modifiers/push_back_exception_safety.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <list>
+
+// void push_back(const value_type& x);
+
+#include <list>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+	public: CMyClass();
+	public: CMyClass(const CMyClass& iOther);
+	public: ~CMyClass();
+
+	private: int fMagicValue;
+
+	private: static int kStartedConstructionMagicValue;
+	private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// If requested, throw an exception _before_ setting fMagicValue to kFinishedConstructionMagicValue
+	if (gCopyConstructorShouldThow) {
+		throw std::exception();
+	}
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+	// Only instances for which the constructor has finished running should be destructed
+	assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+	CMyClass instance;
+	std::list<CMyClass> vec;
+
+	vec.push_back(instance);
+
+	gCopyConstructorShouldThow = true;
+	try {
+		vec.push_back(instance);
+	}
+	catch (...) {
+	}
+}
diff --git a/test/containers/sequences/list/list.modifiers/push_front_exception_safety.pass.cpp b/test/containers/sequences/list/list.modifiers/push_front_exception_safety.pass.cpp
new file mode 100644
index 0000000..03f8af2
--- /dev/null
+++ b/test/containers/sequences/list/list.modifiers/push_front_exception_safety.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <list>
+
+// void push_front(const value_type& x);
+
+#include <list>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+	public: CMyClass();
+	public: CMyClass(const CMyClass& iOther);
+	public: ~CMyClass();
+
+	private: int fMagicValue;
+
+	private: static int kStartedConstructionMagicValue;
+	private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// If requested, throw an exception _before_ setting fMagicValue to kFinishedConstructionMagicValue
+	if (gCopyConstructorShouldThow) {
+		throw std::exception();
+	}
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+	// Only instances for which the constructor has finished running should be destructed
+	assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+	CMyClass instance;
+	std::list<CMyClass> vec;
+
+	vec.push_front(instance);
+
+	gCopyConstructorShouldThow = true;
+	try {
+		vec.push_front(instance);
+	}
+	catch (...) {
+	}
+}
diff --git a/test/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp b/test/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp
new file mode 100644
index 0000000..17a13a8
--- /dev/null
+++ b/test/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <vector>
+
+// void push_back(const value_type& x);
+
+#include <vector>
+#include <cassert>
+
+// Flag that makes the copy constructor for CMyClass throw an exception
+static bool gCopyConstructorShouldThow = false;
+
+
+class CMyClass {
+	public: CMyClass();
+	public: CMyClass(const CMyClass& iOther);
+	public: ~CMyClass();
+
+	private: int fMagicValue;
+
+	private: static int kStartedConstructionMagicValue;
+	private: static int kFinishedConstructionMagicValue;
+};
+
+// Value for fMagicValue when the constructor has started running, but not yet finished
+int CMyClass::kStartedConstructionMagicValue = 0;
+// Value for fMagicValue when the constructor has finished running
+int CMyClass::kFinishedConstructionMagicValue = 12345;
+
+CMyClass::CMyClass() :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::CMyClass(const CMyClass& /*iOther*/) :
+	fMagicValue(kStartedConstructionMagicValue)
+{
+	// If requested, throw an exception _before_ setting fMagicValue to kFinishedConstructionMagicValue
+	if (gCopyConstructorShouldThow) {
+		throw std::exception();
+	}
+	// Signal that the constructor has finished running
+	fMagicValue = kFinishedConstructionMagicValue;
+}
+
+CMyClass::~CMyClass() {
+	// Only instances for which the constructor has finished running should be destructed
+	assert(fMagicValue == kFinishedConstructionMagicValue);
+}
+
+int main()
+{
+	CMyClass instance;
+	std::vector<CMyClass> vec;
+
+	vec.push_back(instance);
+
+	gCopyConstructorShouldThow = true;
+	try {
+		vec.push_back(instance);
+	}
+	catch (...) {
+	}
+}