[cxx2a] P0641R2: (Some) type mismatches on defaulted functions only
render the function deleted instead of rendering the program ill-formed.

This change also adds an enabled-by-default warning for the case where
an explicitly-defaulted special member function of a non-template class
is implicitly deleted by the type checking rules. (This fires either due
to this language change or due to pre-C++20 reasons for the member being
implicitly deleted). I've tested this on a large codebase and found only
bugs (where the program means something that's clearly different from
what the programmer intended), so this is enabled by default, but we
should revisit this if there are problems with this being enabled by
default.

llvm-svn: 343285
diff --git a/clang/test/CXX/class.derived/class.abstract/p16.cpp b/clang/test/CXX/class.derived/class.abstract/p16.cpp
index 80396a9..fe31b73 100644
--- a/clang/test/CXX/class.derived/class.abstract/p16.cpp
+++ b/clang/test/CXX/class.derived/class.abstract/p16.cpp
@@ -44,8 +44,8 @@
 // expected-error@-3 {{deleted function 'operator=' cannot override a non-deleted function}}
 // expected-note@-4 {{while declaring the implicit move assignment operator for 'G'}}
 // expected-note@-5 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
-struct H : D {
-  H &operator=(H&&) = default;
+struct H : D { // expected-note {{deleted because base class 'D' has an inaccessible move assignment}}
+  H &operator=(H&&) = default; // expected-warning {{implicitly deleted}}
   // expected-error@-1 {{deleted function 'operator=' cannot override a non-deleted function}}
   // expected-note@-3 {{move assignment operator of 'H' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
   ~H();
diff --git a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
index 5199330..3f2bc56 100644
--- a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
@@ -1,15 +1,30 @@
 // RUN: %clang_cc1 -verify %s -std=c++11
+// RUN: %clang_cc1 -verify %s -std=c++17
+// RUN: %clang_cc1 -verify %s -std=c++2a
 
 // A function that is explicitly defaulted shall
 struct A {
   // -- be a special member function,
   A(int) = default; // expected-error {{only special member functions may be defaulted}}
+  A(A) = default; // expected-error {{must pass its first argument by reference}}
 
   // -- have the same declared function type as if it had been implicitly
   //    declared
   void operator=(const A &) = default; // expected-error {{must return 'A &'}}
-  A(...) = default; // expected-error {{cannot be variadic}}
-  A(const A &, ...) = default; // expected-error {{cannot be variadic}}
+  A(...) = default;
+  A(const A &, ...) = default;
+  A &operator=(const A&) const = default;
+  A &operator=(A) const = default; // expected-error {{must be an lvalue refe}}
+#if __cplusplus <= 201703L
+  // expected-error@-5 {{cannot be variadic}}
+  // expected-error@-5 {{cannot be variadic}}
+  // expected-error@-5 {{may not have 'const'}}
+  // expected-error@-5 {{may not have 'const'}}
+#else
+  // expected-warning@-10 {{implicitly deleted}} expected-note@-10 {{declared type does not match the type of an implicit default constructor}}
+  // expected-warning@-10 {{implicitly deleted}} expected-note@-10 {{declared type does not match the type of an implicit copy constructor}}
+  // expected-warning@-10 {{implicitly deleted}} expected-note@-10 {{declared type does not match the type of an implicit copy assignment}}
+#endif
 
   //    (except for possibly differing ref-qualifiers
   A &operator=(A &&) & = default;
@@ -23,3 +38,35 @@
   A(double = 0.0) = default; // expected-error {{cannot have default arguments}}
   A(const A & = 0) = default; // expected-error {{cannot have default arguments}}
 };
+
+struct A2 {
+  A2(...);
+  A2(const A2 &, ...);
+  A2 &operator=(const A2&) const;
+};
+A2::A2(...) = default; // expected-error {{cannot be variadic}}
+A2::A2(const A2&, ...) = default; // expected-error {{cannot be variadic}}
+A2 &A2::operator=(const A2&) const = default; // expected-error {{may not have 'const'}}
+
+struct B {
+  B(B&);
+  B &operator=(B&);
+};
+struct C : B {
+  C(const C&) = default;
+  C &operator=(const C&) = default;
+#if __cplusplus <= 201703L
+  // expected-error@-3 {{is const, but a member or base requires it to be non-const}}
+  // expected-error@-3 {{is const, but a member or base requires it to be non-const}}
+#else
+  // expected-warning@-6 {{implicitly deleted}} expected-note@-6 {{type does not match}}
+  // expected-warning@-6 {{implicitly deleted}} expected-note@-6 {{type does not match}}
+#endif
+};
+
+struct D : B { // expected-note 2{{base class}}
+  D(const D&);
+  D &operator=(const D&);
+};
+D::D(const D&) = default; // expected-error {{would delete}} expected-error {{is const, but}}
+D &D::operator=(const D&) = default; // expected-error {{would delete}} expected-error {{is const, but}}
diff --git a/clang/test/CXX/drs/dr6xx.cpp b/clang/test/CXX/drs/dr6xx.cpp
index c3c867b..0f07226 100644
--- a/clang/test/CXX/drs/dr6xx.cpp
+++ b/clang/test/CXX/drs/dr6xx.cpp
@@ -757,8 +757,8 @@
 #if __cplusplus >= 201103L
 namespace dr667 { // dr667: yes
   struct A {
-    A() = default;
-    int &r;
+    A() = default; // expected-warning {{explicitly defaulted default constructor is implicitly deleted}}
+    int &r; // expected-note {{because field 'r' of reference type 'int &' would not be initialized}}
   };
   static_assert(!__is_trivially_constructible(A), "");
 
diff --git a/clang/test/CXX/special/class.copy/p12-0x.cpp b/clang/test/CXX/special/class.copy/p12-0x.cpp
index 1b23b5a..a0ef49d 100644
--- a/clang/test/CXX/special/class.copy/p12-0x.cpp
+++ b/clang/test/CXX/special/class.copy/p12-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-defaulted-function-deleted
 
 // expected-no-diagnostics
 
diff --git a/clang/test/CXX/special/class.copy/p23-cxx11.cpp b/clang/test/CXX/special/class.copy/p23-cxx11.cpp
index ac21cc6..0b9652b 100644
--- a/clang/test/CXX/special/class.copy/p23-cxx11.cpp
+++ b/clang/test/CXX/special/class.copy/p23-cxx11.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify %s -std=c++11
+// RUN: %clang_cc1 -verify %s -std=c++11 -Wno-defaulted-function-deleted
 
 struct Trivial {};
 
diff --git a/clang/test/CXX/special/class.ctor/p5-0x.cpp b/clang/test/CXX/special/class.ctor/p5-0x.cpp
index 061a3d1..5fa6100 100644
--- a/clang/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/clang/test/CXX/special/class.ctor/p5-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-defaulted-function-deleted
 
 struct DefaultedDefCtor1 {};
 struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
diff --git a/clang/test/CXX/special/class.dtor/p5-0x.cpp b/clang/test/CXX/special/class.dtor/p5-0x.cpp
index 595784f..f69baca 100644
--- a/clang/test/CXX/special/class.dtor/p5-0x.cpp
+++ b/clang/test/CXX/special/class.dtor/p5-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: %clang_cc1 -verify -std=c++11 %s -Wno-defaulted-function-deleted
 
 struct NonTrivDtor {
   ~NonTrivDtor();
diff --git a/clang/test/SemaCUDA/implicit-member-target.cu b/clang/test/SemaCUDA/implicit-member-target.cu
index 242d345..d87e696 100644
--- a/clang/test/SemaCUDA/implicit-member-target.cu
+++ b/clang/test/SemaCUDA/implicit-member-target.cu
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s -Wno-defaulted-function-deleted
 
 #include "Inputs/cuda.h"
 
diff --git a/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp b/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
index b9af679..80efd81 100644
--- a/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
+++ b/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
@@ -59,7 +59,7 @@
 good_const gc;
 
 struct no_default {
-  no_default() = delete; // expected-note 4{{deleted here}}
+  no_default() = delete; // expected-note 5{{deleted here}}
 };
 struct no_dtor {
   ~no_dtor() = delete; // expected-note 2{{deleted here}}
@@ -108,8 +108,8 @@
 has_friend hf;
 
 struct defaulted_delete {
-  no_default nd; // expected-note {{because field 'nd' has a deleted default constructor}}
-  defaulted_delete() = default; // expected-note{{implicitly deleted here}}
+  no_default nd; // expected-note 2{{because field 'nd' has a deleted default constructor}}
+  defaulted_delete() = default; // expected-note{{implicitly deleted here}} expected-warning {{implicitly deleted}}
 };
 defaulted_delete dd; // expected-error {{call to implicitly-deleted default constructor}}
 
diff --git a/clang/test/SemaCXX/cxx17-compat.cpp b/clang/test/SemaCXX/cxx17-compat.cpp
index 9d628da..93e052f 100644
--- a/clang/test/SemaCXX/cxx17-compat.cpp
+++ b/clang/test/SemaCXX/cxx17-compat.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++17 -pedantic -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++2a -Wc++17-compat-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++2a -Wc++17-compat-pedantic -verify %s -Wno-defaulted-function-deleted
 
 struct A {};
 int (A::*pa)() const&;
@@ -42,3 +42,15 @@
 #else
     // expected-warning@-4 {{assignment of lambda is incompatible with C++ standards before C++2a}}
 #endif
+
+struct DefaultDeleteWrongTypeBase {
+  DefaultDeleteWrongTypeBase(DefaultDeleteWrongTypeBase&);
+};
+struct DefaultDeleteWrongType : DefaultDeleteWrongTypeBase {
+  DefaultDeleteWrongType(const DefaultDeleteWrongType&) = default;
+#if __cplusplus <= 201703L
+    // expected-error@-2 {{a member or base requires it to be non-const}}
+#else
+    // expected-warning@-4 {{explicitly defaulting this copy constructor with a type different from the implicit type is incompatible with C++ standards before C++2a}}
+#endif
+};
diff --git a/clang/test/SemaCXX/dr1301.cpp b/clang/test/SemaCXX/dr1301.cpp
index ec0db74..b7dc91d 100644
--- a/clang/test/SemaCXX/dr1301.cpp
+++ b/clang/test/SemaCXX/dr1301.cpp
@@ -6,7 +6,7 @@
 int a = A().n; // expected-error {{no matching constructor}}
 
 struct B {
-  B() = delete; // expected-note 3{{here}}
+  B() = delete; // expected-note 4{{here}}
   int n;
 };
 int b = B().n; // expected-error {{call to deleted}}
@@ -17,8 +17,8 @@
 int c = C().b.n; // expected-error {{call to implicitly-deleted default}}
 
 struct D {
-  D() = default; // expected-note {{here}}
-  B b; // expected-note {{'b' has a deleted default constructor}}
+  D() = default; // expected-note {{here}} expected-warning {{implicitly deleted}}
+  B b; // expected-note 2{{'b' has a deleted default constructor}}
 };
 int d = D().b.n; // expected-error {{call to implicitly-deleted default}}
 
diff --git a/clang/test/SemaCXX/microsoft-dtor-lookup-cxx11.cpp b/clang/test/SemaCXX/microsoft-dtor-lookup-cxx11.cpp
index 5a399aa..000492e 100644
--- a/clang/test/SemaCXX/microsoft-dtor-lookup-cxx11.cpp
+++ b/clang/test/SemaCXX/microsoft-dtor-lookup-cxx11.cpp
@@ -6,8 +6,8 @@
   void operator delete(void*, double);
 } s; // expected-error {{attempt to use a deleted function}}
 
-struct T { // expected-note{{virtual destructor requires an unambiguous, accessible 'operator delete'}}
-  virtual ~T() = default; // expected-note {{explicitly defaulted function was implicitly deleted here}}
+struct T { // expected-note 2{{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+  virtual ~T() = default; // expected-note {{explicitly defaulted function was implicitly deleted here}} expected-warning {{implicitly deleted}}
   void operator delete(void*, int);
   void operator delete(void*, double);
 } t; // expected-error {{attempt to use a deleted function}}
diff --git a/clang/test/SemaTemplate/exception-spec-crash.cpp b/clang/test/SemaTemplate/exception-spec-crash.cpp
index 4d93559..ebbb30a 100644
--- a/clang/test/SemaTemplate/exception-spec-crash.cpp
+++ b/clang/test/SemaTemplate/exception-spec-crash.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -DCXX_EXCEPTIONS -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -Wno-defaulted-function-deleted
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -DCXX_EXCEPTIONS -fsyntax-only -verify %s -Wno-defaulted-function-deleted
 
 template <class _Tp> struct is_nothrow_move_constructible {
   static const bool value = false;