Index: lib/CodeGen/CGCXXABI.h
===================================================================
--- lib/CodeGen/CGCXXABI.h
+++ lib/CodeGen/CGCXXABI.h
@@ -111,6 +111,10 @@
     RAA_Indirect
   };
 
+  /// Returns true if C++ allows us to copy the memory of an object of type RD
+  /// when it is passed as an argument.
+  bool canCopyArgument(const CXXRecordDecl *RD) const;
+
   /// Returns how an argument of the given record type should be passed.
   virtual RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const = 0;
 
Index: lib/CodeGen/CGCXXABI.cpp
===================================================================
--- lib/CodeGen/CGCXXABI.cpp
+++ lib/CodeGen/CGCXXABI.cpp
@@ -28,6 +28,37 @@
     << S;
 }
 
+bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {
+  // If RD has a non-trivial move or copy constructor, we cannot copy the
+  // argument.
+  if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialMoveConstructor())
+    return false;
+
+  // If RD has a non-trivial destructor, we cannot copy the argument.
+  if (RD->hasNonTrivialDestructor())
+    return false;
+
+  // We can only copy the argument if there exists at least one trivial,
+  // non-deleted copy or move constructor.
+  // FIXME: This assumes that all lazily declared copy and move constructors are
+  // not deleted.  This assumption might not be true in some corner cases.
+  bool CopyOrMoveDeleted = false;
+  for (const CXXConstructorDecl *CD : RD->ctors()) {
+    if (CD->isCopyConstructor() || CD->isMoveConstructor()) {
+      assert(CD->isTrivial());
+      // We had at least one undeleted trivial copy or move ctor.  Return
+      // directly.
+      if (!CD->isDeleted())
+        return true;
+      CopyOrMoveDeleted = true;
+    }
+  }
+
+  // If all trivial copy and move constructors are deleted, we cannot copy the
+  // argument.
+  return !CopyOrMoveDeleted;
+}
+
 llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
   return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
 }
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -59,9 +59,8 @@
   }
 
   RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
-    // Structures with either a non-trivial destructor or a non-trivial
-    // copy constructor are always indirect.
-    if (!RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor())
+    // If C++ prohibits us from making a copy, pass by address.
+    if (!canCopyArgument(RD))
       return RAA_Indirect;
     return RAA_Default;
   }
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -407,19 +407,46 @@
     return RAA_Default;
 
   case llvm::Triple::x86:
-    // 32-bit x86 constructs non-trivial objects directly in outgoing argument
-    // slots.  LLVM uses the inalloca attribute to implement this.
-    if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialDestructor())
+    // All record arguments are passed in memory on x86.  Decide whether to
+    // construct the object directly in argument memory, or to construct the
+    // argument elsewhere and copy the bytes during the call.
+
+    // If C++ prohibits us from making a copy, construct the arguments directly
+    // into argument memory.
+    if (!canCopyArgument(RD))
       return RAA_DirectInMemory;
+
+    // Otherwise, construct the argument into a temporary and copy the bytes
+    // into the outgoing argument memory.
     return RAA_Default;
 
   case llvm::Triple::x86_64:
     // Win64 passes objects with non-trivial copy ctors indirectly.
     if (RD->hasNonTrivialCopyConstructor())
       return RAA_Indirect;
+
     // Win64 passes objects larger than 8 bytes indirectly.
     if (getContext().getTypeSize(RD->getTypeForDecl()) > 64)
       return RAA_Indirect;
+
+    // We have a trivial copy constructor or no copy constructors, but we have
+    // to make sure it isn't deleted.
+    bool CopyDeleted = false;
+    for (const CXXConstructorDecl *CD : RD->ctors()) {
+      if (CD->isCopyConstructor()) {
+        assert(CD->isTrivial());
+        // We had at least one undeleted trivial copy ctor.  Return directly.
+        if (!CD->isDeleted())
+          return RAA_Default;
+        CopyDeleted = true;
+      }
+    }
+
+    // The trivial copy constructor was deleted.  Return indirectly.
+    if (CopyDeleted)
+      return RAA_Indirect;
+
+    // There were no copy ctors.  Return in RAX.
     return RAA_Default;
   }
 
