EricWF updated this revision to Diff 145643.
EricWF added a comment.

- Rebase on master.

I think the correct direction to head with this patch is to start removing the 
bits of the implementation which evaluate and build rewritten expressions 
during overload resolution. I'll submit such an update tomorrow.


https://reviews.llvm.org/D45680

Files:
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Sema/Overload.h
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/Expr.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/cxx2a-compare.cpp
  test/SemaCXX/compare-cxx2a.cpp

Index: test/SemaCXX/compare-cxx2a.cpp
===================================================================
--- test/SemaCXX/compare-cxx2a.cpp
+++ test/SemaCXX/compare-cxx2a.cpp
@@ -292,20 +292,21 @@
 
 template <int>
 struct Tag {};
-// expected-note@+1 {{candidate}}
-Tag<0> operator<=>(EnumA, EnumA) {
-  return {};
+std::strong_ordering operator<=>(EnumA, EnumA) {
+  return std::strong_ordering::equal;
 }
-Tag<1> operator<=>(EnumA, EnumB) {
-  return {};
+// expected-note@+1 {{candidate function}},
+std::strong_ordering operator<=>(EnumA a, EnumB b) {
+  return ((int)a <=> (int)b);
 }
 
 void test_enum_ovl_provided() {
   auto r1 = (EnumA::A <=> EnumA::A);
-  ASSERT_EXPR_TYPE(r1, Tag<0>);
+  ASSERT_EXPR_TYPE(r1, std::strong_ordering);
   auto r2 = (EnumA::A <=> EnumB::B);
-  ASSERT_EXPR_TYPE(r2, Tag<1>);
-  (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}}
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+  (void)(EnumB::B <=> EnumA::A); // OK, chooses reverse order synthesized candidate.
+  (void)(EnumB::B <=> EnumC::C); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumC')}}
 }
 
 void enum_float_test() {
@@ -421,3 +422,116 @@
 }
 
 } // namespace ComplexTest
+
+namespace TestRewritting {
+
+struct T {
+  int x;
+  // expected-note@+1 {{candidate}}
+  constexpr std::strong_ordering operator<=>(T y) const {
+    return (x <=> y.x);
+  }
+};
+
+struct U {
+  int x;
+  // FIXME: This diagnostic is wrong-ish.
+  // expected-note@+1 {{candidate function not viable: requires single argument 'y', but 2 arguments were provided}}
+  constexpr std::strong_equality operator<=>(T y) const {
+    if (x == y.x)
+      return std::strong_equality::equal;
+    return std::strong_equality::nonequal;
+  }
+};
+
+struct X { int x; };
+struct Y { int x; };
+template <int>
+struct Tag {};
+// expected-note@+1 2 {{candidate}}
+Tag<0> operator<=>(X, Y) {
+  return {};
+}
+// expected-note@+1 2 {{candidate}}
+constexpr auto operator<=>(Y y, X x) {
+  return y.x <=> x.x;
+}
+
+void foo() {
+  T t{42};
+  T t2{0};
+  U u{101};
+  auto r1 = (t <=> u);
+  ASSERT_EXPR_TYPE(r1, std::strong_equality);
+  auto r2 = (t <=> t2);
+  ASSERT_EXPR_TYPE(r2, std::strong_ordering);
+
+  auto r3 = t == u;
+  ASSERT_EXPR_TYPE(r3, bool);
+
+  (void)(t < u); // expected-error {{invalid operands to binary expression ('TestRewritting::T' and 'TestRewritting::U')}}
+
+  constexpr X x{1};
+  constexpr Y y{2};
+  constexpr auto r4 = (y < x);
+  static_assert(r4 == false);
+  constexpr auto r5 = (x < y);
+  static_assert(r5 == true);
+}
+
+} // namespace TestRewritting
+
+// The implicit object parameter is not considered when performing partial
+// ordering. That makes the reverse synthesized candidates ambiguous with the
+// rewritten candidates if any of them resolve to a member function.
+namespace TestOvlMatchingIgnoresImplicitObject {
+struct U;
+// expected-note@+2 {{candidate}}
+struct T {
+  std::strong_ordering operator<=>(U const &RHS) const;
+};
+// expected-note@+2 {{candidate}}
+struct U {
+  std::strong_ordering operator<=>(T const &RHS) const;
+};
+
+struct V {
+  int x;
+};
+auto operator<=>(V const &LHS, V &&RHS) { // expected-note 4 {{candidate}}
+  return LHS.x <=> RHS.x;
+}
+auto operator<(V const &, V &&) { // expected-note {{candidate}}
+  return std::strong_equality::equal;
+}
+
+void test() {
+  // expected-error@+1 {{use of overloaded operator '<' is ambiguous}}
+  (void)(T{} < U{});
+  // expected-error@+1 {{use of overloaded operator '<' is ambiguous}}
+  (void)(V{} < V{});
+  // expected-error@+1 {{use of overloaded operator '<=>' is ambiguous}}
+  (void)(V{} <=> V{});
+}
+
+} // namespace TestOvlMatchingIgnoresImplicitObject
+
+namespace TestRewrittenTemplate {
+
+template <class T>
+auto test(T const &LHS, T const &RHS) {
+  // expected-error@+1 {{invalid operands to binary expression ('const TestRewrittenTemplate::None'}}
+  return LHS < RHS;
+}
+struct None {};
+template auto test<None>(None const &, None const &); // expected-note {{requested here}}
+
+struct Relational {};
+bool operator<(Relational, Relational);
+template auto test<Relational>(Relational const &, Relational const &);
+
+struct ThreeWay {};
+std::strong_ordering operator<=>(ThreeWay, ThreeWay);
+template auto test<ThreeWay>(ThreeWay const &, ThreeWay const &);
+
+} // namespace TestRewrittenTemplate
Index: test/CodeGenCXX/cxx2a-compare.cpp
===================================================================
--- test/CodeGenCXX/cxx2a-compare.cpp
+++ test/CodeGenCXX/cxx2a-compare.cpp
@@ -186,3 +186,17 @@
 }
 
 } // namespace ComplexTest
+
+namespace RewrittenTest {
+struct U {
+  int x;
+  std::strong_ordering operator<=>(U const &) const;
+};
+// FIXME(EricWF): Write this test
+auto test(U t1, U t2) {
+  return (t1 < t2);
+}
+
+} // namespace RewrittenTest
+
+
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1289,6 +1289,7 @@
     case Stmt::PackExpansionExprClass:
     case Stmt::SubstNonTypeTemplateParmPackExprClass:
     case Stmt::FunctionParmPackExprClass:
+    case Stmt::CXXRewrittenExprClass:
     case Stmt::CoroutineBodyStmtClass:
     case Stmt::CoawaitExprClass:
     case Stmt::DependentCoawaitExprClass:
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -1695,6 +1695,21 @@
   Code = serialization::EXPR_CXX_FOLD;
 }
 
+void ASTStmtWriter::VisitCXXRewrittenExpr(CXXRewrittenExpr *E) {
+  VisitExpr(E);
+  Record.push_back(E->getRewrittenKind());
+  Record.AddStmt(E->SubExprs[0]);
+  Record.AddStmt(E->SubExprs[1]);
+  switch (E->getRewrittenKind()) {
+  case CXXRewrittenExpr::Comparison: {
+    CXXRewrittenExpr::ComparisonBits Bits = E->ExtraBits.CompareBits;
+    Record.push_back(Bits.IsSynthesized);
+    break;
+  }
+  }
+  Code = serialization::EXPR_CXX_REWRITTEN_OPERATOR;
+}
+
 void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   Record.AddStmt(E->getSourceExpr());
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -1705,6 +1705,21 @@
   E->Opcode = (BinaryOperatorKind)Record.readInt();
 }
 
+void ASTStmtReader::VisitCXXRewrittenExpr(CXXRewrittenExpr *E) {
+  VisitExpr(E);
+  E->setRewrittenKind(
+      static_cast<CXXRewrittenExpr::RewrittenKind>(Record.readInt()));
+  E->SubExprs[0] = Record.readSubExpr();
+  E->SubExprs[1] = Record.readSubExpr();
+  switch (E->getRewrittenKind()) {
+  case CXXRewrittenExpr::Comparison: {
+    CXXRewrittenExpr::ComparisonBits &Bits = E->ExtraBits.CompareBits;
+    Bits.IsSynthesized = Record.readInt();
+    break;
+  }
+  }
+}
+
 void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   E->SourceExpr = Record.readSubExpr();
@@ -4074,6 +4089,9 @@
       S = new (Context) CXXFoldExpr(Empty);
       break;
 
+    case EXPR_CXX_REWRITTEN_OPERATOR:
+      S = new (Context) CXXRewrittenExpr(Empty);
+
     case EXPR_OPAQUE_VALUE:
       S = new (Context) OpaqueValueExpr(Empty);
       break;
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -3217,6 +3217,14 @@
     return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator);
   }
 
+  ExprResult
+  RebuildCXXRewrittenExpr(CXXRewrittenExpr::RewrittenKind Kind, Expr *Original,
+                          Expr *Rewritten,
+                          CXXRewrittenExpr::ExtraRewrittenBits ExtraBits) {
+    return new (SemaRef.Context)
+        CXXRewrittenExpr(Kind, Original, Rewritten, ExtraBits);
+  }
+
   /// \brief Build a new atomic operation expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -11515,6 +11523,68 @@
   return getDerived().TransformExpr(E->GetTemporaryExpr());
 }
 
