[c++2a] Allow comparison functions to be explicitly defaulted.

This adds some initial syntactic checking that only the appropriate
function signatures can be defaulted. No implicit definitions are
generated yet.
diff --git a/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
new file mode 100644
index 0000000..1f8d6a2
--- /dev/null
+++ b/clang/test/CXX/class/class.compare/class.compare.default/p1.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+struct B {};
+bool operator==(const B&, const B&) = default; // expected-error {{equality comparison operator can only be defaulted in a class definition}}
+bool operator<=>(const B&, const B&) = default; // expected-error {{three-way comparison operator can only be defaulted in a class definition}}
+
+template<typename T = void>
+  bool operator<(const B&, const B&) = default; // expected-error {{comparison operator template cannot be defaulted}}
+
+struct A {
+  friend bool operator==(const A&, const A&) = default;
+  friend bool operator!=(const A&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison}}
+  friend bool operator!=(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted equality comparison}}
+  friend bool operator<(const A&, const A&);
+  friend bool operator<(const B&, const B&) = default; // expected-error {{invalid parameter type for defaulted relational comparison}}
+  friend bool operator>(A, A) = default; // expected-error {{invalid parameter type for defaulted relational comparison}}
+
+  bool operator<(const A&) const;
+  bool operator<=(const A&) const = default;
+  bool operator==(const A&) const volatile && = default; // surprisingly, OK
+  bool operator<=>(const A&) = default; // expected-error {{defaulted member three-way comparison operator must be const-qualified}}
+  bool operator>=(const B&) const = default; // expected-error {{invalid parameter type for defaulted relational comparison}}
+  static bool operator>(const B&) = default; // expected-error {{overloaded 'operator>' cannot be a static member function}}
+
+  template<typename T = void>
+    friend bool operator==(const A&, const A&) = default; // expected-error {{comparison operator template cannot be defaulted}}
+  template<typename T = void>
+    bool operator==(const A&) const = default; // expected-error {{comparison operator template cannot be defaulted}}
+};
+
+// FIXME: The wording is not clear as to whether these are valid, but the
+// intention is that they are not.
+bool operator<(const A&, const A&) = default; // expected-error {{relational comparison operator can only be defaulted in a class definition}}
+bool A::operator<(const A&) const = default; // expected-error {{can only be defaulted in a class definition}}
+
+template<typename T> struct Dependent {
+  using U = typename T::type;
+  bool operator==(U) const = default; // expected-error {{found 'Dependent<Bad>::U'}}
+  friend bool operator==(U, U) = default; // expected-error {{found 'Dependent<Bad>::U'}}
+};
+
+struct Good { using type = const Dependent<Good>&; };
+template struct Dependent<Good>;
+
+struct Bad { using type = Dependent<Bad>&; };
+template struct Dependent<Bad>; // expected-note {{in instantiation of}}
diff --git a/clang/test/CXX/class/class.compare/class.eq/p1.cpp b/clang/test/CXX/class/class.compare/class.eq/p1.cpp
new file mode 100644
index 0000000..622f66c
--- /dev/null
+++ b/clang/test/CXX/class/class.compare/class.eq/p1.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+struct Good {
+  bool operator==(const Good&) const = default;
+  bool operator!=(const Good&) const = default;
+  friend bool operator==(const Good&, const Good&) = default;
+  friend bool operator!=(const Good&, const Good&) = default;
+};
+
+enum Bool : bool {};
+struct Bad {
+  bool &operator==(const Bad&) const = default; // expected-error {{return type for defaulted equality comparison operator must be 'bool', not 'bool &'}}
+  const bool operator!=(const Bad&) const = default; // expected-error {{return type for defaulted equality comparison operator must be 'bool', not 'const bool'}}
+  friend Bool operator==(const Bad&, const Bad&) = default; // expected-error {{return type for defaulted equality comparison operator must be 'bool', not 'Bool'}}
+  friend int operator!=(const Bad&, const Bad&) = default; // expected-error {{return type for defaulted equality comparison operator must be 'bool', not 'int'}}
+};
+
+template<typename T> struct Ugly {
+  T operator==(const Ugly&) const = default; // expected-error {{return type}}
+  T operator!=(const Ugly&) const = default; // expected-error {{return type}}
+  friend T operator==(const Ugly&, const Ugly&) = default; // expected-error {{return type}}
+  friend T operator!=(const Ugly&, const Ugly&) = default; // expected-error {{return type}}
+};
+template struct Ugly<bool>;
+template struct Ugly<int>; // expected-note {{in instantiation of}}
diff --git a/clang/test/CXX/class/class.compare/class.rel/p1.cpp b/clang/test/CXX/class/class.compare/class.rel/p1.cpp
new file mode 100644
index 0000000..3797d5f
--- /dev/null
+++ b/clang/test/CXX/class/class.compare/class.rel/p1.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+struct Good {
+  bool operator<(const Good&) const = default;
+  bool operator>(const Good&) const = default;
+  friend bool operator<=(const Good&, const Good&) = default;
+  friend bool operator>=(const Good&, const Good&) = default;
+};
+
+enum Bool : bool {};
+struct Bad {
+  bool &operator<(const Bad&) const = default; // expected-error {{return type for defaulted relational comparison operator must be 'bool', not 'bool &'}}
+  const bool operator>(const Bad&) const = default; // expected-error {{return type for defaulted relational comparison operator must be 'bool', not 'const bool'}}
+  friend Bool operator<=(const Bad&, const Bad&) = default; // expected-error {{return type for defaulted relational comparison operator must be 'bool', not 'Bool'}}
+  friend int operator>=(const Bad&, const Bad&) = default; // expected-error {{return type for defaulted relational comparison operator must be 'bool', not 'int'}}
+};
+
+template<typename T> struct Ugly {
+  T operator<(const Ugly&) const = default; // expected-error {{return type}}
+  T operator>(const Ugly&) const = default; // expected-error {{return type}}
+  friend T operator<=(const Ugly&, const Ugly&) = default; // expected-error {{return type}}
+  friend T operator>=(const Ugly&, const Ugly&) = default; // expected-error {{return type}}
+};
+template struct Ugly<bool>;
+template struct Ugly<int>; // expected-note {{in instantiation of}}
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 3f2bc56..6e9b459 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,12 +1,28 @@
-// RUN: %clang_cc1 -verify %s -std=c++11
-// RUN: %clang_cc1 -verify %s -std=c++17
-// RUN: %clang_cc1 -verify %s -std=c++2a
+// RUN: %clang_cc1 -verify=expected,pre2a %s -std=c++11
+// RUN: %clang_cc1 -verify=expected,pre2a %s -std=c++17
+// RUN: %clang_cc1 -verify=expected %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}}
+  // -- be a special member function [C++2a: or a comparison operator function],
+  A(int) = default;
+#if __cplusplus <= 201703L
+  // expected-error@-2 {{only special member functions may be defaulted}}
+#else
+  // expected-error@-4 {{only special member functions and comparison operators may be defaulted}}
+#endif
   A(A) = default; // expected-error {{must pass its first argument by reference}}