Index: test/CodeGenCXX/uncopyable-args.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/uncopyable-args.cpp
@@ -0,0 +1,200 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s | FileCheck %s -check-prefix=WIN64
+
+namespace trivial {
+// Trivial structs should be passed directly.
+struct A {
+  void *p;
+};
+void foo(A);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN7trivial3barEv()
+// CHECK: alloca %"struct.trivial::A"
+// CHECK: load i8**
+// CHECK: call void @_ZN7trivial3fooENS_1AE(i8* %{{.*}})
+// CHECK-LABEL: declare void @_ZN7trivial3fooENS_1AE(i8*)
+
+// WIN64-LABEL: declare void @"\01?foo@trivial@@YAXUA@1@@Z"(i64)
+}
+
+namespace default_ctor {
+struct A {
+  A();
+  void *p;
+};
+void foo(A);
+void bar() {
+  // Core issue 1590.  We can pass this type in registers, even though C++
+  // normally doesn't permit copies when using braced initialization.
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN12default_ctor3barEv()
+// CHECK: alloca %"struct.default_ctor::A"
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK: load i8**
+// CHECK: call void @_ZN12default_ctor3fooENS_1AE(i8* %{{.*}})
+// CHECK-LABEL: declare void @_ZN12default_ctor3fooENS_1AE(i8*)
+
+// WIN64-LABEL: declare void @"\01?foo@default_ctor@@YAXUA@1@@Z"(i64)
+}
+
+namespace move_ctor {
+// The presence of a move constructor implicitly deletes the trivial copy ctor
+// and means that we have to pass this struct by address.
+struct A {
+  A();
+  A(A &&o);
+  void *p;
+};
+void foo(A);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN9move_ctor3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT: call
+// CHECK: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})
+// CHECK-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)
+
+// WIN64-LABEL: declare void @"\01?foo@move_ctor@@YAXUA@1@@Z"(%"struct.move_ctor::A"*)
+}
+
+namespace all_deleted {
+struct A {
+  A();
+  A(const A &o) = delete;
+  A(A &&o) = delete;
+  void *p;
+};
+void foo(A);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN11all_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT call
+// CHECK: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
+// CHECK-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
+
+// WIN64-LABEL: declare void @"\01?foo@all_deleted@@YAXUA@1@@Z"(%"struct.all_deleted::A"*)
+}
+
+namespace implicitly_deleted {
+struct A {
+  A();
+  A &operator=(A &&o);
+  void *p;
+};
+void foo(A);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN18implicitly_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT call
+// CHECK: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}})
+// CHECK-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
+
+// WIN64-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(%"struct.implicitly_deleted::A"*)
+}
+
+namespace one_deleted {
+struct A {
+  A();
+  A(A &&o) = delete;
+  void *p;
+};
+void foo(A);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN11one_deleted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK-NOT call
+// CHECK: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
+// CHECK-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
+
+// WIN64-LABEL: declare void @"\01?foo@one_deleted@@YAXUA@1@@Z"(%"struct.one_deleted::A"*)
+}
+
+namespace copy_defaulted {
+struct A {
+  A();
+  A(const A &o) = default;
+  A(A &&o) = delete;
+  void *p;
+};
+void foo(A);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN14copy_defaulted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK: load i8**
+// CHECK: call void @_ZN14copy_defaulted3fooENS_1AE(i8* %{{.*}})
+// CHECK-LABEL: declare void @_ZN14copy_defaulted3fooENS_1AE(i8*)
+
+// WIN64-LABEL: declare void @"\01?foo@copy_defaulted@@YAXUA@1@@Z"(i64)
+}
+
+namespace move_defaulted {
+struct A {
+  A();
+  A(const A &o) = delete;
+  A(A &&o) = default;
+  void *p;
+};
+void foo(A);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN14move_defaulted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK: load i8**
+// CHECK: call void @_ZN14move_defaulted3fooENS_1AE(i8* %{{.*}})
+// CHECK-LABEL: declare void @_ZN14move_defaulted3fooENS_1AE(i8*)
+
+// WIN64-LABEL: declare void @"\01?foo@move_defaulted@@YAXUA@1@@Z"(%"struct.move_defaulted::A"*)
+}
+
+namespace trivial_defaulted {
+struct A {
+  A();
+  A(const A &o) = default;
+  void *p;
+};
+void foo(A);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN17trivial_defaulted3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK: load i8**
+// CHECK: call void @_ZN17trivial_defaulted3fooENS_1AE(i8* %{{.*}})
+// CHECK-LABEL: declare void @_ZN17trivial_defaulted3fooENS_1AE(i8*)
+
+// WIN64-LABEL: declare void @"\01?foo@trivial_defaulted@@YAXUA@1@@Z"(i64)
+}
+
+namespace two_copy_ctors {
+struct A {
+  A();
+  A(const A &) = default;
+  A(const A &, int = 0);
+  void *p;
+};
+struct B : A {};
+
+void foo(B);
+void bar() {
+  foo({});
+}
+// CHECK-LABEL: define void @_ZN14two_copy_ctors3barEv()
+// CHECK: call void @_Z{{.*}}C1Ev(
+// CHECK: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
+// CHECK-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
+
+// WIN64-LABEL: declare void @"\01?foo@two_copy_ctors@@YAXUB@1@@Z"(%"struct.two_copy_ctors::B"*)
+}