+static Expr *extractOperand(Expr *E, unsigned Idx) {
+  assert(Idx < 2);
+  if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+    if (Idx == 0)
+      return BO->getLHS();
+    return BO->getRHS();
+  }
+  if (auto *CE = dyn_cast<CallExpr>(E)) {
+    assert(CE->getNumArgs() == 2);
+    return CE->getArg(Idx);
+  }
+  llvm_unreachable("unhandled case");
+}
+static std::pair<Expr *, Expr *>
+extractOriginalOperandsFromRewrittenComparison(Expr *E, bool IsThreeWay,
+                                               bool IsSynthesized) {
+  if (IsThreeWay)
+    return {extractOperand(E, IsSynthesized ? 1 : 0),
+            extractOperand(E, IsSynthesized ? 0 : 1)};
+  return extractOriginalOperandsFromRewrittenComparison(
+      extractOperand(E, IsSynthesized ? 1 : 0), true, IsSynthesized);
+}
+
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCXXRewrittenExpr(CXXRewrittenExpr *E) {
+
+  // FIXME(EricWF): Is there a case where the underlying expression has been
+  // transformed in such a way that we need to re-compute the rewritten
+  // expression? (and not just re-build it).
+  ExprResult RewrittenRes = getDerived().TransformExpr(E->getRewrittenExpr());
+  if (RewrittenRes.isInvalid())
+    return ExprError();
+  Expr *Rewritten = RewrittenRes.get();
+
+  if (Rewritten == E->getRewrittenExpr() && !getDerived().AlwaysRebuild())
+    return E;
+
+  Expr *Original;
+  switch (E->getRewrittenKind()) {
+  case CXXRewrittenExpr::Comparison: {
+    BinaryOperator *Op = cast<BinaryOperator>(E->getOriginalExpr());
+
+    // Extract the already transformed operands from the rewritten expression.
+    std::pair<Expr *, Expr *> OrigArgs =
+        extractOriginalOperandsFromRewrittenComparison(
+            Rewritten, Op->getOpcode() == BO_Cmp,
+            E->getRewrittenInfo()->CompareBits.IsSynthesized);
+
+    // Build a dummy node representing the expression as written.
+    Original = new (SemaRef.Context) BinaryOperator(
+        OpaqueValueExpr::Create(SemaRef.Context, OrigArgs.first),
+        OpaqueValueExpr::Create(SemaRef.Context, OrigArgs.second),
+        Op->getOpcode(), Rewritten->getType(), Rewritten->getValueKind(),
+        Rewritten->getObjectKind(), Op->getOperatorLoc(), Op->getFPFeatures());
+    break;
+  }
+  }
+  return getDerived().RebuildCXXRewrittenExpr(
+      E->getRewrittenKind(), Original, Rewritten, *E->getRewrittenInfo());
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -831,6 +831,19 @@
   }
 }
 
+const ImplicitConversionSequence &
+OverloadCandidate::getConversion(unsigned ArgIdx) const {
+  return Conversions[getConversionIndexForArgIndex(ArgIdx)];
+}
+
+unsigned OverloadCandidate::getConversionIndexForArgIndex(unsigned Idx) const {
+  if (getRewrittenKind() != ROC_Synthesized)
+    return Idx;
+  // FIXME(EricWF): Handle these cases.
+  assert(Idx < 2);
+  return Idx == 0 ? 1 : 0;
+}
+
 void OverloadCandidateSet::destroyCandidates() {
   for (iterator i = begin(), e = end(); i != e; ++i) {
     for (auto &C : i->Conversions)
@@ -5942,13 +5955,15 @@
   //   (possibly cv-qualified) T2", when T2 is an enumeration type, are
   //   candidate functions.
   if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
-      !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
+      !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args)) {
     return;
+  }
 
   // C++11 [class.copy]p11: [DR1402]
   //   A defaulted move constructor that is defined as deleted is ignored by
   //   overload resolution.
   CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function);
+
   if (Constructor && Constructor->isDefaulted() && Constructor->isDeleted() &&
       Constructor->isMoveConstructor())
     return;
@@ -5964,6 +5979,7 @@
   Candidate.Function = Function;
   Candidate.Viable = true;
   Candidate.IsSurrogate = false;
+  Candidate.RewrittenOpKind = ROC_None;
   Candidate.IgnoreObjectArgument = false;
   Candidate.ExplicitCallArguments = Args.size();
 
@@ -6654,6 +6670,7 @@
     Candidate.Function = MethodTmpl->getTemplatedDecl();
     Candidate.Viable = false;
     Candidate.IsSurrogate = false;
+    Candidate.RewrittenOpKind = ROC_None;
     Candidate.IgnoreObjectArgument =
         cast<CXXMethodDecl>(Candidate.Function)->isStatic() ||
         ObjectType.isNull();
@@ -6718,6 +6735,7 @@
     Candidate.Function = FunctionTemplate->getTemplatedDecl();
     Candidate.Viable = false;
     Candidate.IsSurrogate = false;
+    Candidate.RewrittenOpKind = ROC_None;
     // Ignore the object argument if there is one, since we don't have an object
     // type.
     Candidate.IgnoreObjectArgument =
@@ -6889,6 +6907,7 @@
   Candidate.FoundDecl = FoundDecl;
   Candidate.Function = Conversion;
   Candidate.IsSurrogate = false;
+  Candidate.RewrittenOpKind = ROC_None;
   Candidate.IgnoreObjectArgument = false;
   Candidate.FinalConversion.setAsIdentityConversion();
   Candidate.FinalConversion.setFromType(ConvType);
@@ -7050,6 +7069,7 @@
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_bad_deduction;
     Candidate.IsSurrogate = false;
+    Candidate.RewrittenOpKind = ROC_None;
     Candidate.IgnoreObjectArgument = false;
     Candidate.ExplicitCallArguments = 1;
     Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
@@ -7090,6 +7110,7 @@
   Candidate.Surrogate = Conversion;
   Candidate.Viable = true;
   Candidate.IsSurrogate = true;
+  Candidate.RewrittenOpKind = ROC_None;
   Candidate.IgnoreObjectArgument = false;
   Candidate.ExplicitCallArguments = Args.size();
 
@@ -7186,7 +7207,7 @@
 void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
                                        SourceLocation OpLoc,
                                        ArrayRef<Expr *> Args,
-                                       OverloadCandidateSet& CandidateSet,
+                                       OverloadCandidateSet &CandidateSet,
                                        SourceRange OpRange) {
   DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
 
@@ -7247,6 +7268,7 @@
   Candidate.FoundDecl = DeclAccessPair::make(nullptr, AS_none);
   Candidate.Function = nullptr;
   Candidate.IsSurrogate = false;
+  Candidate.RewrittenOpKind = ROC_None;
   Candidate.IgnoreObjectArgument = false;
   std::copy(ParamTys, ParamTys + Args.size(), Candidate.BuiltinParamTypes);
 
@@ -8862,20 +8884,78 @@
   }
 }
 
+/// Add the rewritten and synthesized candidates for binary comparison
+///  operators. No additional semantic checking is done to see if the candidate
+///    is well formed.
+void Sema::AddRewrittenOperatorCandidates(OverloadedOperatorKind Op,
+                                          SourceLocation OpLoc,
+                                          ArrayRef<Expr *> InputArgs,
+                                          const UnresolvedSetImpl &Fns,
+                                          OverloadCandidateSet &CandidateSet,
+                                          bool PerformADL) {
+  auto Opc = BinaryOperator::getOverloadedOpcode(Op);
+
+  bool IsRelationalOrEquality =
+      BinaryOperator::isRelationalOp(Opc) || BinaryOperator::isEqualityOp(Opc);
+  if (!IsRelationalOrEquality && Opc != BO_Cmp)
+    return;
+  assert(InputArgs.size() == 2);
+
+  OverloadedOperatorKind CmpOp = OO_Spaceship;
+  DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(CmpOp);
+
+  // AddCandidates - Add operator<=> candidates for the specified set of args,
+  // and mark all newly generated candidates as having the specified
+  // 'RewrittenOverloadCandidateKind'.
+  auto AddCandidates = [&](ArrayRef<Expr *> Args,
+                           RewrittenOverloadCandidateKind Kind) {
+    OverloadCandidateSet::RewrittenCandidateContextGuard Guard(CandidateSet);
+
+    unsigned InitialSize = CandidateSet.size();
+    AddFunctionCandidates(Fns, Args, CandidateSet);
+    AddMemberOperatorCandidates(CmpOp, OpLoc, Args, CandidateSet);
+    if (PerformADL)
+      AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
+                                           /*ExplicitTemplateArgs*/ nullptr,
+                                           CandidateSet);
+    AddBuiltinOperatorCandidates(CmpOp, OpLoc, Args, CandidateSet);
+
+    for (auto It = std::next(CandidateSet.begin(), InitialSize);
+         It != CandidateSet.end(); ++It) {
+      OverloadCandidate &Ovl = *It;
+      Ovl.RewrittenOpKind = Kind;
+    }
+  };
+
+  // If we have a relational or equality operation, add the rewritten candidates
+  // of the form: (LHS <=> RHS) @ 0
+  if (IsRelationalOrEquality)
+   AddCandidates(InputArgs, ROC_Rewritten);
+
+  // TODO: We should be able to avoid adding synthesized candidates when LHS and
+  // RHS have the same type, value category, and other relevent properties.
+  // In that case synthesized candidates for <=> should be the same as the
+  // rewritten ones. Note: It's still possible for the result of operator<=> to
+  // be usable only on the left or right side of the expression (0 @ <result>)
+  // or (<result> @ 0).
+
+  // For relational, equality, and three-way comparisons, add the rewritten and
+  // synthesized candidates of the form: 0 @ (RHS <=> LHS)
+  SmallVector<Expr *, 2> ReverseArgs(InputArgs.rbegin(), InputArgs.rend());
+  AddCandidates(ReverseArgs, ROC_Synthesized);
+}
+
 /// \brief Add function candidates found via argument-dependent lookup
 /// to the set of overloading candidates.
 ///
 /// This routine performs argument-dependent name lookup based on the
 /// given function name (which may also be an operator name) and adds
 /// all of the overload candidates found by ADL to the overload
 /// candidate set (C++ [basic.lookup.argdep]).