+  void f(A) = default; // expected-error-re {{only special member functions{{( and comparison operators)?}} may be defaulted}}
+
+  bool operator==(const A&) const = default; // pre2a-warning {{defaulted comparison operators are a C++20 extension}}
+  bool operator!=(const A&) const = default; // pre2a-warning {{defaulted comparison operators are a C++20 extension}}
+  bool operator<(const A&) const = default; // pre2a-error {{only special member functions may be defaulted}}
+  bool operator>(const A&) const = default; // pre2a-error {{only special member functions may be defaulted}}
+  bool operator<=(const A&) const = default; // pre2a-error {{only special member functions may be defaulted}}
+  bool operator>=(const A&) const = default; // pre2a-error {{only special member functions may be defaulted}}
+  bool operator<=>(const A&) const = default; // pre2a-error 1+{{}} pre2a-warning {{'<=>' is a single token in C++2a}}
+
+  A operator+(const A&) const = default; // expected-error-re {{only special member functions{{( and comparison operators)?}} may be defaulted}}
 
   // -- have the same declared function type as if it had been implicitly
   //    declared
diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp
index 2f219ac..3c1c360 100644
--- a/clang/test/Parser/cxx0x-decl.cpp
+++ b/clang/test/Parser/cxx0x-decl.cpp
@@ -39,7 +39,7 @@
 
 // PR9903
 struct SS {
-  typedef void d() = default; // expected-error {{function definition declared 'typedef'}} expected-error {{only special member functions may be defaulted}}
+  typedef void d() = default; // expected-error {{function definition declared 'typedef'}} expected-error {{only special member functions and comparison operators may be defaulted}}
 };
 
 using PR14855 = int S::; // expected-error {{expected ';' after alias declaration}}
diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
index 45a6544..c68b7d6 100644
--- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -175,7 +175,7 @@
   Outer<T>::Inner1<T>::~Inner1() = delete; // expected-error {{nested name specifier 'Outer<T>::Inner1<T>::' for declaration does not refer into a class, class template or class template partial specialization}}  expected-error {{only functions can have deleted definitions}}
 
   template<typename T>
-  Outer<T>::Inner2<T>::~Inner2() = default; // expected-error {{nested name specifier 'Outer<T>::Inner2<T>::' for declaration does not refer into a class, class template or class template partial specialization}}  expected-error {{only special member functions may be defaulted}}
+  Outer<T>::Inner2<T>::~Inner2() = default; // expected-error {{nested name specifier 'Outer<T>::Inner2<T>::' for declaration does not refer into a class, class template or class template partial specialization}}
 }
 
 extern "C" { // expected-note {{extern "C" language linkage specification begins here}}
diff --git a/clang/test/SemaCXX/cxx17-compat.cpp b/clang/test/SemaCXX/cxx17-compat.cpp
index 3d5420f..e063b1f 100644
--- a/clang/test/SemaCXX/cxx17-compat.cpp
+++ b/clang/test/SemaCXX/cxx17-compat.cpp
@@ -88,3 +88,36 @@
     // expected-warning@-4 {{decomposition declaration declared with 'static thread_local' specifiers is incompatible with C++ standards before C++2a}}
 #endif
 }
+
+struct DefaultedComparisons {
+  bool operator==(const DefaultedComparisons&) const = default;
+  bool operator!=(const DefaultedComparisons&) const = default;
+#if __cplusplus <= 201703L
+  // expected-warning@-3 {{defaulted comparison operators are a C++20 extension}}
+  // expected-warning@-3 {{defaulted comparison operators are a C++20 extension}}
+#else
+  // expected-warning@-6 {{defaulted comparison operators are incompatible with C++ standards before C++20}}
+  // expected-warning@-6 {{defaulted comparison operators are incompatible with C++ standards before C++20}}
+#endif
+  bool operator<=>(const DefaultedComparisons&) const = default;
+#if __cplusplus <= 201703L
+  // expected-error@-2 {{'operator<=' cannot be the name of a variable or data member}} expected-error@-2 0+{{}} expected-warning@-2 {{}}
+#else
+  // expected-warning@-4 {{'<=>' operator is incompatible with C++ standards before C++2a}}
+#endif
+  bool operator<(const DefaultedComparisons&) const = default;
+  bool operator<=(const DefaultedComparisons&) const = default;
+  bool operator>(const DefaultedComparisons&) const = default;
+  bool operator>=(const DefaultedComparisons&) const = default;
+#if __cplusplus <= 201703L
+  // expected-error@-5 {{only special member functions}}
+  // expected-error@-5 {{only special member functions}}
+  // expected-error@-5 {{only special member functions}}
+  // expected-error@-5 {{only special member functions}}
+#else
+  // expected-warning@-10 {{defaulted comparison operators are incompatible with C++ standards before C++20}}
+  // expected-warning@-10 {{defaulted comparison operators are incompatible with C++ standards before C++20}}
+  // expected-warning@-10 {{defaulted comparison operators are incompatible with C++ standards before C++20}}
+  // expected-warning@-10 {{defaulted comparison operators are incompatible with C++ standards before C++20}}
+#endif
+};