[libcxx] func.wrap.func.con: Unset function before destroying anything

Be defensive against a reentrant std::function::operator=(nullptr_t), in case
the held function object has a non-trivial destructor.  Destroying the function
object in-place can lead to the destructor being called twice.

Patch by Duncan P. N. Exon Smith. C++03 support by Volodymyr Sapsai.

rdar://problem/32836603

Reviewers: EricWF, mclow.lists

Reviewed By: mclow.lists

Subscribers: cfe-commits, arphaman

Differential Revision: https://reviews.llvm.org/D34331

llvm-svn: 330885
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: aa208791bb950bd56f85eb200c7ac08df89b5efb
diff --git a/include/functional b/include/functional
index e45beb8..bb0bdf1 100644
--- a/include/functional
+++ b/include/functional
@@ -1818,11 +1818,7 @@
 function<_Rp(_ArgTypes...)>&
 function<_Rp(_ArgTypes...)>::operator=(function&& __f) _NOEXCEPT
 {
-    if ((void *)__f_ == &__buf_)
-        __f_->destroy();
-    else if (__f_)
-        __f_->destroy_deallocate();
-    __f_ = 0;
+    *this = nullptr;
     if (__f.__f_ == 0)
         __f_ = 0;
     else if ((void *)__f.__f_ == &__f.__buf_)
@@ -1842,11 +1838,12 @@
 function<_Rp(_ArgTypes...)>&
 function<_Rp(_ArgTypes...)>::operator=(nullptr_t) _NOEXCEPT
 {
-    if ((void *)__f_ == &__buf_)
-        __f_->destroy();
-    else if (__f_)
-        __f_->destroy_deallocate();
+    __base* __t = __f_;
     __f_ = 0;
+    if ((void *)__t == &__buf_)
+        __t->destroy();
+    else if (__t)
+        __t->destroy_deallocate();
     return *this;
 }