-void
-Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
-                                           SourceLocation Loc,
-                                           ArrayRef<Expr *> Args,
-                                 TemplateArgumentListInfo *ExplicitTemplateArgs,
-                                           OverloadCandidateSet& CandidateSet,
-                                           bool PartialOverloading) {
+void Sema::AddArgumentDependentLookupCandidates(
+    DeclarationName Name, SourceLocation Loc, ArrayRef<Expr *> Args,
+    TemplateArgumentListInfo *ExplicitTemplateArgs,
+    OverloadCandidateSet &CandidateSet, bool PartialOverloading) {
   ADLResult Fns;
 
   // FIXME: This approach for uniquing ADL results (and removing
@@ -9008,8 +9088,8 @@
   assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
   bool HasBetterConversion = false;
   for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
-    bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]);
-    bool Cand2Bad = IsIllFormedConversion(Cand2.Conversions[ArgIdx]);
+    bool Cand1Bad = IsIllFormedConversion(Cand1.getConversion(ArgIdx));
+    bool Cand2Bad = IsIllFormedConversion(Cand2.getConversion(ArgIdx));
     if (Cand1Bad != Cand2Bad) {
       if (Cand1Bad)
         return false;
@@ -9026,8 +9106,8 @@
   //   conversion sequence than ICSi(F2), and then...
   for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
     switch (CompareImplicitConversionSequences(S, Loc,
-                                               Cand1.Conversions[ArgIdx],
-                                               Cand2.Conversions[ArgIdx])) {
+                                               Cand1.getConversion(ArgIdx),
+                                               Cand2.getConversion(ArgIdx))) {
     case ImplicitConversionSequence::Better:
       // Cand1 has a better conversion sequence.
       HasBetterConversion = true;
@@ -9133,6 +9213,48 @@
     // Inherited from sibling base classes: still ambiguous.
   }
 
+  // Check C++2a tie-breakers for rewritten candidates
+  {
+    // --- F2 is a rewritten candidate ([over.match.oper]) and F1 is not.
+    RewrittenOverloadCandidateKind C1Roc = Cand1.getRewrittenKind();
+    RewrittenOverloadCandidateKind C2Roc = Cand2.getRewrittenKind();
+    if (C1Roc || C2Roc) {
+      if (!C1Roc || !C2Roc)
+        return !C1Roc;
+      // --- F1 and F2 are rewritten candidates, and F2 is a synthesized
+      // candidate with reversed order of parameters and F1 is not.
+      if ((C1Roc == ROC_Synthesized || C2Roc == ROC_Synthesized) &&
+          C1Roc != C2Roc) {
+        auto GetParamTypes = [&](const OverloadCandidate &Ovl) {
+          SmallVector<QualType, 2> Types;
+          // If the candidate is a method, compute the implicit object type.
+          if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Ovl.Function)) {
+            assert(Ovl.Conversions[0].isStandard());
+            QualType Ty = Ovl.Conversions[0].Standard.getToType(2);
+            assert(!Ty->isReferenceType());
+            const auto *FTP = MD->getType()->getAs<FunctionProtoType>();
+            switch (FTP->getRefQualifier()) {
+            case RQ_LValue:
+            case RQ_None:
+              Types.push_back(S.Context.getLValueReferenceType(Ty));
+              break;
+            case RQ_RValue:
+              Types.push_back(S.Context.getRValueReferenceType(Ty));
+              break;
+            }
+          }
+          for (unsigned I = 0; I < Ovl.getNumParams(); ++I)
+            Types.push_back(Ovl.getParamType(I).getCanonicalType());
+          if (Ovl.getRewrittenKind() == ROC_Synthesized)
+            llvm::reverse(Types);
+          return Types;
+        };
+        if (GetParamTypes(Cand1) == GetParamTypes(Cand2))
+          return C2Roc == ROC_Synthesized;
+      }
+    }
+  }
+
   // Check C++17 tie-breakers for deduction guides.
   {
     auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
@@ -9245,9 +9367,9 @@
 /// function, \p Best points to the candidate function found.
 ///
 /// \returns The result of overload resolution.
-OverloadingResult
-OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
-                                         iterator &Best) {
+OverloadingResult OverloadCandidateSet::BestViableFunction(
+    Sema &S, SourceLocation Loc, iterator &Best,
+    SmallVectorImpl<OverloadCandidate *> *EquivalentCands) {
   llvm::SmallVector<OverloadCandidate *, 16> Candidates;
   std::transform(begin(), end(), std::back_inserter(Candidates),
                  [](OverloadCandidate &Cand) { return &Cand; });
@@ -9289,33 +9411,42 @@
   if (Best == end())
     return OR_No_Viable_Function;
 
-  llvm::SmallVector<const NamedDecl *, 4> EquivalentCands;
-
+  llvm::SmallVector<const NamedDecl *, 4> EquivalentFunctionCands;
+  if (EquivalentCands)
+    EquivalentCands->push_back(&(*Best));
   // Make sure that this function is better than every other viable
   // function. If not, we have an ambiguity.
   for (auto *Cand : Candidates) {
     if (Cand->Viable && Cand != Best &&
         !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) {
+      if (EquivalentCands)
+        EquivalentCands->push_back(Cand);
       if (S.isEquivalentInternalLinkageDeclaration(Best->Function,
                                                    Cand->Function)) {
-        EquivalentCands.push_back(Cand->Function);
+        EquivalentFunctionCands.push_back(Cand->Function);
         continue;
       }
+      if (EquivalentCands)
+        continue;
 
       Best = end();
       return OR_Ambiguous;
     }
   }
+  if (EquivalentCands && EquivalentCands->size() > 1) {
+    Best = end();
+    return OR_Ambiguous;
+  }
 
   // Best is the best viable function.
   if (Best->Function &&
       (Best->Function->isDeleted() ||
        S.isFunctionConsideredUnavailable(Best->Function)))
     return OR_Deleted;
 
-  if (!EquivalentCands.empty())
+  if (!EquivalentFunctionCands.empty())
     S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
-                                                    EquivalentCands);
+                                                    EquivalentFunctionCands);
 
   return OR_Success;
 }
@@ -12228,6 +12359,325 @@
   return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
 }
 
