Merge remote-tracking branch 'origin/swift-3.0-branch' into stable

* origin/swift-3.0-branch:
  [tsan] Avoid false positives with GCD data callbacks
diff --git a/lib/tsan/rtl/tsan_libdispatch_mac.cc b/lib/tsan/rtl/tsan_libdispatch_mac.cc
index cde5ed0..15805b9 100644
--- a/lib/tsan/rtl/tsan_libdispatch_mac.cc
+++ b/lib/tsan/rtl/tsan_libdispatch_mac.cc
@@ -475,6 +475,32 @@
   WRAP(dispatch_apply)(iterations, queue, new_block);
 }
 
+DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
+DECLARE_REAL_AND_INTERCEPTOR(int, munmap, void *addr, long_t sz)
+
+TSAN_INTERCEPTOR(dispatch_data_t, dispatch_data_create, const void *buffer,
+                 size_t size, dispatch_queue_t q, dispatch_block_t destructor) {
+  SCOPED_TSAN_INTERCEPTOR(dispatch_data_create, buffer, size, q, destructor);
+  if ((q == nullptr) || (destructor == DISPATCH_DATA_DESTRUCTOR_DEFAULT))
+    return REAL(dispatch_data_create)(buffer, size, q, destructor);
+
+  if (destructor == DISPATCH_DATA_DESTRUCTOR_FREE)
+    destructor = ^(void) { WRAP(free)((void *)buffer); };
+  else if (destructor == DISPATCH_DATA_DESTRUCTOR_MUNMAP)
+    destructor = ^(void) { WRAP(munmap)((void *)buffer, size); };
+
+  SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+  dispatch_block_t heap_block = Block_copy(destructor);
+  SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+  tsan_block_context_t *new_context =
+      AllocContext(thr, pc, q, heap_block, &invoke_and_release_block);
+  uptr submit_sync = (uptr)new_context;
+  Release(thr, pc, submit_sync);
+  return REAL(dispatch_data_create)(buffer, size, q, ^(void) {
+    dispatch_callback_wrap(new_context);
+  });
+}
+
 }  // namespace __tsan
 
 #endif  // SANITIZER_MAC
diff --git a/test/tsan/Darwin/gcd-data.mm b/test/tsan/Darwin/gcd-data.mm
new file mode 100644
index 0000000..a5154dc
--- /dev/null
+++ b/test/tsan/Darwin/gcd-data.mm
@@ -0,0 +1,36 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+  fprintf(stderr, "Hello world.\n");
+
+  dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL);
+  dispatch_semaphore_t sem = dispatch_semaphore_create(0);
+
+  global = 44;
+  dispatch_data_t data = dispatch_data_create("buffer", 6, q, ^{
+    fprintf(stderr, "Data destructor.\n");
+    global++;
+
+    dispatch_semaphore_signal(sem);
+  });
+  dispatch_release(data);
+  data = nil;
+
+  dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+
+  data = dispatch_data_create("buffer", 6, q, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+  dispatch_release(data);
+  data = nil;
+
+  fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: Data destructor.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.