+ExprResult Sema::BuildBinaryOperatorCandidate(SourceLocation OpLoc,
+                                              BinaryOperatorKind Opc,
+                                              const OverloadCandidate &Ovl,
+                                              Expr *LHSE, Expr *RHSE,
+                                              bool HadMultipleCandidates) {
+  Expr *Args[2] = {LHSE, RHSE};
+  OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
+  // We found a built-in operator or an overloaded operator.
+  FunctionDecl *FnDecl = Ovl.Function;
+
+  if (FnDecl) {
+    Expr *Base = nullptr;
+    // We matched an overloaded operator. Build a call to that
+    // operator.
+
+    // Convert the arguments.
+    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+      // Ovl.Access is only meaningful for class members.
+      CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Ovl.FoundDecl);
+
+      ExprResult Arg1 =
+          PerformCopyInitialization(InitializedEntity::InitializeParameter(
+                                        Context, FnDecl->getParamDecl(0)),
+                                    SourceLocation(), Args[1]);
+      if (Arg1.isInvalid())
+        return ExprError();
+
+      ExprResult Arg0 = PerformObjectArgumentInitialization(
+          Args[0], /*Qualifier=*/nullptr, Ovl.FoundDecl, Method);
+      if (Arg0.isInvalid())
+        return ExprError();
+      Base = Args[0] = Arg0.getAs<Expr>();
+      Args[1] = Arg1.getAs<Expr>();
+    } else {
+      // Convert the arguments.
+      ExprResult Arg0 =
+          PerformCopyInitialization(InitializedEntity::InitializeParameter(
+                                        Context, FnDecl->getParamDecl(0)),
+                                    SourceLocation(), Args[0]);
+      if (Arg0.isInvalid())
+        return ExprError();
+
+      ExprResult Arg1 =
+          PerformCopyInitialization(InitializedEntity::InitializeParameter(
+                                        Context, FnDecl->getParamDecl(1)),
+                                    SourceLocation(), Args[1]);
+      if (Arg1.isInvalid())
+        return ExprError();
+      Args[0] = Arg0.getAs<Expr>();
+      Args[1] = Arg1.getAs<Expr>();
+    }
+
+    // Build the actual expression node.
+    ExprResult FnExpr = CreateFunctionRefExpr(
+        *this, FnDecl, Ovl.FoundDecl, Base, HadMultipleCandidates, OpLoc);
+    if (FnExpr.isInvalid())
+      return ExprError();
+
+    // Determine the result type.
+    QualType ResultTy = FnDecl->getReturnType();
+    ExprValueKind VK = Expr::getValueKindForType(ResultTy);
+    ResultTy = ResultTy.getNonLValueExprType(Context);
+
+    CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(
+        Context, Op, FnExpr.get(), Args, ResultTy, VK, OpLoc, FPFeatures);
+
+    if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
+      return ExprError();
+
+    ArrayRef<const Expr *> ArgsArray(Args, 2);
+    const Expr *ImplicitThis = nullptr;
+    // Cut off the implicit 'this'.
+    if (isa<CXXMethodDecl>(FnDecl)) {
+      ImplicitThis = ArgsArray[0];
+      ArgsArray = ArgsArray.slice(1);
+    }
+
+    // Check for a self move.
+    if (Op == OO_Equal)
+      DiagnoseSelfMove(Args[0], Args[1], OpLoc);
+
+    checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray,
+              isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
+              Sema::VariadicDoesNotApply);
+
+    return MaybeBindToTemporary(TheCall);
+
+  } else {
+    // We matched a built-in operator. Convert the arguments, then
+    // break out so that we will build the appropriate built-in
+    // operator node.
+    ExprResult ArgsRes0 =
+        PerformImplicitConversion(Args[0], Ovl.BuiltinParamTypes[0],
+                                  Ovl.Conversions[0], Sema::AA_Passing);
+    if (ArgsRes0.isInvalid())
+      return ExprError();
+    Args[0] = ArgsRes0.get();
+
+    ExprResult ArgsRes1 =
+        PerformImplicitConversion(Args[1], Ovl.BuiltinParamTypes[1],
+                                  Ovl.Conversions[1], Sema::AA_Passing);
+    if (ArgsRes1.isInvalid())
+      return ExprError();
+    Args[1] = ArgsRes1.get();
+  }
+  // We matched a built-in operator; build it.
+  return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
+}
+
+namespace {
+
+/// \brief RewrittenOverloadResolver - This class handles initial
+/// overload resolution for candidate sets which include rewritten candidates.
+///
+/// Rewritten candidates haven't been fully checked for validity. They may still
+/// be invalid if:
+///    (A) The rewritten candidate is a builtin, but semantic checking of the
+///        builtin would fail.
+///    (B) The result of the "partially rewritten expression"
+///        (ie the (LHS <=> RHS) part) is ill-formed when used as an operand to
+///        (<result> @ 0) or (0 @ <result>).
+///
+/// TODO: Separate out the bits of semantic checking for builtin spaceship
+/// operators which determine validity and the return type, and use that instead
+/// of building the full expression to check validity.
+class RewrittenOverloadResolver {
+  enum CheckOverloadResult { Done, Continue };
+
+public:
+  RewrittenOverloadResolver(Sema &S, SourceLocation OpLoc,
+                            BinaryOperatorKind Opc, ArrayRef<Expr *> Args,
+                            const UnresolvedSetImpl &Fns, bool PerformADL,
+                            OverloadCandidateSet &CS)
+      : S(S), OpLoc(OpLoc), Opc(Opc), Args(Args), Fns(Fns),
+        PerformADL(PerformADL), CandidateSet(CS) {}
+
+  ExprResult ResolveRewrittenCandidates() {
+    ExprResult FinalResult = ExprError();
+    OverloadCandidateSet::iterator Best;
+    OverloadingResult OvlRes;
+    llvm::SmallVector<OverloadCandidate *, 4> EquivCands;
+    do {
+      EquivCands.clear();
+      OvlRes = CandidateSet.BestViableFunction(S, OpLoc, Best, &EquivCands);
+    } while (Continue == RemoveNonViableRewrittenCandidates(
+                             OvlRes, Best, EquivCands, FinalResult));
+    return FinalResult;
+  }
+private:
+  CheckOverloadResult RemoveNonViableRewrittenCandidates(
+      OverloadingResult OvlRes, OverloadCandidateSet::iterator Best,
+      ArrayRef<OverloadCandidate *> EquivCands, ExprResult &FinalResult);
+  ExprResult BuildRewrittenCandidate(const OverloadCandidate &Ovl);
+
+  RewrittenOverloadResolver(RewrittenOverloadResolver const &) = delete;
+  RewrittenOverloadResolver &
+  operator=(RewrittenOverloadResolver const &) = delete;
+
+private:
+  Sema &S;
+  SourceLocation OpLoc;
+  BinaryOperatorKind Opc;
+  ArrayRef<Expr *> Args;
+  const UnresolvedSetImpl &Fns;
+  bool PerformADL;
+  OverloadCandidateSet &CandidateSet;
+};
+} // end namespace
+
+ExprResult RewrittenOverloadResolver::BuildRewrittenCandidate(
+    const OverloadCandidate &Ovl) {
+  Expr *RewrittenArgs[2] = {Args[0], Args[1]};
+  assert(Ovl.getRewrittenKind());
+  bool IsSynthesized = Ovl.getRewrittenKind() == ROC_Synthesized;
+  if (IsSynthesized)
+    std::swap(RewrittenArgs[0], RewrittenArgs[1]);
+
+  // Supress diagnostics when building the expressions for the specified
+  // candidate. If evaluation fails the candidate will be marked non-viable
+  // and the best viable candidate re-computed.
+  Sema::TentativeAnalysisScope DiagnosticScopeGuard(S);
+
+  // Build the '(LHS <=> RHS)' operand to the full expression.
+  ExprResult RewrittenRes = S.BuildBinaryOperatorCandidate(
+      OpLoc, BO_Cmp, Ovl, RewrittenArgs[0], RewrittenArgs[1],
+      /*HadMultipleCandidates*/ false);
+  if (RewrittenRes.isInvalid())
+    return ExprError();
+
+  if (Opc != BO_Cmp) {
+    // Now attempt to build the full expression '(LHS <=> RHS) @ 0' using the
+    // evaluated operand and the literal 0.
+    llvm::APInt I =
+        llvm::APInt::getNullValue(S.Context.getIntWidth(S.Context.IntTy));
+    Expr *Zero =
+        IntegerLiteral::Create(S.Context, I, S.Context.IntTy, SourceLocation());
+
+    Expr *NewLHS = RewrittenRes.get();
+    Expr *NewRHS = Zero;
+    if (Ovl.getRewrittenKind() == ROC_Synthesized)
+      std::swap(NewLHS, NewRHS);
+
+    RewrittenRes =
+        S.CreateOverloadedBinOp(OpLoc, Opc, Fns, NewLHS, NewRHS, PerformADL,
+                                /*AllowRewrittenCandidates*/ false);
+    if (RewrittenRes.isInvalid())
+      return ExprError();
+  }
+  Expr *Rewritten = RewrittenRes.get();
+
+  // Create a dummy expression representing the original expression as written.
+  // FIXME(EricWF): This doesn't actually really represent the expression as
+  // written, because it may not result in a to a builtin operator.
+  Expr *Original = new (S.Context)
+      BinaryOperator(OpaqueValueExpr::Create(S.Context, Args[0]),
+                     OpaqueValueExpr::Create(S.Context, Args[1]), Opc,
+                     Rewritten->getType(), Rewritten->getValueKind(),
+                     Rewritten->getObjectKind(), OpLoc, S.FPFeatures);
+
+  CXXRewrittenExpr::ExtraRewrittenBits ExtraBits;
+  ExtraBits.CompareBits.IsSynthesized = IsSynthesized;
+  return new (S.Context) CXXRewrittenExpr(CXXRewrittenExpr::Comparison,
+                                          Original, Rewritten, ExtraBits);
+}
+
+/// Rewritten candidates have been added but not checked for validity. They
+/// could still be non-viable if:
+///  (A) The rewritten call (x <=> y) is a builtin, but it will be ill-formed
+///      when built (for example it has narrowing conversions).
+///  (B) The expression (x <=> y) @ 0 is ill-formed for the result of (x <=> y).
+///
+/// If either is the case, this function should be considered non-viable and
+/// another best viable function needs to be computed.
+///
+/// Therefore, we do the following:
+///  (1) If we have no viable candidate, or a deleted candidate, stop.
+///      Otherwise, if we have a best viable candidate or a set of ambiguous
+///      candidates and none of them are rewritten, stop.
+///
+///  (2) If the best viable candidate is a rewritten candidate, build and
+///      check the full expression for that candidate. If it succeeds return
+///      the result. Otherwise, mark the candidate as non-viable, re-compute
+///      the best viable function, and continue.
+///
+///  (3) If we have ambiguity attempt to resolve it by evaluating each rewritten
+///      candidate causing ambiguity:
+///
+///        (3.1) build the full expression for the specified candidate.
+///        (3.2) If the result is invalid, mark the candidate as non-viable.
+///
+///      If only one viable candidate remains, stop. If the viable candidate is
+///      rewritten, return the previously computed full expression. Otherwise,
+///      if we have more than one viable candidate, stop. If no viable candidates
+///      remain from the initial set of equally ranked candidates, recompute the
+///      new best viable overload and continue.
+RewrittenOverloadResolver::CheckOverloadResult
+RewrittenOverloadResolver::RemoveNonViableRewrittenCandidates(
+    OverloadingResult OvlRes, OverloadCandidateSet::iterator Best,
+    ArrayRef<OverloadCandidate *> EquivCands, ExprResult &FinalResult) {
+  auto Success = [&](ExprResult Res) {
+    FinalResult = Res;
+    return Done;
+  };
+  switch (OvlRes) {
+  case OR_Deleted:
+    // FIXME(EricWF): If we've found a deleted rewritten operator, it's
+    // possible we should have never considered it a viable candidate.
+  case OR_No_Viable_Function:
+    return Done;
+
+  case OR_Success: {
+    OverloadCandidate &Ovl = *Best;
+    if (!Ovl.getRewrittenKind())
+      return Done;
+    // Build the full expression for the rewritten candidate, and return it if
+    // it's valid. Otherwise mark this candidate as non-viable and continue.
+    ExprResult Res = BuildRewrittenCandidate(Ovl);
+    if (Res.isInvalid()) {
+      Ovl.Viable = false;
+      return Continue;
+    }
+    return Success(Res);
+  }
+  case OR_Ambiguous: {
+    assert(EquivCands.size() > 1);
+    // If none of the viable candidates are rewritten, stop.
+    if (llvm::none_of(EquivCands, [](const OverloadCandidate *Cand) {
+          return (bool)Cand->getRewrittenKind();
+        }))
+      return Done;
+    int NumViableCandidates = 0;
+    ExprResult ViableRewritten = ExprError();
+    for (auto *Cand : EquivCands) {
+      OverloadCandidate &Ovl = *Cand;
+      if (Ovl.getRewrittenKind()) {
+        ExprResult Res = BuildRewrittenCandidate(Ovl);
+        if (Res.isInvalid()) {
+          Ovl.Viable = false;
+          continue;
+        }
+        ViableRewritten = Res;
+      }
+      ++NumViableCandidates;
+    }
+    // If only one of the candidates turns out to be viable, and it's a
+    // rewritten candidate, return that candidate as the result.
+    if (NumViableCandidates == 1 && !ViableRewritten.isInvalid())
+      return Success(ViableRewritten);
+    // If we still have ambiguity, return and let the caller diagnose it.
+    if (NumViableCandidates > 1)
+      return Done;
+    // All of the equally ranked candidates are invalid. Loop and try overload
+    // resolution again.
+    return Continue;
+  }
+  }
+  llvm_unreachable("unhandled case");
+}
+
 /// \brief Create a binary operation that may resolve to an overloaded
 /// operator.
 ///
@@ -12244,11 +12694,11 @@
 ///
 /// \param LHS Left-hand argument.
 /// \param RHS Right-hand argument.
-ExprResult
-Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
-                            BinaryOperatorKind Opc,
-                            const UnresolvedSetImpl &Fns,
-                            Expr *LHS, Expr *RHS, bool PerformADL) {
+ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
+                                       BinaryOperatorKind Opc,
+                                       const UnresolvedSetImpl &Fns, Expr *LHS,
+                                       Expr *RHS, bool PerformADL,
+                                       bool AllowRewrittenCandidates) {
   Expr *Args[2] = { LHS, RHS };
   LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
 
@@ -12310,11 +12760,27 @@
   if (Opc == BO_PtrMemD)
     return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
 
+  UnresolvedSet<6> OrigFuncs;
+  UnresolvedSet<6> ThreeWayFuncs;
+  for (NamedDecl *D : Fns) {
+    FunctionDecl *FD = D->getAsFunction();
+    if (FD) {
+      assert(FD->isOverloadedOperator());
+      if (FD->getOverloadedOperator() == OO_Spaceship) {
+        ThreeWayFuncs.addDecl(D);
+        if (Op == OO_Spaceship)
+          OrigFuncs.addDecl(D);
+      } else
+        OrigFuncs.addDecl(D);
+    } else
+      OrigFuncs.addDecl(D);
+  }
+
   // Build an empty overload set.
   OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
 
   // Add the candidates from the given function set.
-  AddFunctionCandidates(Fns, Args, CandidateSet);
+  AddFunctionCandidates(OrigFuncs, Args, CandidateSet);
 
   // Add operator candidates that are member functions.
   AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
@@ -12330,191 +12796,113 @@
   // Add builtin operator candidates.
   AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
 
-  bool HadMultipleCandidates = (CandidateSet.size() > 1);
-
-  // Perform overload resolution.
-  OverloadCandidateSet::iterator Best;
-  switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) {
-    case OR_Success: {
-      // We found a built-in operator or an overloaded operator.
-      FunctionDecl *FnDecl = Best->Function;
-
-      if (FnDecl) {
-        Expr *Base = nullptr;
-        // We matched an overloaded operator. Build a call to that
-        // operator.
-
-        // Convert the arguments.
-        if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
-          // Best->Access is only meaningful for class members.
-          CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Best->FoundDecl);
-
-          ExprResult Arg1 =
-            PerformCopyInitialization(
-              InitializedEntity::InitializeParameter(Context,
-                                                     FnDecl->getParamDecl(0)),
-              SourceLocation(), Args[1]);
-          if (Arg1.isInvalid())
-            return ExprError();
-
-          ExprResult Arg0 =
-            PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
-                                                Best->FoundDecl, Method);
-          if (Arg0.isInvalid())
-            return ExprError();
-          Base = Args[0] = Arg0.getAs<Expr>();
-          Args[1] = RHS = Arg1.getAs<Expr>();
-        } else {
-          // Convert the arguments.
-          ExprResult Arg0 = PerformCopyInitialization(
-            InitializedEntity::InitializeParameter(Context,
-                                                   FnDecl->getParamDecl(0)),
-            SourceLocation(), Args[0]);
-          if (Arg0.isInvalid())
-            return ExprError();
-
-          ExprResult Arg1 =
-            PerformCopyInitialization(
-              InitializedEntity::InitializeParameter(Context,
-                                                     FnDecl->getParamDecl(1)),
-              SourceLocation(), Args[1]);
-          if (Arg1.isInvalid())
-            return ExprError();
-          Args[0] = LHS = Arg0.getAs<Expr>();
-          Args[1] = RHS = Arg1.getAs<Expr>();
-        }
-
-        // Build the actual expression node.
-        ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
-                                                  Best->FoundDecl, Base,
-                                                  HadMultipleCandidates, OpLoc);
-        if (FnExpr.isInvalid())
-          return ExprError();
-
-        // Determine the result type.
-        QualType ResultTy = FnDecl->getReturnType();
-        ExprValueKind VK = Expr::getValueKindForType(ResultTy);
-        ResultTy = ResultTy.getNonLValueExprType(Context);
-
-        CXXOperatorCallExpr *TheCall =
-          new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(),
-                                            Args, ResultTy, VK, OpLoc,
-                                            FPFeatures);
-
-        if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
-                                FnDecl))
-          return ExprError();
+  // C++2a Add rewritten and synthesized operator candidates.
+  bool HasRewrittenCandidates = false;
+  if (getLangOpts().CPlusPlus2a && AllowRewrittenCandidates &&
+      BinaryOperator::isComparisonOp(Opc)) {
+    unsigned BeforeRewrittenSize = CandidateSet.size();
+    AddRewrittenOperatorCandidates(Op, OpLoc, Args, ThreeWayFuncs, CandidateSet,
+                                   PerformADL);
+    HasRewrittenCandidates = BeforeRewrittenSize != CandidateSet.size();
+  }
 
-        ArrayRef<const Expr *> ArgsArray(Args, 2);
-        const Expr *ImplicitThis = nullptr;
-        // Cut off the implicit 'this'.
-        if (isa<CXXMethodDecl>(FnDecl)) {
-          ImplicitThis = ArgsArray[0];
-          ArgsArray = ArgsArray.slice(1);
-        }
+  if (HasRewrittenCandidates) {
+    RewrittenOverloadResolver RewrittenOvlResolver(*this, OpLoc, Opc, Args, Fns,
+                                                   PerformADL, CandidateSet);
 
-        // Check for a self move.
-        if (Op == OO_Equal)
-          DiagnoseSelfMove(Args[0], Args[1], OpLoc);
+    // Perform initial overload resolution that includes partially checked
+    // rewritten candidates, removing rewritten candidates which turn out to be
+    // invalid as needed.
+    ExprResult RewrittenResult =
+        RewrittenOvlResolver.ResolveRewrittenCandidates();
 
-        checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray,
-                  isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
-                  VariadicDoesNotApply);
+    // If overload resolution was successful and the result was a re-written
+    // overload candidate, then that candidate was evaluated and we can return
+    // the result directly.
+    if (!RewrittenResult.isInvalid())
+      return RewrittenResult;
+  }
 
-        return MaybeBindToTemporary(TheCall);
-      } else {
-        // We matched a built-in operator. Convert the arguments, then
-        // break out so that we will build the appropriate built-in
-        // operator node.
-        ExprResult ArgsRes0 =
-            PerformImplicitConversion(Args[0], Best->BuiltinParamTypes[0],
-                                      Best->Conversions[0], AA_Passing);
-        if (ArgsRes0.isInvalid())
-          return ExprError();
-        Args[0] = ArgsRes0.get();
+  // Perform final overload resolution.
+  bool HadMultipleCandidates = (CandidateSet.size() > 1);
+  OverloadCandidateSet::iterator Best;
+  switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) {
+  case OR_Success:
+    assert(
+        !Best->getRewrittenKind() &&
+        "rewritten candidates should have already been resolved and evaluated");
+    return BuildBinaryOperatorCandidate(OpLoc, Opc, *Best, Args[0], Args[1],
+                                        HadMultipleCandidates);
+  case OR_No_Viable_Function: {
+    // C++ [over.match.oper]p9:
+    //   If the operator is the operator , [...] and there are no
+    //   viable functions, then the operator is assumed to be the
+    //   built-in operator and interpreted according to clause 5.
+    if (Opc == BO_Comma)
+      break;
 
-        ExprResult ArgsRes1 =
-            PerformImplicitConversion(Args[1], Best->BuiltinParamTypes[1],
-                                      Best->Conversions[1], AA_Passing);
-        if (ArgsRes1.isInvalid())
-          return ExprError();
-        Args[1] = ArgsRes1.get();
-        break;
+    // For class as left operand for assignment or compound assignment
+    // operator do not fall through to handling in built-in, but report that
+    // no overloaded assignment operator found
+    ExprResult Result = ExprError();
+    if (Args[0]->getType()->isRecordType() && Opc >= BO_Assign &&
+        Opc <= BO_OrAssign) {
+      Diag(OpLoc, diag::err_ovl_no_viable_oper)
+          << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange()
+          << Args[1]->getSourceRange();
+      if (Args[0]->getType()->isIncompleteType()) {
+        Diag(OpLoc, diag::note_assign_lhs_incomplete)
+            << Args[0]->getType() << Args[0]->getSourceRange()
+            << Args[1]->getSourceRange();
       }
-    }
-
-    case OR_No_Viable_Function: {
-      // C++ [over.match.oper]p9:
-      //   If the operator is the operator , [...] and there are no
-      //   viable functions, then the operator is assumed to be the
-      //   built-in operator and interpreted according to clause 5.
-      if (Opc == BO_Comma)
-        break;
-
-      // For class as left operand for assignment or compound assignment
-      // operator do not fall through to handling in built-in, but report that
-      // no overloaded assignment operator found
-      ExprResult Result = ExprError();
-      if (Args[0]->getType()->isRecordType() &&
-          Opc >= BO_Assign && Opc <= BO_OrAssign) {
-        Diag(OpLoc,  diag::err_ovl_no_viable_oper)
-             << BinaryOperator::getOpcodeStr(Opc)
-             << Args[0]->getSourceRange() << Args[1]->getSourceRange();
-        if (Args[0]->getType()->isIncompleteType()) {
-          Diag(OpLoc, diag::note_assign_lhs_incomplete)
-            << Args[0]->getType()
-            << Args[0]->getSourceRange() << Args[1]->getSourceRange();
-        }
-      } else {
-        // This is an erroneous use of an operator which can be overloaded by
-        // a non-member function. Check for non-member operators which were
-        // defined too late to be candidates.
-        if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args))
-          // FIXME: Recover by calling the found function.
-          return ExprError();
+    } else {
+      // This is an erroneous use of an operator which can be overloaded by
+      // a non-member function. Check for non-member operators which were
+      // defined too late to be candidates.
+      if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args))
+        // FIXME: Recover by calling the found function.
+        return ExprError();
 
-        // No viable function; try to create a built-in operation, which will
-        // produce an error. Then, show the non-viable candidates.
-        Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
-      }
-      assert(Result.isInvalid() &&
-             "C++ binary operator overloading is missing candidates!");
-      if (Result.isInvalid())
-        CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
-                                    BinaryOperator::getOpcodeStr(Opc), OpLoc);
-      return Result;
+      // No viable function; try to create a built-in operation, which will
+      // produce an error. Then, show the non-viable candidates.
+      Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
     }
-
-    case OR_Ambiguous:
-      Diag(OpLoc,  diag::err_ovl_ambiguous_oper_binary)
-          << BinaryOperator::getOpcodeStr(Opc)
-          << Args[0]->getType() << Args[1]->getType()
-          << Args[0]->getSourceRange() << Args[1]->getSourceRange();
-      CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args,
+    assert(Result.isInvalid() &&
+           "C++ binary operator overloading is missing candidates!");
+    if (Result.isInvalid())
+      CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
                                   BinaryOperator::getOpcodeStr(Opc), OpLoc);
-      return ExprError();
+    return Result;
+  }
+  case OR_Ambiguous:
+    Diag(OpLoc, diag::err_ovl_ambiguous_oper_binary)
+        << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getType()
+        << Args[1]->getType() << Args[0]->getSourceRange()
+        << Args[1]->getSourceRange();
+    CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args,
+                                BinaryOperator::getOpcodeStr(Opc), OpLoc);
+    return ExprError();
 
-    case OR_Deleted:
-      if (isImplicitlyDeleted(Best->Function)) {
-        CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
-        Diag(OpLoc, diag::err_ovl_deleted_special_oper)
+  case OR_Deleted:
+    if (isImplicitlyDeleted(Best->Function)) {
+      CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
+      Diag(OpLoc, diag::err_ovl_deleted_special_oper)
           << Context.getRecordType(Method->getParent())
           << getSpecialMember(Method);
 
-        // The user probably meant to call this special member. Just
-        // explain why it's deleted.
-        NoteDeletedFunction(Method);
-        return ExprError();
-      } else {
-        Diag(OpLoc, diag::err_ovl_deleted_oper)
-          << Best->Function->isDeleted()
-          << BinaryOperator::getOpcodeStr(Opc)
+      // The user probably meant to call this special member. Just
+      // explain why it's deleted.
+      NoteDeletedFunction(Method);
+      return ExprError();
+    } else {
+      Diag(OpLoc, diag::err_ovl_deleted_oper)
+          << Best->Function->isDeleted() << BinaryOperator::getOpcodeStr(Opc)
           << getDeletedOrUnavailableSuffix(Best->Function)
           << Args[0]->getSourceRange() << Args[1]->getSourceRange();
-      }
-      CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
-                                  BinaryOperator::getOpcodeStr(Opc), OpLoc);
-      return ExprError();
+    }
+    CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
+                                BinaryOperator::getOpcodeStr(Opc), OpLoc);
+    return ExprError();
   }
 
   // We matched a built-in operator; build it.
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -12372,7 +12372,12 @@
   if (Sc && OverOp != OO_None && OverOp != OO_Equal)
     S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),
                                    RHS->getType(), Functions);
-
+  if (S.getLangOpts().CPlusPlus2a) {
+    if (Sc && Opc != BO_Cmp && BinaryOperator::isRelationalOp(Opc)) {
+      S.LookupOverloadedOperatorName(OO_Spaceship, Sc, LHS->getType(),
+                                     RHS->getType(), Functions);
+    }
+  }
   // Build the (potentially-overloaded, potentially-dependent)
   // binary operation.
   return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS);
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1174,6 +1174,9 @@
   case Expr::VAArgExprClass:
     return canSubExprsThrow(*this, E);
 
+  case Expr::CXXRewrittenExprClass:
+    return canThrow(cast<CXXRewrittenExpr>(E)->getRewrittenExpr());
+
     // Some might be dependent for other reasons.
   case Expr::ArraySubscriptExprClass:
   case Expr::OMPArraySectionExprClass:
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -541,6 +541,10 @@
     return EmitScalarPrePostIncDec(E, LV, true, true);
   }
 
+  Value *VisitCXXRewrittenExpr(const CXXRewrittenExpr *E) {
+    return Visit(E->getRewrittenExpr());
+  }
+
   llvm::Value *EmitIncDecConsiderOverflowBehavior(const UnaryOperator *E,
                                                   llvm::Value *InVal,
                                                   bool IsInc);
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -1816,6 +1816,11 @@
   ID.AddInteger(S->getOperator());
 }
 
+void StmtProfiler::VisitCXXRewrittenExpr(const CXXRewrittenExpr *S) {
+  VisitExpr(S);
+  VisitExpr(S->getRewrittenExpr());
+}
+
 void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
   VisitStmt(S);
 }
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -2588,6 +2588,13 @@
   OS << ")";
 }
 
+void StmtPrinter::VisitCXXRewrittenExpr(CXXRewrittenExpr *E) {
+  // FIXME(EricWF): Are there ever cases where we want to display the rewritten
+  // code? For example when producing diagnostics on implicitly generated
+  // expressions?
+  Visit(E->getOriginalExpr());
+}
+
 // C++ Coroutines TS
 
 void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3516,9 +3516,13 @@
   }
 
   // These are used for internal purposes and cannot be meaningfully mangled.
-  case Expr::OpaqueValueExprClass:
-    llvm_unreachable("cannot mangle opaque value; mangling wrong thing?");
-
+  case Expr::OpaqueValueExprClass: {
+    const OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(E);
+    assert(OVE->getSourceExpr() && "cannot mangle opaque value without a "
+                                   "source expression; mangling wrong thing?");
+    mangleExpression(OVE->getSourceExpr());
+    break;
+  }
   case Expr::InitListExprClass: {
     Out << "il";
     mangleInitListElements(cast<InitListExpr>(E));
@@ -3559,6 +3563,10 @@
     mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity);
     break;
 
+  case Expr::CXXRewrittenExprClass:
+    mangleExpression(cast<CXXRewrittenExpr>(E)->getOriginalExpr(), Arity);
+    break;
+
   case Expr::SubstNonTypeTemplateParmExprClass:
     mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
                      Arity);
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -5059,6 +5059,10 @@
       return;
     VisitIgnoredValue(E);
   }
+
+  bool VisitCXXRewrittenExpr(const CXXRewrittenExpr *E) {
+    return StmtVisitorTy::Visit(E->getRewrittenExpr());
+  }
 };
 
 } // namespace
@@ -10858,6 +10862,8 @@
   case Expr::ChooseExprClass: {
     return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx);
   }
+  case Expr::CXXRewrittenExprClass:
+    return CheckICE(cast<CXXRewrittenExpr>(E)->getRewrittenExpr(), Ctx);
   }
 
   llvm_unreachable("Invalid StmtClass!");
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -287,7 +287,8 @@
     if (cast<GenericSelectionExpr>(E)->isResultDependent())
       return Cl::CL_PRValue;
     return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr());
-
+  case Expr::CXXRewrittenExprClass:
+    return ClassifyInternal(Ctx, cast<CXXRewrittenExpr>(E)->getRewrittenExpr());
   case Expr::BinaryOperatorClass:
   case Expr::CompoundAssignOperatorClass:
     // C doesn't have any binary expressions that are lvalues.
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -3187,6 +3187,11 @@
     return false;
   }
 
+  case CXXRewrittenExprClass: {
+    const auto *RO = cast<CXXRewrittenExpr>(this);
+    return RO->getRewrittenExpr()->HasSideEffects(Ctx, IncludePossibleEffects);
+  }
+
   case PseudoObjectExprClass: {
     // Only look for side-effects in the semantic form, and look past
     // OpaqueValueExpr bindings in that form.
@@ -3897,6 +3902,11 @@
   }
 }
 
+OpaqueValueExpr *OpaqueValueExpr::Create(const ASTContext &Ctx, Expr *E) {
+  return new (Ctx) OpaqueValueExpr(E->getExprLoc(), E->getType(),
+                                   E->getValueKind(), E->getObjectKind(), E);
+}
+
 const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
   if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
     e = ewc->getSubExpr();
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1666,7 +1666,7 @@
       EXPR_OBJC_BOXED_EXPRESSION,
       EXPR_OBJC_ARRAY_LITERAL,
       EXPR_OBJC_DICTIONARY_LITERAL,
-   
+
       /// \brief An ObjCEncodeExpr record.
       EXPR_OBJC_ENCODE,
 
@@ -1725,7 +1725,7 @@
       EXPR_OBJC_AVAILABILITY_CHECK,
 
       // C++
-      
+
       /// \brief A CXXCatchStmt record.
       STMT_CXX_CATCH,
 
@@ -1774,59 +1774,60 @@
       /// \brief A CXXBoolLiteralExpr record.
       EXPR_CXX_BOOL_LITERAL,
 
-      EXPR_CXX_NULL_PTR_LITERAL,  // CXXNullPtrLiteralExpr
-      EXPR_CXX_TYPEID_EXPR,       // CXXTypeidExpr (of expr).
-      EXPR_CXX_TYPEID_TYPE,       // CXXTypeidExpr (of type).
-      EXPR_CXX_THIS,              // CXXThisExpr
-      EXPR_CXX_THROW,             // CXXThrowExpr
-      EXPR_CXX_DEFAULT_ARG,       // CXXDefaultArgExpr
-      EXPR_CXX_DEFAULT_INIT,      // CXXDefaultInitExpr
-      EXPR_CXX_BIND_TEMPORARY,    // CXXBindTemporaryExpr
+      EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
+      EXPR_CXX_TYPEID_EXPR,      // CXXTypeidExpr (of expr).
+      EXPR_CXX_TYPEID_TYPE,      // CXXTypeidExpr (of type).
+      EXPR_CXX_THIS,             // CXXThisExpr
+      EXPR_CXX_THROW,            // CXXThrowExpr
+      EXPR_CXX_DEFAULT_ARG,      // CXXDefaultArgExpr
+      EXPR_CXX_DEFAULT_INIT,     // CXXDefaultInitExpr
+      EXPR_CXX_BIND_TEMPORARY,   // CXXBindTemporaryExpr
 
       EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr
       EXPR_CXX_NEW,               // CXXNewExpr
       EXPR_CXX_DELETE,            // CXXDeleteExpr
       EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr
-      
-      EXPR_EXPR_WITH_CLEANUPS,    // ExprWithCleanups
-      
+
+      EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups
+
       EXPR_CXX_DEPENDENT_SCOPE_MEMBER,   // CXXDependentScopeMemberExpr
       EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr
       EXPR_CXX_UNRESOLVED_CONSTRUCT,     // CXXUnresolvedConstructExpr
       EXPR_CXX_UNRESOLVED_MEMBER,        // UnresolvedMemberExpr
       EXPR_CXX_UNRESOLVED_LOOKUP,        // UnresolvedLookupExpr
 
-      EXPR_CXX_EXPRESSION_TRAIT,  // ExpressionTraitExpr
-      EXPR_CXX_NOEXCEPT,          // CXXNoexceptExpr
+      EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr
+      EXPR_CXX_NOEXCEPT,         // CXXNoexceptExpr
 
-      EXPR_OPAQUE_VALUE,          // OpaqueValueExpr
-      EXPR_BINARY_CONDITIONAL_OPERATOR,  // BinaryConditionalOperator
-      EXPR_TYPE_TRAIT,            // TypeTraitExpr
-      EXPR_ARRAY_TYPE_TRAIT,      // ArrayTypeTraitIntExpr
-      
-      EXPR_PACK_EXPANSION,        // PackExpansionExpr
-      EXPR_SIZEOF_PACK,           // SizeOfPackExpr
-      EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr
-      EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
-      EXPR_FUNCTION_PARM_PACK,    // FunctionParmPackExpr
-      EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
-      EXPR_CXX_FOLD,              // CXXFoldExpr
+      EXPR_OPAQUE_VALUE,                // OpaqueValueExpr
+      EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator
+      EXPR_TYPE_TRAIT,                  // TypeTraitExpr
+      EXPR_ARRAY_TYPE_TRAIT,            // ArrayTypeTraitIntExpr
+
+      EXPR_PACK_EXPANSION,                    // PackExpansionExpr
+      EXPR_SIZEOF_PACK,                       // SizeOfPackExpr
+      EXPR_SUBST_NON_TYPE_TEMPLATE_PARM,      // SubstNonTypeTemplateParmExpr
+      EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr
+      EXPR_FUNCTION_PARM_PACK,                // FunctionParmPackExpr
+      EXPR_MATERIALIZE_TEMPORARY,             // MaterializeTemporaryExpr
+      EXPR_CXX_FOLD,                          // CXXFoldExpr
+      EXPR_CXX_REWRITTEN_OPERATOR,            // CXXRewrittenExpr
 
       // CUDA
-      EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr      
+      EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
 
       // OpenCL
-      EXPR_ASTYPE,                 // AsTypeExpr
+      EXPR_ASTYPE, // AsTypeExpr
 
       // Microsoft
-      EXPR_CXX_PROPERTY_REF_EXPR, // MSPropertyRefExpr
+      EXPR_CXX_PROPERTY_REF_EXPR,       // MSPropertyRefExpr
       EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR, // MSPropertySubscriptExpr
-      EXPR_CXX_UUIDOF_EXPR,       // CXXUuidofExpr (of expr).
-      EXPR_CXX_UUIDOF_TYPE,       // CXXUuidofExpr (of type).
-      STMT_SEH_LEAVE,             // SEHLeaveStmt
-      STMT_SEH_EXCEPT,            // SEHExceptStmt
-      STMT_SEH_FINALLY,           // SEHFinallyStmt
-      STMT_SEH_TRY,               // SEHTryStmt
+      EXPR_CXX_UUIDOF_EXPR,             // CXXUuidofExpr (of expr).
+      EXPR_CXX_UUIDOF_TYPE,             // CXXUuidofExpr (of type).
+      STMT_SEH_LEAVE,                   // SEHLeaveStmt
+      STMT_SEH_EXCEPT,                  // SEHExceptStmt
+      STMT_SEH_FINALLY,                 // SEHFinallyStmt
+      STMT_SEH_TRY,                     // SEHTryStmt
 
       // OpenMP directives
       STMT_OMP_PARALLEL_DIRECTIVE,
@@ -1879,10 +1880,10 @@
       EXPR_OMP_ARRAY_SECTION,
 
       // ARC
-      EXPR_OBJC_BRIDGED_CAST,     // ObjCBridgedCastExpr
+      EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
 
-      STMT_MS_DEPENDENT_EXISTS,   // MSDependentExistsStmt
-      EXPR_LAMBDA,                // LambdaExpr
+      STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt
+      EXPR_LAMBDA,              // LambdaExpr
       STMT_COROUTINE_BODY,
       STMT_CORETURN,
       EXPR_COAWAIT,
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2784,7 +2784,12 @@
                                 TemplateArgumentListInfo *ExplicitTemplateArgs,
                                             OverloadCandidateSet& CandidateSet,
                                             bool PartialOverloading = false);
-
+  void AddRewrittenOperatorCandidates(OverloadedOperatorKind Op,
+                                      SourceLocation OpLoc,
+                                      ArrayRef<Expr *> InputArgs,
+                                      const UnresolvedSetImpl &Fns,
+                                      OverloadCandidateSet &CandidateSet,
+                                      bool PerformADL);
   // Emit as a 'note' the specific overload candidate
   void NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
                              QualType DestType = QualType(),
@@ -2920,16 +2925,21 @@
                                      const UnresolvedSetImpl &Fns,
                                      Expr *input, bool RequiresADL = true);
 
-  ExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
-                                   BinaryOperatorKind Opc,
-                                   const UnresolvedSetImpl &Fns,
-                                   Expr *LHS, Expr *RHS,
-                                   bool RequiresADL = true);
+  ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc,
+                                   const UnresolvedSetImpl &Fns, Expr *LHS,
+                                   Expr *RHS, bool RequiresADL = true,
+                                   bool AllowRewrittenCandidates = true);
 
   ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
                                                 SourceLocation RLoc,
                                                 Expr *Base,Expr *Idx);
 
+  ExprResult BuildBinaryOperatorCandidate(SourceLocation OpLoc,
+                                          BinaryOperatorKind Opc,
+                                          const OverloadCandidate &Ovl,
+                                          Expr *LHS, Expr *RHS,
+                                          bool HadMultipleCandidates);
+
   ExprResult
   BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
                             SourceLocation LParenLoc,
Index: include/clang/Sema/Overload.h
===================================================================
--- include/clang/Sema/Overload.h
+++ include/clang/Sema/Overload.h
@@ -62,7 +62,7 @@
     /// Succeeded, but refers to a deleted function.
     OR_Deleted
   };
-  
+
   enum OverloadCandidateDisplayKind {
     /// Requests that all candidates be shown.  Viable candidates will
     /// be printed first.
@@ -72,6 +72,17 @@
     OCD_ViableCandidates
   };
 
+  /// OperatorOverloadCandidateKind - The kind of the operator candidate in
+  /// accordance with [over.match.oper].
+  enum RewrittenOverloadCandidateKind : unsigned char {
+    /// Not a rewritten candidate.
+    ROC_None,
+    /// Rewritten but not synthesized.
+    ROC_Rewritten,
+    /// Both rewritten and synthesized.
+    ROC_Synthesized
+  };
+
   /// ImplicitConversionKind - The kind of implicit conversion used to
   /// convert an argument to a parameter's type. The enumerator values
   /// match with the table titled 'Conversions' in [over.ics.scs] and are listed
@@ -107,7 +118,7 @@
     /// Integral conversions (C++ [conv.integral])
     ICK_Integral_Conversion,
 
-    /// Floating point conversions (C++ [conv.double] 
+    /// Floating point conversions (C++ [conv.double]
     ICK_Floating_Conversion,
 
     /// Complex conversions (C99 6.3.1.6)
@@ -252,7 +263,7 @@
     /// \brief Whether the qualification conversion involves a change in the
     /// Objective-C lifetime (for automatic reference counting).
     unsigned QualificationIncludesObjCLifetime : 1;
-    
+
     /// IncompatibleObjC - Whether this is an Objective-C conversion
     /// that we should warn about (if we actually use it).
     unsigned IncompatibleObjC : 1;
@@ -268,21 +279,21 @@
     /// \brief Whether this is an lvalue reference binding (otherwise, it's
     /// an rvalue reference binding).
     unsigned IsLvalueReference : 1;
-    
+
     /// \brief Whether we're binding to a function lvalue.
     unsigned BindsToFunctionLvalue : 1;
-    
+
     /// \brief Whether we're binding to an rvalue.
     unsigned BindsToRvalue : 1;
-    
-    /// \brief Whether this binds an implicit object argument to a 
+
+    /// \brief Whether this binds an implicit object argument to a
     /// non-static member function without a ref-qualifier.
     unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1;
-    
+
     /// \brief Whether this binds a reference to an object with a different
     /// Objective-C lifetime qualifier.
     unsigned ObjCLifetimeConversionBinding : 1;
-    
+
     /// FromType - The type that this conversion is converting
     /// from. This is an opaque pointer that can be translated into a
     /// QualType.
@@ -303,13 +314,13 @@
 
     void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
 
-    void setToType(unsigned Idx, QualType T) { 
+    void setToType(unsigned Idx, QualType T) {
       assert(Idx < 3 && "To type index is out of range");
-      ToTypePtrs[Idx] = T.getAsOpaquePtr(); 
+      ToTypePtrs[Idx] = T.getAsOpaquePtr();
     }
 
     void setAllToTypes(QualType T) {
-      ToTypePtrs[0] = T.getAsOpaquePtr(); 
+      ToTypePtrs[0] = T.getAsOpaquePtr();
       ToTypePtrs[1] = ToTypePtrs[0];
       ToTypePtrs[2] = ToTypePtrs[0];
     }
@@ -324,11 +335,11 @@
     }
 
     void setAsIdentityConversion();
-    
+
     bool isIdentityConversion() const {
       return Second == ICK_Identity && Third == ICK_Identity;
     }
-    
+
     ImplicitConversionRank getRank() const;
     NarrowingKind
     getNarrowingKind(ASTContext &Context, const Expr *Converted,
@@ -562,16 +573,16 @@
       new (this) ImplicitConversionSequence(Other);
       return *this;
     }
-    
+
     ~ImplicitConversionSequence() {
       destruct();
     }
 
     Kind getKind() const {
       assert(isInitialized() && "querying uninitialized conversion");
       return Kind(ConversionKind);
     }
-    
+
     /// \brief Return a ranking of the implicit conversion sequence
     /// kind, where smaller ranks represent better conversion
     /// sequences.
@@ -581,11 +592,11 @@
     /// per C++ [over.best.ics]p10.
     unsigned getKindRank() const {
       switch (getKind()) {
-      case StandardConversion: 
+      case StandardConversion:
         return 0;
 
       case UserDefinedConversion:
-      case AmbiguousConversion: 
+      case AmbiguousConversion:
         return 1;
 
       case EllipsisConversion:
@@ -755,21 +766,25 @@
     ConversionFixItGenerator Fix;
 
     /// Viable - True to indicate that this overload candidate is viable.
-    bool Viable;
+    bool Viable : 1;
 
     /// IsSurrogate - True to indicate that this candidate is a
     /// surrogate for a conversion to a function pointer or reference
     /// (C++ [over.call.object]).
-    bool IsSurrogate;
+    bool IsSurrogate : 1;
 
     /// IgnoreObjectArgument - True to indicate that the first
     /// argument's conversion, which for this function represents the
     /// implicit object argument, should be ignored. This will be true
     /// when the candidate is a static member function (where the
     /// implicit object argument is just a placeholder) or a
     /// non-static member function when the call doesn't have an
     /// object argument.
-    bool IgnoreObjectArgument;
+    bool IgnoreObjectArgument : 1;
+
+    /// RewrittenKind - For rewritten operator candidates, the kind of rewritten
+    /// candidate it is: rewritten or synthesized.
+    unsigned char RewrittenOpKind : 2;
 
     /// FailureKind - The reason why this candidate is not viable.
     /// Actually an OverloadFailureKind.
@@ -781,7 +796,7 @@
 
     union {
       DeductionFailureInfo DeductionFailure;
-      
+
       /// FinalConversion - For a conversion function (where Function is
       /// a CXXConversionDecl), the standard conversion that occurs
       /// after the call to the overload candidate to convert the result
@@ -812,6 +827,24 @@
       return CanFix;
     }
 
+    /// \brief Return the index of the conversion corresponding to the specified
+    /// argument index. If this is not a synthesized candidate, 'Idx' is
+    /// returned. Otherwise the index corresponding to the reversed parameter
+    /// is returned.
+    unsigned getConversionIndexForArgIndex(unsigned Idx) const;
+
+    /// \brief Return the conversion sequence for the specified argument index.
+    /// If this is a synthesized candidate, the argument index is reversed.
+    const ImplicitConversionSequence &getConversion(unsigned ArgIdx) const;
+
+    /// \brief Returns the parameter type corresponding to the specified index.
+    /// (The index is not reversed for synthesized candidates).
+    QualType getParamType(unsigned Idx) const {
+      if (Function)
+        return Function->getParamDecl(Idx)->getType();
+      return BuiltinParamTypes[Idx];
+    }
+
     unsigned getNumParams() const {
       if (IsSurrogate) {
         auto STy = Surrogate->getConversionType();
@@ -823,6 +856,10 @@
         return Function->getNumParams();
       return ExplicitCallArguments;
     }
+
+    RewrittenOverloadCandidateKind getRewrittenKind() const {
+      return static_cast<RewrittenOverloadCandidateKind>(RewrittenOpKind);
+    }
   };
 
   /// OverloadCandidateSet - A set of overload candidates, used in C++
@@ -853,8 +890,10 @@
 
   private:
     SmallVector<OverloadCandidate, 16> Candidates;
-    llvm::SmallPtrSet<Decl *, 16> Functions;
+    using DeclSet = llvm::SmallPtrSet<Decl *, 16>;
+    DeclSet Functions;
 
+  private:
     // Allocator for ConversionSequenceLists. We store the first few of these
     // inline to avoid allocation for small sets.
     llvm::BumpPtrAllocator SlabAllocator;
@@ -896,6 +935,31 @@
     void destroyCandidates();
 
   public:
+    /// \brief RewrittenCandidateContextGuard - Enter a context suitable for
+    /// adding rewritten overload candidates. Rewritten candidates can
+    /// re-consider previously seen functions, so save and clear the list of
+    /// considered functions, and restore it when the rewritten context is
+    /// exited.
+    struct RewrittenCandidateContextGuard {
+      RewrittenCandidateContextGuard(OverloadCandidateSet &CS)
+          : CandidateSet(CS) {
+        assert(CS.Kind == CSK_Operator &&
+               "rewritten expressions can only occur for operators");
+        OldFunctions = std::move(CandidateSet.Functions);
+      }
+
+      ~RewrittenCandidateContextGuard() {
+        CandidateSet.Functions.insert(OldFunctions.begin(), OldFunctions.end());
+      }
+
+    private:
+      OverloadCandidateSet &CandidateSet;
+      DeclSet OldFunctions;
+    };
+
+    friend struct RewrittenCandidateContextGuard;
+
+  public:
     OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK)
         : Loc(Loc), Kind(CSK) {}
     OverloadCandidateSet(const OverloadCandidateSet &) = delete;
@@ -952,8 +1016,9 @@
     }
 
     /// Find the best viable function on this overload set, if it exists.
-    OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
-                                         OverloadCandidateSet::iterator& Best);
+    OverloadingResult BestViableFunction(
+        Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator &Best,
+        SmallVectorImpl<OverloadCandidate *> *EquivalentCands = nullptr);
 
     void NoteCandidates(Sema &S,
                         OverloadCandidateDisplayKind OCD,
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -146,6 +146,7 @@
 def MaterializeTemporaryExpr : DStmt<Expr>;
 def LambdaExpr : DStmt<Expr>;
 def CXXFoldExpr : DStmt<Expr>;
+def CXXRewrittenExpr : DStmt<Expr>;
 
 // C++ Coroutines TS expressions
 def CoroutineSuspendExpr : DStmt<Expr, 1>;
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -246,6 +246,13 @@
     /// bit is set to true.
     unsigned IsUnique : 1;
   };
+  class CXXRewrittenExprBitfields {
+    friend class CXXRewrittenExpr;
+
+    unsigned : NumExprBits;
+
+    unsigned Kind : 1;
+  };
 
   class ObjCIndirectCopyRestoreExprBitfields {
     friend class ObjCIndirectCopyRestoreExpr;
@@ -309,6 +316,7 @@
     InitListExprBitfields InitListExprBits;
     TypeTraitExprBitfields TypeTraitExprBits;
     CoawaitExprBitfields CoawaitBits;
+    CXXRewrittenExprBitfields CXXRewrittenBits;
   };
 
 public:
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2549,6 +2549,14 @@
 DEF_TRAVERSE_STMT(CXXFoldExpr, {})
 DEF_TRAVERSE_STMT(AtomicExpr, {})
 
+DEF_TRAVERSE_STMT(CXXRewrittenExpr, {
+  TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOriginalExpr());
+  if (!getDerived().shouldVisitImplicitCode()) {
+    TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRewrittenExpr());
+  }
+  ShouldVisitChildren = false;
+})
+
 // For coroutines expressions, traverse either the operand
 // as written or the implied calls, depending on what the
 // derived class requests.
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -87,6 +87,8 @@
   SourceRange getSourceRangeImpl() const LLVM_READONLY;
 
 public:
+  friend class ASTReader;
+  friend class ASTWriter;
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
 
@@ -4207,6 +4209,71 @@
   child_range children() { return child_range(SubExprs, SubExprs + 2); }
 };
 
+class CXXRewrittenExpr : public Expr {
+
+public:
+  enum RewrittenKind { Comparison };
+
+  struct ComparisonBits {
+    /// Whether this rewritten comparison expression has reverse-order
+    /// parameters.
+    unsigned IsSynthesized : 1;
+  };
+
+  union ExtraRewrittenBits {
+    ComparisonBits CompareBits;
+  };
+
+private:
+  friend class ASTReader;
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+
+  Stmt *SubExprs[2];
+  ExtraRewrittenBits ExtraBits;
+
+  CXXRewrittenExpr(EmptyShell Empty) : Expr(CXXRewrittenExprClass, Empty) {}
+
+public:
+  CXXRewrittenExpr(RewrittenKind Kind, Expr *Original, Expr *Rewritten,
+                   ExtraRewrittenBits ExtraBits)
+      : Expr(CXXRewrittenExprClass, Rewritten->getType(),
+             Rewritten->getValueKind(), Rewritten->getObjectKind(),
+             /*Dependent*/ Rewritten->isTypeDependent(),
+             Rewritten->isValueDependent(),
+             Original->isInstantiationDependent(),
+             Rewritten->containsUnexpandedParameterPack()),
+        ExtraBits(ExtraBits) {
+    SubExprs[0] = Original;
+    SubExprs[1] = Rewritten;
+  }
+
+  RewrittenKind getRewrittenKind() const {
+    return static_cast<RewrittenKind>(CXXRewrittenBits.Kind);
+  }
+  void setRewrittenKind(RewrittenKind Kind) { CXXRewrittenBits.Kind = Kind; }
+
+  ExtraRewrittenBits *getRewrittenInfo() { return &ExtraBits; }
+  const ExtraRewrittenBits *getRewrittenInfo() const { return &ExtraBits; }
+
+  Expr *getOriginalExpr() const { return static_cast<Expr *>(SubExprs[0]); }
+  Expr *getRewrittenExpr() const {
+    return static_cast<Expr *>(SubExprs[1]);
+  }
+
+  SourceLocation getLocStart() const {
+    return getOriginalExpr()->getLocStart();
+  }
+  SourceLocation getLocEnd() const { return getOriginalExpr()->getLocEnd(); }
+  SourceLocation getExprLoc() const { return getOriginalExpr()->getExprLoc(); }
+
+  child_range children() { return child_range(SubExprs, SubExprs + 2); }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXRewrittenExprClass;
+  }
+};
+
 /// \brief Represents an expression that might suspend coroutine execution;
 /// either a co_await or co_yield expression.
 ///
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -886,6 +886,9 @@
     setIsUnique(false);
   }
 
+  /// Create an OpaqueValueExpr representing the specified source expression
+  static OpaqueValueExpr *Create(const ASTContext &Ctx, Expr *Source);
+
   /// Given an expression which invokes a copy constructor --- i.e.  a
   /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups ---
   /// find the OpaqueValueExpr that's the source of the construction.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to