<div dir="ltr"><div dir="ltr">On Mon, Jan 13, 2020 at 5:50 PM Richard Smith <<a href="mailto:richard@metafoo.co.uk" target="_blank">richard@metafoo.co.uk</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr">On Mon, 13 Jan 2020 at 15:12, Peter Collingbourne via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr">On Fri, Oct 18, 2019 at 5:02 PM Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: rsmith<br>
Date: Fri Oct 18 17:04:43 2019<br>
New Revision: 375306<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=375306&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=375306&view=rev</a><br>
Log:<br>
[c++20] Add rewriting from comparison operators to <=> / ==.<br>
<br>
This adds support for rewriting <, >, <=, and >= to a normal or reversed<br>
call to operator<=>, for rewriting != to a normal or reversed call to<br>
operator==, and for rewriting <=> and == to reversed forms of those same<br>
operators.<br>
<br>
Note that this is a breaking change for various C++17 code patterns,<br>
including some in use in LLVM. The most common patterns (where an<br>
operator== becomes ambiguous with a reversed form of itself) are still<br>
accepted under this patch, as an extension (with a warning). I'm hopeful<br>
that we can get the language rules fixed before C++20 ships, and the<br>
extension warning is aimed primarily at providing data to inform that<br>
decision.<br></blockquote><div><br></div><div>Hi Richard, it looks like this change caused us to start rejecting the following input:</div><div><br></div><div>struct S {<br>  bool operator==(int rhs) const;<br>  bool operator!=(int rhs) const;<br>  operator int() const;<br>};<br><br>void f(S a, S b) {<br>  a != b;<br>}<br></div><div><br></div><div>with:</div><div><br></div><div>$ clang -std=gnu++2a -fsyntax-only /tmp/test.cpp<br></div>/tmp/test.cpp:8:5: error: use of overloaded operator '!=' is ambiguous (with operand types 'S' and 'S')<br>  a != b;<br>  ~ ^  ~<br>/tmp/test.cpp:2:8: note: candidate function (with reversed parameter order)<br>  bool operator==(int rhs) const;<br>       ^<br>/tmp/test.cpp:3:8: note: candidate function<br>  bool operator!=(int rhs) const;<br>       ^<br>/tmp/test.cpp:2:8: note: candidate function<br>  bool operator==(int rhs) const;<br>       ^<br><div><br></div><div>It looks like this was intentional, but I wanted to make sure. The code pattern isn't very common (I see only one instance in Android), but I figured that you might want to be aware of it in case it would inform any changes to the language.</div></div></div></blockquote><div><br></div><div>Thanks. Yes, this C++20 change is known to break some (hopefully mostly rare) code patterns. I'd not seen the one above before, but I think that's moderately likely to stay broken in C++20 onwards; the ambiguity between non-reversed and reversed != seems real here (note that C++17 wouldn't have allowed 0 != a, but C++20 does, which is why this became ambiguous). I'll ask on the committee reflectors just in case.</div></div></div></blockquote><div><br></div><div>Got it, thanks for the information. </div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>Hopefully you're only seeing a build break under -std=c++2a? (If not, that'd be a problem.)</div></div></div></blockquote><div><br></div><div>Yes, I'm only seeing this under -std=c++2a.</div><div><br></div><div>Peter </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>Peter</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Added:<br>
    cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp<br>
    cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p8-2a.cpp<br>
    cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p9-2a.cpp<br>
    cfe/trunk/test/CodeGenCXX/mangle-cxx2a.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/AST/ExprCXX.h<br>
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
    cfe/trunk/include/clang/Basic/OperatorKinds.h<br>
    cfe/trunk/include/clang/Sema/Overload.h<br>
    cfe/trunk/include/clang/Sema/Sema.h<br>
    cfe/trunk/lib/AST/ExprCXX.cpp<br>
    cfe/trunk/lib/Frontend/FrontendActions.cpp<br>
    cfe/trunk/lib/Sema/SemaExpr.cpp<br>
    cfe/trunk/lib/Sema/SemaOverload.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplate.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp<br>
    cfe/trunk/lib/Sema/TreeTransform.h<br>
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp<br>
    cfe/trunk/test/PCH/cxx2a-compare.cpp<br>
    cfe/trunk/test/SemaCXX/compare-cxx2a.cpp<br>
    cfe/trunk/test/SemaCXX/self-comparison.cpp<br>
    cfe/trunk/www/cxx_status.html<br>
<br>
Modified: cfe/trunk/include/clang/AST/ExprCXX.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)<br>
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Oct 18 17:04:43 2019<br>
@@ -220,6 +220,40 @@ public:<br>
   }<br>
 };<br>
<br>
+/// Represents a call to a CUDA kernel function.<br>
+class CUDAKernelCallExpr final : public CallExpr {<br>
+  friend class ASTStmtReader;<br>
+<br>
+  enum { CONFIG, END_PREARG };<br>
+<br>
+  // CUDAKernelCallExpr has some trailing objects belonging<br>
+  // to CallExpr. See CallExpr for the details.<br>
+<br>
+  CUDAKernelCallExpr(Expr *Fn, CallExpr *Config, ArrayRef<Expr *> Args,<br>
+                     QualType Ty, ExprValueKind VK, SourceLocation RP,<br>
+                     unsigned MinNumArgs);<br>
+<br>
+  CUDAKernelCallExpr(unsigned NumArgs, EmptyShell Empty);<br>
+<br>
+public:<br>
+  static CUDAKernelCallExpr *Create(const ASTContext &Ctx, Expr *Fn,<br>
+                                    CallExpr *Config, ArrayRef<Expr *> Args,<br>
+                                    QualType Ty, ExprValueKind VK,<br>
+                                    SourceLocation RP, unsigned MinNumArgs = 0);<br>
+<br>
+  static CUDAKernelCallExpr *CreateEmpty(const ASTContext &Ctx,<br>
+                                         unsigned NumArgs, EmptyShell Empty);<br>
+<br>
+  const CallExpr *getConfig() const {<br>
+    return cast_or_null<CallExpr>(getPreArg(CONFIG));<br>
+  }<br>
+  CallExpr *getConfig() { return cast_or_null<CallExpr>(getPreArg(CONFIG)); }<br>
+<br>
+  static bool classof(const Stmt *T) {<br>
+    return T->getStmtClass() == CUDAKernelCallExprClass;<br>
+  }<br>
+};<br>
+<br>
 /// A rewritten comparison expression that was originally written using<br>
 /// operator syntax.<br>
 ///<br>
@@ -310,40 +344,6 @@ public:<br>
   }<br>
 };<br>
<br>
-/// Represents a call to a CUDA kernel function.<br>
-class CUDAKernelCallExpr final : public CallExpr {<br>
-  friend class ASTStmtReader;<br>
-<br>
-  enum { CONFIG, END_PREARG };<br>
-<br>
-  // CUDAKernelCallExpr has some trailing objects belonging<br>
-  // to CallExpr. See CallExpr for the details.<br>
-<br>
-  CUDAKernelCallExpr(Expr *Fn, CallExpr *Config, ArrayRef<Expr *> Args,<br>
-                     QualType Ty, ExprValueKind VK, SourceLocation RP,<br>
-                     unsigned MinNumArgs);<br>
-<br>
-  CUDAKernelCallExpr(unsigned NumArgs, EmptyShell Empty);<br>
-<br>
-public:<br>
-  static CUDAKernelCallExpr *Create(const ASTContext &Ctx, Expr *Fn,<br>
-                                    CallExpr *Config, ArrayRef<Expr *> Args,<br>
-                                    QualType Ty, ExprValueKind VK,<br>
-                                    SourceLocation RP, unsigned MinNumArgs = 0);<br>
-<br>
-  static CUDAKernelCallExpr *CreateEmpty(const ASTContext &Ctx,<br>
-                                         unsigned NumArgs, EmptyShell Empty);<br>
-<br>
-  const CallExpr *getConfig() const {<br>
-    return cast_or_null<CallExpr>(getPreArg(CONFIG));<br>
-  }<br>
-  CallExpr *getConfig() { return cast_or_null<CallExpr>(getPreArg(CONFIG)); }<br>
-<br>
-  static bool classof(const Stmt *T) {<br>
-    return T->getStmtClass() == CUDAKernelCallExprClass;<br>
-  }<br>
-};<br>
-<br>
 /// Abstract class common to all of the C++ "named"/"keyword" casts.<br>
 ///<br>
 /// This abstract class is inherited by all of the classes<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Oct 18 17:04:43 2019<br>
@@ -3769,7 +3769,8 @@ def note_ovl_too_many_candidates : Note<<br>
     "pass -fshow-overloads=all to show them">;<br>
<br>
 def select_ovl_candidate_kind : TextSubstitution<<br>
-  "%select{function|function|constructor|"<br>
+  "%select{function|function|function (with reversed parameter order)|"<br>
+    "constructor|"<br>
     "constructor (the implicit default constructor)|"<br>
     "constructor (the implicit copy constructor)|"<br>
     "constructor (the implicit move constructor)|"<br>
@@ -3990,6 +3991,13 @@ def err_ovl_ambiguous_oper_unary : Error<br>
   "use of overloaded operator '%0' is ambiguous (operand type %1)">;<br>
 def err_ovl_ambiguous_oper_binary : Error<<br>
   "use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">;<br>
+def ext_ovl_ambiguous_oper_binary_reversed : ExtWarn<<br>
+  "ISO C++20 considers use of overloaded operator '%0' (with operand types %1 "<br>
+  "and %2) to be ambiguous despite there being a unique best viable function">,<br>
+  InGroup<DiagGroup<"ambiguous-reversed-operator">>, SFINAEFailure;<br>
+def note_ovl_ambiguous_oper_binary_reversed_candidate : Note<<br>
+  "ambiguity is between a regular call to this operator and a call with the "<br>
+  "argument order reversed">;<br>
 def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;<br>
 def note_assign_lhs_incomplete : Note<"type %0 is incomplete">;<br>
 def err_ovl_deleted_oper : Error<<br>
@@ -3997,6 +4005,9 @@ def err_ovl_deleted_oper : Error<<br>
 def err_ovl_deleted_special_oper : Error<<br>
   "object of type %0 cannot be %select{constructed|copied|moved|assigned|"<br>
   "assigned|destroyed}1 because its %sub{select_special_member_kind}1 is implicitly deleted">;<br>
+def err_ovl_rewrite_equalequal_not_bool : Error<<br>
+  "return type %0 of selected 'operator==' function for rewritten "<br>
+  "'%1' comparison is not 'bool'">;<br>
 def err_ovl_no_viable_subscript :<br>
     Error<"no viable overloaded operator[] for type %0">;<br>
 def err_ovl_no_oper :<br>
@@ -9961,6 +9972,8 @@ def err_std_compare_type_not_supported :<br>
    "member '%2' is missing|"<br>
    "the type is not trivially copyable|"<br>
    "the type does not have the expected form}1">;<br>
+def note_rewriting_operator_as_spaceship : Note<<br>
+  "while rewriting comparison as call to 'operator<=>' declared here">;<br>
<br>
 // Memory Tagging Extensions (MTE) diagnostics<br>
 def err_memtag_arg_null_or_pointer : Error<<br>
<br>
Modified: cfe/trunk/include/clang/Basic/OperatorKinds.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OperatorKinds.h?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OperatorKinds.h?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/OperatorKinds.h (original)<br>
+++ cfe/trunk/include/clang/Basic/OperatorKinds.h Fri Oct 18 17:04:43 2019<br>
@@ -30,6 +30,25 @@ enum OverloadedOperatorKind : int {<br>
 /// the preceding "operator" keyword.<br>
 const char *getOperatorSpelling(OverloadedOperatorKind Operator);<br>
<br>
+/// Get the other overloaded operator that the given operator can be rewritten<br>
+/// into, if any such operator exists.<br>
+inline OverloadedOperatorKind<br>
+getRewrittenOverloadedOperator(OverloadedOperatorKind Kind) {<br>
+  switch (Kind) {<br>
+  case OO_Less:<br>
+  case OO_LessEqual:<br>
+  case OO_Greater:<br>
+  case OO_GreaterEqual:<br>
+    return OO_Spaceship;<br>
+<br>
+  case OO_ExclaimEqual:<br>
+    return OO_EqualEqual;<br>
+<br>
+  default:<br>
+    return OO_None;<br>
+  }<br>
+}<br>
+<br>
 } // end namespace clang<br>
<br>
 #endif<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Overload.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Overload.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Overload.h Fri Oct 18 17:04:43 2019<br>
@@ -71,6 +71,30 @@ class Sema;<br>
     OCD_ViableCandidates<br>
   };<br>
<br>
+  /// The parameter ordering that will be used for the candidate. This is<br>
+  /// used to represent C++20 binary operator rewrites that reverse the order<br>
+  /// of the arguments. If the parameter ordering is Reversed, the Args list is<br>
+  /// reversed (but obviously the ParamDecls for the function are not).<br>
+  ///<br>
+  /// After forming an OverloadCandidate with reversed parameters, the list<br>
+  /// of conversions will (as always) be indexed by argument, so will be<br>
+  /// in reverse parameter order.<br>
+  enum class OverloadCandidateParamOrder : char { Normal, Reversed };<br>
+<br>
+  /// The kinds of rewrite we perform on overload candidates. Note that the<br>
+  /// values here are chosen to serve as both bitflags and as a rank (lower<br>
+  /// values are preferred by overload resolution).<br>
+  enum OverloadCandidateRewriteKind : unsigned {<br>
+    /// Candidate is not a rewritten candidate.<br>
+    CRK_None = 0x0,<br>
+<br>
+    /// Candidate is a rewritten candidate with a different operator name.<br>
+    CRK_DifferentOperator = 0x1,<br>
+<br>
+    /// Candidate is a rewritten candidate with a reversed order of parameters.<br>
+    CRK_Reversed = 0x2,<br>
+  };<br>
+<br>
   /// ImplicitConversionKind - The kind of implicit conversion used to<br>
   /// convert an argument to a parameter's type. The enumerator values<br>
   /// match with the table titled 'Conversions' in [over.ics.scs] and are listed<br>
@@ -757,7 +781,8 @@ class Sema;<br>
     CXXConversionDecl *Surrogate;<br>
<br>
     /// The conversion sequences used to convert the function arguments<br>
-    /// to the function parameters.<br>
+    /// to the function parameters. Note that these are indexed by argument,<br>
+    /// so may not match the parameter order of Function.<br>
     ConversionSequenceList Conversions;<br>
<br>
     /// The FixIt hints which can be used to fix the Bad candidate.<br>
@@ -783,6 +808,9 @@ class Sema;<br>
     /// True if the candidate was found using ADL.<br>
     CallExpr::ADLCallKind IsADLCandidate : 1;<br>
<br>
+    /// Whether this is a rewritten candidate, and if so, of what kind?<br>
+    OverloadCandidateRewriteKind RewriteKind : 2;<br>
+<br>
     /// FailureKind - The reason why this candidate is not viable.<br>
     /// Actually an OverloadFailureKind.<br>
     unsigned char FailureKind;<br>
@@ -838,7 +866,8 @@ class Sema;<br>
<br>
   private:<br>
     friend class OverloadCandidateSet;<br>
-    OverloadCandidate() : IsADLCandidate(CallExpr::NotADL) {}<br>
+    OverloadCandidate()<br>
+        : IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {}<br>
   };<br>
<br>
   /// OverloadCandidateSet - A set of overload candidates, used in C++<br>
@@ -867,9 +896,54 @@ class Sema;<br>
       CSK_InitByConstructor,<br>
     };<br>
<br>
+    /// Information about operator rewrites to consider when adding operator<br>
+    /// functions to a candidate set.<br>
+    struct OperatorRewriteInfo {<br>
+      OperatorRewriteInfo()<br>
+          : OriginalOperator(OO_None), AllowRewrittenCandidates(false) {}<br>
+      OperatorRewriteInfo(OverloadedOperatorKind Op, bool AllowRewritten)<br>
+          : OriginalOperator(Op), AllowRewrittenCandidates(AllowRewritten) {}<br>
+<br>
+      /// The original operator as written in the source.<br>
+      OverloadedOperatorKind OriginalOperator;<br>
+      /// Whether we should include rewritten candidates in the overload set.<br>
+      bool AllowRewrittenCandidates;<br>
+<br>
+      /// Would use of this function result in a rewrite using a different<br>
+      /// operator?<br>
+      bool isRewrittenOperator(const FunctionDecl *FD) {<br>
+        return OriginalOperator &&<br>
+               FD->getDeclName().getCXXOverloadedOperator() != OriginalOperator;<br>
+      }<br>
+<br>
+      bool isAcceptableCandidate(const FunctionDecl *FD) {<br>
+        return AllowRewrittenCandidates || !isRewrittenOperator(FD);<br>
+      }<br>
+<br>
+      /// Determine the kind of rewrite that should be performed for this<br>
+      /// candidate.<br>
+      OverloadCandidateRewriteKind<br>
+      getRewriteKind(const FunctionDecl *FD, OverloadCandidateParamOrder PO) {<br>
+        OverloadCandidateRewriteKind CRK = CRK_None;<br>
+        if (isRewrittenOperator(FD))<br>
+          CRK = OverloadCandidateRewriteKind(CRK | CRK_DifferentOperator);<br>
+        if (PO == OverloadCandidateParamOrder::Reversed)<br>
+          CRK = OverloadCandidateRewriteKind(CRK | CRK_Reversed);<br>
+        return CRK;<br>
+      }<br>
+<br>
+      /// Determine whether we should consider looking for and adding reversed<br>
+      /// candidates for operator Op.<br>
+      bool shouldAddReversed(OverloadedOperatorKind Op);<br>
+<br>
+      /// Determine whether we should add a rewritten candidate for \p FD with<br>
+      /// reversed parameter order.<br>
+      bool shouldAddReversed(ASTContext &Ctx, const FunctionDecl *FD);<br>
+    };<br>
+<br>
   private:<br>
     SmallVector<OverloadCandidate, 16> Candidates;<br>
-    llvm::SmallPtrSet<Decl *, 16> Functions;<br>
+    llvm::SmallPtrSet<uintptr_t, 16> Functions;<br>
<br>
     // Allocator for ConversionSequenceLists. We store the first few of these<br>
     // inline to avoid allocation for small sets.<br>
@@ -877,6 +951,7 @@ class Sema;<br>
<br>
     SourceLocation Loc;<br>
     CandidateSetKind Kind;<br>
+    OperatorRewriteInfo RewriteInfo;<br>
<br>
     constexpr static unsigned NumInlineBytes =<br>
         24 * sizeof(ImplicitConversionSequence);<br>
@@ -915,19 +990,24 @@ class Sema;<br>
     void destroyCandidates();<br>
<br>
   public:<br>
-    OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK)<br>
-        : Loc(Loc), Kind(CSK) {}<br>
+    OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK,<br>
+                         OperatorRewriteInfo RewriteInfo = {})<br>
+        : Loc(Loc), Kind(CSK), RewriteInfo(RewriteInfo) {}<br>
     OverloadCandidateSet(const OverloadCandidateSet &) = delete;<br>
     OverloadCandidateSet &operator=(const OverloadCandidateSet &) = delete;<br>
     ~OverloadCandidateSet() { destroyCandidates(); }<br>
<br>
     SourceLocation getLocation() const { return Loc; }<br>
     CandidateSetKind getKind() const { return Kind; }<br>
+    OperatorRewriteInfo getRewriteInfo() const { return RewriteInfo; }<br>
<br>
     /// Determine when this overload candidate will be new to the<br>
     /// overload set.<br>
-    bool isNewCandidate(Decl *F) {<br>
-      return Functions.insert(F->getCanonicalDecl()).second;<br>
+    bool isNewCandidate(Decl *F, OverloadCandidateParamOrder PO =<br>
+                                     OverloadCandidateParamOrder::Normal) {<br>
+      uintptr_t Key = reinterpret_cast<uintptr_t>(F->getCanonicalDecl());<br>
+      Key |= static_cast<uintptr_t>(PO);<br>
+      return Functions.insert(Key).second;<br>
     }<br>
<br>
     /// Clear out all of the candidates.<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Oct 18 17:04:43 2019<br>
@@ -159,6 +159,8 @@ namespace clang {<br>
   class OMPClause;<br>
   struct OMPVarListLocTy;<br>
   struct OverloadCandidate;<br>
+  enum class OverloadCandidateParamOrder : char;<br>
+  enum OverloadCandidateRewriteKind : unsigned;<br>
   class OverloadCandidateSet;<br>
   class OverloadExpr;<br>
   class ParenListExpr;<br>
@@ -3019,7 +3021,8 @@ public:<br>
                             bool AllowExplicit = true,<br>
                             bool AllowExplicitConversion = false,<br>
                             ADLCallKind IsADLCandidate = ADLCallKind::NotADL,<br>
-                            ConversionSequenceList EarlyConversions = None);<br>
+                            ConversionSequenceList EarlyConversions = None,<br>
+                            OverloadCandidateParamOrder PO = {});<br>
   void AddFunctionCandidates(const UnresolvedSetImpl &Functions,<br>
                       ArrayRef<Expr *> Args,<br>
                       OverloadCandidateSet &CandidateSet,<br>
@@ -3032,7 +3035,8 @@ public:<br>
                           Expr::Classification ObjectClassification,<br>
                           ArrayRef<Expr *> Args,<br>
                           OverloadCandidateSet& CandidateSet,<br>
-                          bool SuppressUserConversion = false);<br>
+                          bool SuppressUserConversion = false,<br>
+                          OverloadCandidateParamOrder PO = {});<br>
   void AddMethodCandidate(CXXMethodDecl *Method,<br>
                           DeclAccessPair FoundDecl,<br>
                           CXXRecordDecl *ActingContext, QualType ObjectType,<br>
@@ -3041,7 +3045,8 @@ public:<br>
                           OverloadCandidateSet& CandidateSet,<br>
                           bool SuppressUserConversions = false,<br>
                           bool PartialOverloading = false,<br>
-                          ConversionSequenceList EarlyConversions = None);<br>
+                          ConversionSequenceList EarlyConversions = None,<br>
+                          OverloadCandidateParamOrder PO = {});<br>
   void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,<br>
                                   DeclAccessPair FoundDecl,<br>
                                   CXXRecordDecl *ActingContext,<br>
@@ -3051,23 +3056,22 @@ public:<br>
                                   ArrayRef<Expr *> Args,<br>
                                   OverloadCandidateSet& CandidateSet,<br>
                                   bool SuppressUserConversions = false,<br>
-                                  bool PartialOverloading = false);<br>
+                                  bool PartialOverloading = false,<br>
+                                  OverloadCandidateParamOrder PO = {});<br>
   void AddTemplateOverloadCandidate(<br>
       FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,<br>
       TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,<br>
       OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,<br>
       bool PartialOverloading = false, bool AllowExplicit = true,<br>
-      ADLCallKind IsADLCandidate = ADLCallKind::NotADL);<br>
-  bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,<br>
-                                    ArrayRef<QualType> ParamTypes,<br>
-                                    ArrayRef<Expr *> Args,<br>
-                                    OverloadCandidateSet &CandidateSet,<br>
-                                    ConversionSequenceList &Conversions,<br>
-                                    bool SuppressUserConversions,<br>
-                                    CXXRecordDecl *ActingContext = nullptr,<br>
-                                    QualType ObjectType = QualType(),<br>
-                                    Expr::Classification<br>
-                                        ObjectClassification = {});<br>
+      ADLCallKind IsADLCandidate = ADLCallKind::NotADL,<br>
+      OverloadCandidateParamOrder PO = {});<br>
+  bool CheckNonDependentConversions(<br>
+      FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes,<br>
+      ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet,<br>
+      ConversionSequenceList &Conversions, bool SuppressUserConversions,<br>
+      CXXRecordDecl *ActingContext = nullptr, QualType ObjectType = QualType(),<br>
+      Expr::Classification ObjectClassification = {},<br>
+      OverloadCandidateParamOrder PO = {});<br>
   void AddConversionCandidate(<br>
       CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,<br>
       CXXRecordDecl *ActingContext, Expr *From, QualType ToType,<br>
@@ -3084,10 +3088,14 @@ public:<br>
                              const FunctionProtoType *Proto,<br>
                              Expr *Object, ArrayRef<Expr *> Args,<br>
                              OverloadCandidateSet& CandidateSet);<br>
+  void AddNonMemberOperatorCandidates(<br>
+      const UnresolvedSetImpl &Functions, ArrayRef<Expr *> Args,<br>
+      OverloadCandidateSet &CandidateSet,<br>
+      TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr);<br>
   void AddMemberOperatorCandidates(OverloadedOperatorKind Op,<br>
                                    SourceLocation OpLoc, ArrayRef<Expr *> Args,<br>
-                                   OverloadCandidateSet& CandidateSet,<br>
-                                   SourceRange OpRange = SourceRange());<br>
+                                   OverloadCandidateSet &CandidateSet,<br>
+                                   OverloadCandidateParamOrder PO = {});<br>
   void AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args,<br>
                            OverloadCandidateSet& CandidateSet,<br>
                            bool IsAssignmentOperator = false,<br>
@@ -3103,9 +3111,10 @@ public:<br>
                                             bool PartialOverloading = false);<br>
<br>
   // Emit as a 'note' the specific overload candidate<br>
-  void NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,<br>
-                             QualType DestType = QualType(),<br>
-                             bool TakingAddress = false);<br>
+  void NoteOverloadCandidate(<br>
+      NamedDecl *Found, FunctionDecl *Fn,<br>
+      OverloadCandidateRewriteKind RewriteKind = OverloadCandidateRewriteKind(),<br>
+      QualType DestType = QualType(), bool TakingAddress = false);<br>
<br>
   // Emit as a series of 'note's all template and non-templates identified by<br>
   // the expression Expr<br>
@@ -3237,7 +3246,8 @@ public:<br>
                                    BinaryOperatorKind Opc,<br>
                                    const UnresolvedSetImpl &Fns,<br>
                                    Expr *LHS, Expr *RHS,<br>
-                                   bool RequiresADL = true);<br>
+                                   bool RequiresADL = true,<br>
+                                   bool AllowRewrittenCandidates = true);<br>
<br>
   ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,<br>
                                                 SourceLocation RLoc,<br>
@@ -7665,6 +7675,9 @@ public:<br>
       // We are substituting template arguments into a constraint expression.<br>
       ConstraintSubstitution,<br>
<br>
+      /// We are rewriting a comparison operator in terms of an operator<=>.<br>
+      RewritingOperatorAsSpaceship,<br>
+<br>
       /// Added for Template instantiation observation.<br>
       /// Memoization means we are _not_ instantiating a template because<br>
       /// it is already instantiated (but we entered a context where we<br>
<br>
Modified: cfe/trunk/lib/AST/ExprCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)<br>
+++ cfe/trunk/lib/AST/ExprCXX.cpp Fri Oct 18 17:04:43 2019<br>
@@ -79,7 +79,7 @@ CXXRewrittenBinaryOperator::getDecompose<br>
     Result.RHS = BO->getRHS();<br>
     Result.InnerBinOp = BO;<br>
   } else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) {<br>
-    assert(!SkippedNot || BO->getOperator() == OO_Equal);<br>
+    assert(!SkippedNot || BO->getOperator() == OO_EqualEqual);<br>
     assert(BO->isInfixBinaryOp());<br>
     switch (BO->getOperator()) {<br>
     case OO_Less: Result.Opcode = BO_LT; break;<br>
@@ -107,7 +107,7 @@ CXXRewrittenBinaryOperator::getDecompose<br>
     return Result;<br>
<br>
   // Otherwise, we expect a <=> to now be on the LHS.<br>
-  E = Result.InnerBinOp->IgnoreImplicit();<br>
+  E = Result.LHS->IgnoreImplicit();<br>
   if (auto *BO = dyn_cast<BinaryOperator>(E)) {<br>
     assert(BO->getOpcode() == BO_Cmp);<br>
     Result.LHS = BO->getLHS();<br>
<br>
Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)<br>
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Fri Oct 18 17:04:43 2019<br>
@@ -415,6 +415,8 @@ private:<br>
       return "DeclaringSpecialMember";<br>
     case CodeSynthesisContext::DefiningSynthesizedFunction:<br>
       return "DefiningSynthesizedFunction";<br>
+    case CodeSynthesisContext::RewritingOperatorAsSpaceship:<br>
+      return "RewritingOperatorAsSpaceship";<br>
     case CodeSynthesisContext::Memoization:<br>
       return "Memoization";<br>
     case CodeSynthesisContext::ConstraintsCheck:<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Oct 18 17:04:43 2019<br>
@@ -13310,6 +13310,13 @@ static ExprResult BuildOverloadedBinOp(S<br>
     S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),<br>
                                    RHS->getType(), Functions);<br>
<br>
+  // In C++20 onwards, we may have a second operator to look up.<br>
+  if (S.getLangOpts().CPlusPlus2a) {<br>
+    if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp))<br>
+      S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(),<br>
+                                     RHS->getType(), Functions);<br>
+  }<br>
+<br>
   // Build the (potentially-overloaded, potentially-dependent)<br>
   // binary operation.<br>
   return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS);<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Oct 18 17:04:43 2019<br>
@@ -848,6 +848,25 @@ llvm::Optional<unsigned> DeductionFailur<br>
   }<br>
 }<br>
<br>
+bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(<br>
+    OverloadedOperatorKind Op) {<br>
+  if (!AllowRewrittenCandidates)<br>
+    return false;<br>
+  return Op == OO_EqualEqual || Op == OO_Spaceship;<br>
+}<br>
+<br>
+bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(<br>
+    ASTContext &Ctx, const FunctionDecl *FD) {<br>
+  if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator()))<br>
+    return false;<br>
+  // Don't bother adding a reversed candidate that can never be a better<br>
+  // match than the non-reversed version.<br>
+  return FD->getNumParams() != 2 ||<br>
+         !Ctx.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),<br>
+                                     FD->getParamDecl(1)->getType()) ||<br>
+         FD->hasAttr<EnableIfAttr>();<br>
+}<br>
+<br>
 void OverloadCandidateSet::destroyCandidates() {<br>
   for (iterator i = begin(), e = end(); i != e; ++i) {<br>
     for (auto &C : i->Conversions)<br>
@@ -6056,7 +6075,8 @@ void Sema::AddOverloadCandidate(<br>
     FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,<br>
     OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,<br>
     bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,<br>
-    ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions) {<br>
+    ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,<br>
+    OverloadCandidateParamOrder PO) {<br>
   const FunctionProtoType *Proto<br>
     = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());<br>
   assert(Proto && "Functions without a prototype cannot be overloaded");<br>
@@ -6075,25 +6095,14 @@ void Sema::AddOverloadCandidate(<br>
       AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),<br>
                          Expr::Classification::makeSimpleLValue(), Args,<br>
                          CandidateSet, SuppressUserConversions,<br>
-                         PartialOverloading, EarlyConversions);<br>
+                         PartialOverloading, EarlyConversions, PO);<br>
       return;<br>
     }<br>
     // We treat a constructor like a non-member function, since its object<br>
     // argument doesn't participate in overload resolution.<br>
   }<br>
<br>
-  if (!CandidateSet.isNewCandidate(Function))<br>
-    return;<br>
-<br>
-  // C++ [over.match.oper]p3:<br>
-  //   if no operand has a class type, only those non-member functions in the<br>
-  //   lookup set that have a first parameter of type T1 or "reference to<br>
-  //   (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there<br>
-  //   is a right operand) a second parameter of type T2 or "reference to<br>
-  //   (possibly cv-qualified) T2", when T2 is an enumeration type, are<br>
-  //   candidate functions.<br>
-  if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&<br>
-      !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))<br>
+  if (!CandidateSet.isNewCandidate(Function, PO))<br>
     return;<br>
<br>
   // C++11 [class.copy]p11: [DR1402]<br>
@@ -6108,12 +6117,25 @@ void Sema::AddOverloadCandidate(<br>
   EnterExpressionEvaluationContext Unevaluated(<br>
       *this, Sema::ExpressionEvaluationContext::Unevaluated);<br>
<br>
+  // C++ [over.match.oper]p3:<br>
+  //   if no operand has a class type, only those non-member functions in the<br>
+  //   lookup set that have a first parameter of type T1 or "reference to<br>
+  //   (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there<br>
+  //   is a right operand) a second parameter of type T2 or "reference to<br>
+  //   (possibly cv-qualified) T2", when T2 is an enumeration type, are<br>
+  //   candidate functions.<br>
+  if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&<br>
+      !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))<br>
+    return;<br>
+<br>
   // Add this candidate<br>
   OverloadCandidate &Candidate =<br>
       CandidateSet.addCandidate(Args.size(), EarlyConversions);<br>
   Candidate.FoundDecl = FoundDecl;<br>
   Candidate.Function = Function;<br>
   Candidate.Viable = true;<br>
+  Candidate.RewriteKind =<br>
+      CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);<br>
   Candidate.IsSurrogate = false;<br>
   Candidate.IsADLCandidate = IsADLCandidate;<br>
   Candidate.IgnoreObjectArgument = false;<br>
@@ -6213,7 +6235,9 @@ void Sema::AddOverloadCandidate(<br>
   // Determine the implicit conversion sequences for each of the<br>
   // arguments.<br>
   for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {<br>
-    if (Candidate.Conversions[ArgIdx].isInitialized()) {<br>
+    unsigned ConvIdx =<br>
+        PO == OverloadCandidateParamOrder::Reversed ? 1 - ArgIdx : ArgIdx;<br>
+    if (Candidate.Conversions[ConvIdx].isInitialized()) {<br>
       // We already formed a conversion sequence for this parameter during<br>
       // template argument deduction.<br>
     } else if (ArgIdx < NumParams) {<br>
@@ -6222,12 +6246,12 @@ void Sema::AddOverloadCandidate(<br>
       // (13.3.3.1) that converts that argument to the corresponding<br>
       // parameter of F.<br>
       QualType ParamType = Proto->getParamType(ArgIdx);<br>
-      Candidate.Conversions[ArgIdx] = TryCopyInitialization(<br>
+      Candidate.Conversions[ConvIdx] = TryCopyInitialization(<br>
           *this, Args[ArgIdx], ParamType, SuppressUserConversions,<br>
           /*InOverloadResolution=*/true,<br>
           /*AllowObjCWritebackConversion=*/<br>
           getLangOpts().ObjCAutoRefCount, AllowExplicitConversions);<br>
-      if (Candidate.Conversions[ArgIdx].isBad()) {<br>
+      if (Candidate.Conversions[ConvIdx].isBad()) {<br>
         Candidate.Viable = false;<br>
         Candidate.FailureKind = ovl_fail_bad_conversion;<br>
         return;<br>
@@ -6236,7 +6260,7 @@ void Sema::AddOverloadCandidate(<br>
       // (C++ 13.3.2p2): For the purposes of overload resolution, any<br>
       // argument for which there is no corresponding parameter is<br>
       // considered to ""match the ellipsis" (C+ 13.3.3.1.3).<br>
-      Candidate.Conversions[ArgIdx].setEllipsis();<br>
+      Candidate.Conversions[ConvIdx].setEllipsis();<br>
     }<br>
   }<br>
<br>
@@ -6583,9 +6607,10 @@ void Sema::AddFunctionCandidates(const U<br>
         FunctionArgs = Args.slice(1);<br>
       }<br>
       if (FunTmpl) {<br>
-        AddTemplateOverloadCandidate(<br>
-            FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs,<br>
-            CandidateSet, SuppressUserConversions, PartialOverloading);<br>
+        AddTemplateOverloadCandidate(FunTmpl, F.getPair(),<br>
+                                     ExplicitTemplateArgs, FunctionArgs,<br>
+                                     CandidateSet, SuppressUserConversions,<br>
+                                     PartialOverloading);<br>
       } else {<br>
         AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet,<br>
                              SuppressUserConversions, PartialOverloading);<br>
@@ -6596,12 +6621,12 @@ void Sema::AddFunctionCandidates(const U<br>
<br>
 /// AddMethodCandidate - Adds a named decl (which is some kind of<br>
 /// method) as a method candidate to the given overload set.<br>
-void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,<br>
-                              QualType ObjectType,<br>
+void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,<br>
                               Expr::Classification ObjectClassification,<br>
                               ArrayRef<Expr *> Args,<br>
-                              OverloadCandidateSet& CandidateSet,<br>
-                              bool SuppressUserConversions) {<br>
+                              OverloadCandidateSet &CandidateSet,<br>
+                              bool SuppressUserConversions,<br>
+                              OverloadCandidateParamOrder PO) {<br>
   NamedDecl *Decl = FoundDecl.getDecl();<br>
   CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());<br>
<br>
@@ -6614,11 +6639,11 @@ void Sema::AddMethodCandidate(DeclAccess<br>
     AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,<br>
                                /*ExplicitArgs*/ nullptr, ObjectType,<br>
                                ObjectClassification, Args, CandidateSet,<br>
-                               SuppressUserConversions);<br>
+                               SuppressUserConversions, false, PO);<br>
   } else {<br>
     AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,<br>
                        ObjectType, ObjectClassification, Args, CandidateSet,<br>
-                       SuppressUserConversions);<br>
+                       SuppressUserConversions, false, None, PO);<br>
   }<br>
 }<br>
<br>
@@ -6637,14 +6662,15 @@ Sema::AddMethodCandidate(CXXMethodDecl *<br>
                          OverloadCandidateSet &CandidateSet,<br>
                          bool SuppressUserConversions,<br>
                          bool PartialOverloading,<br>
-                         ConversionSequenceList EarlyConversions) {<br>
+                         ConversionSequenceList EarlyConversions,<br>
+                         OverloadCandidateParamOrder PO) {<br>
   const FunctionProtoType *Proto<br>
     = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());<br>
   assert(Proto && "Methods without a prototype cannot be overloaded");<br>
   assert(!isa<CXXConstructorDecl>(Method) &&<br>
          "Use AddOverloadCandidate for constructors");<br>
<br>
-  if (!CandidateSet.isNewCandidate(Method))<br>
+  if (!CandidateSet.isNewCandidate(Method, PO))<br>
     return;<br>
<br>
   // C++11 [class.copy]p23: [DR1402]<br>
@@ -6663,6 +6689,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *<br>
       CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);<br>
   Candidate.FoundDecl = FoundDecl;<br>
   Candidate.Function = Method;<br>
+  Candidate.RewriteKind =<br>
+      CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);<br>
   Candidate.IsSurrogate = false;<br>
   Candidate.IgnoreObjectArgument = false;<br>
   Candidate.ExplicitCallArguments = Args.size();<br>
@@ -6698,12 +6726,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *<br>
     // The implicit object argument is ignored.<br>
     Candidate.IgnoreObjectArgument = true;<br>
   else {<br>
+    unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;<br>
     // Determine the implicit conversion sequence for the object<br>
     // parameter.<br>
-    Candidate.Conversions[0] = TryObjectArgumentInitialization(<br>
+    Candidate.Conversions[ConvIdx] = TryObjectArgumentInitialization(<br>
         *this, CandidateSet.getLocation(), ObjectType, ObjectClassification,<br>
         Method, ActingContext);<br>
-    if (Candidate.Conversions[0].isBad()) {<br>
+    if (Candidate.Conversions[ConvIdx].isBad()) {<br>
       Candidate.Viable = false;<br>
       Candidate.FailureKind = ovl_fail_bad_conversion;<br>
       return;<br>
@@ -6722,7 +6751,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *<br>
   // Determine the implicit conversion sequences for each of the<br>
   // arguments.<br>
   for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {<br>
-    if (Candidate.Conversions[ArgIdx + 1].isInitialized()) {<br>
+    unsigned ConvIdx =<br>
+        PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + 1);<br>
+    if (Candidate.Conversions[ConvIdx].isInitialized()) {<br>
       // We already formed a conversion sequence for this parameter during<br>
       // template argument deduction.<br>
     } else if (ArgIdx < NumParams) {<br>
@@ -6731,13 +6762,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *<br>
       // (13.3.3.1) that converts that argument to the corresponding<br>
       // parameter of F.<br>
       QualType ParamType = Proto->getParamType(ArgIdx);<br>
-      Candidate.Conversions[ArgIdx + 1]<br>
+      Candidate.Conversions[ConvIdx]<br>
         = TryCopyInitialization(*this, Args[ArgIdx], ParamType,<br>
                                 SuppressUserConversions,<br>
                                 /*InOverloadResolution=*/true,<br>
                                 /*AllowObjCWritebackConversion=*/<br>
                                   getLangOpts().ObjCAutoRefCount);<br>
-      if (Candidate.Conversions[ArgIdx + 1].isBad()) {<br>
+      if (Candidate.Conversions[ConvIdx].isBad()) {<br>
         Candidate.Viable = false;<br>
         Candidate.FailureKind = ovl_fail_bad_conversion;<br>
         return;<br>
@@ -6746,7 +6777,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *<br>
       // (C++ 13.3.2p2): For the purposes of overload resolution, any<br>
       // argument for which there is no corresponding parameter is<br>
       // considered to "match the ellipsis" (C+ 13.3.3.1.3).<br>
-      Candidate.Conversions[ArgIdx + 1].setEllipsis();<br>
+      Candidate.Conversions[ConvIdx].setEllipsis();<br>
     }<br>
   }<br>
<br>
@@ -6767,18 +6798,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *<br>
 /// Add a C++ member function template as a candidate to the candidate<br>
 /// set, using template argument deduction to produce an appropriate member<br>
 /// function template specialization.<br>
-void<br>
-Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,<br>
-                                 DeclAccessPair FoundDecl,<br>
-                                 CXXRecordDecl *ActingContext,<br>
-                                 TemplateArgumentListInfo *ExplicitTemplateArgs,<br>
-                                 QualType ObjectType,<br>
-                                 Expr::Classification ObjectClassification,<br>
-                                 ArrayRef<Expr *> Args,<br>
-                                 OverloadCandidateSet& CandidateSet,<br>
-                                 bool SuppressUserConversions,<br>
-                                 bool PartialOverloading) {<br>
-  if (!CandidateSet.isNewCandidate(MethodTmpl))<br>
+void Sema::AddMethodTemplateCandidate(<br>
+    FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl,<br>
+    CXXRecordDecl *ActingContext,<br>
+    TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType,<br>
+    Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,<br>
+    OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,<br>
+    bool PartialOverloading, OverloadCandidateParamOrder PO) {<br>
+  if (!CandidateSet.isNewCandidate(MethodTmpl, PO))<br>
     return;<br>
<br>
   // C++ [over.match.funcs]p7:<br>
@@ -6799,13 +6826,15 @@ Sema::AddMethodTemplateCandidate(Functio<br>
             return CheckNonDependentConversions(<br>
                 MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,<br>
                 SuppressUserConversions, ActingContext, ObjectType,<br>
-                ObjectClassification);<br>
+                ObjectClassification, PO);<br>
           })) {<br>
     OverloadCandidate &Candidate =<br>
         CandidateSet.addCandidate(Conversions.size(), Conversions);<br>
     Candidate.FoundDecl = FoundDecl;<br>
     Candidate.Function = MethodTmpl->getTemplatedDecl();<br>
     Candidate.Viable = false;<br>
+    Candidate.RewriteKind =<br>
+      CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);<br>
     Candidate.IsSurrogate = false;<br>
     Candidate.IgnoreObjectArgument =<br>
         cast<CXXMethodDecl>(Candidate.Function)->isStatic() ||<br>
@@ -6829,7 +6858,7 @@ Sema::AddMethodTemplateCandidate(Functio<br>
   AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,<br>
                      ActingContext, ObjectType, ObjectClassification, Args,<br>
                      CandidateSet, SuppressUserConversions, PartialOverloading,<br>
-                     Conversions);<br>
+                     Conversions, PO);<br>
 }<br>
<br>
 /// Add a C++ function template specialization as a candidate<br>
@@ -6839,8 +6868,9 @@ void Sema::AddTemplateOverloadCandidate(<br>
     FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,<br>
     TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,<br>
     OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,<br>
-    bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate) {<br>
-  if (!CandidateSet.isNewCandidate(FunctionTemplate))<br>
+    bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate,<br>
+    OverloadCandidateParamOrder PO) {<br>
+  if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))<br>
     return;<br>
<br>
   // C++ [over.match.funcs]p7:<br>
@@ -6858,15 +6888,17 @@ void Sema::AddTemplateOverloadCandidate(<br>
   if (TemplateDeductionResult Result = DeduceTemplateArguments(<br>
           FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,<br>
           PartialOverloading, [&](ArrayRef<QualType> ParamTypes) {<br>
-            return CheckNonDependentConversions(FunctionTemplate, ParamTypes,<br>
-                                                Args, CandidateSet, Conversions,<br>
-                                                SuppressUserConversions);<br>
+            return CheckNonDependentConversions(<br>
+                FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions,<br>
+                SuppressUserConversions, nullptr, QualType(), {}, PO);<br>
           })) {<br>
     OverloadCandidate &Candidate =<br>
         CandidateSet.addCandidate(Conversions.size(), Conversions);<br>
     Candidate.FoundDecl = FoundDecl;<br>
     Candidate.Function = FunctionTemplate->getTemplatedDecl();<br>
     Candidate.Viable = false;<br>
+    Candidate.RewriteKind =<br>
+      CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);<br>
     Candidate.IsSurrogate = false;<br>
     Candidate.IsADLCandidate = IsADLCandidate;<br>
     // Ignore the object argument if there is one, since we don't have an object<br>
@@ -6891,7 +6923,7 @@ void Sema::AddTemplateOverloadCandidate(<br>
   AddOverloadCandidate(<br>
       Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,<br>
       PartialOverloading, AllowExplicit,<br>
-      /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions);<br>
+      /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions, PO);<br>
 }<br>
<br>
 /// Check that implicit conversion sequences can be formed for each argument<br>
@@ -6902,7 +6934,7 @@ bool Sema::CheckNonDependentConversions(<br>
     ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet,<br>
     ConversionSequenceList &Conversions, bool SuppressUserConversions,<br>
     CXXRecordDecl *ActingContext, QualType ObjectType,<br>
-    Expr::Classification ObjectClassification) {<br>
+    Expr::Classification ObjectClassification, OverloadCandidateParamOrder PO) {<br>
   // FIXME: The cases in which we allow explicit conversions for constructor<br>
   // arguments never consider calling a constructor template. It's not clear<br>
   // that is correct.<br>
@@ -6925,10 +6957,11 @@ bool Sema::CheckNonDependentConversions(<br>
   // overload resolution is permitted to sidestep instantiations.<br>
   if (HasThisConversion && !cast<CXXMethodDecl>(FD)->isStatic() &&<br>
       !ObjectType.isNull()) {<br>
-    Conversions[0] = TryObjectArgumentInitialization(<br>
+    unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;<br>
+    Conversions[ConvIdx] = TryObjectArgumentInitialization(<br>
         *this, CandidateSet.getLocation(), ObjectType, ObjectClassification,<br>
         Method, ActingContext);<br>
-    if (Conversions[0].isBad())<br>
+    if (Conversions[ConvIdx].isBad())<br>
       return true;<br>
   }<br>
<br>
@@ -6936,14 +6969,17 @@ bool Sema::CheckNonDependentConversions(<br>
        ++I) {<br>
     QualType ParamType = ParamTypes[I];<br>
     if (!ParamType->isDependentType()) {<br>
-      Conversions[ThisConversions + I]<br>
+      unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed<br>
+                             ? 0<br>
+                             : (ThisConversions + I);<br>
+      Conversions[ConvIdx]<br>
         = TryCopyInitialization(*this, Args[I], ParamType,<br>
                                 SuppressUserConversions,<br>
                                 /*InOverloadResolution=*/true,<br>
                                 /*AllowObjCWritebackConversion=*/<br>
                                   getLangOpts().ObjCAutoRefCount,<br>
                                 AllowExplicit);<br>
-      if (Conversions[ThisConversions + I].isBad())<br>
+      if (Conversions[ConvIdx].isBad())<br>
         return true;<br>
     }<br>
   }<br>
@@ -7331,6 +7367,48 @@ void Sema::AddSurrogateCandidate(CXXConv<br>
   }<br>
 }<br>
<br>
+/// Add all of the non-member operator function declarations in the given<br>
+/// function set to the overload candidate set.<br>
+void Sema::AddNonMemberOperatorCandidates(<br>
+    const UnresolvedSetImpl &Fns, ArrayRef<Expr *> Args,<br>
+    OverloadCandidateSet &CandidateSet,<br>
+    TemplateArgumentListInfo *ExplicitTemplateArgs) {<br>
+  for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {<br>
+    NamedDecl *D = F.getDecl()->getUnderlyingDecl();<br>
+    ArrayRef<Expr *> FunctionArgs = Args;<br>
+<br>
+    FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);<br>
+    FunctionDecl *FD =<br>
+        FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D);<br>
+<br>
+    // Don't consider rewritten functions if we're not rewriting.<br>
+    if (!CandidateSet.getRewriteInfo().isAcceptableCandidate(FD))<br>
+      continue;<br>
+<br>
+    assert(!isa<CXXMethodDecl>(FD) &&<br>
+           "unqualified operator lookup found a member function");<br>
+<br>
+    if (FunTmpl) {<br>
+      AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs,<br>
+                                   FunctionArgs, CandidateSet);<br>
+      if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))<br>
+        AddTemplateOverloadCandidate(<br>
+            FunTmpl, F.getPair(), ExplicitTemplateArgs,<br>
+            {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false,<br>
+            true, ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed);<br>
+    } else {<br>
+      if (ExplicitTemplateArgs)<br>
+        continue;<br>
+      AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet);<br>
+      if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))<br>
+        AddOverloadCandidate(FD, F.getPair(),<br>
+                             {FunctionArgs[1], FunctionArgs[0]}, CandidateSet,<br>
+                             false, false, true, false, ADLCallKind::NotADL,<br>
+                             None, OverloadCandidateParamOrder::Reversed);<br>
+    }<br>
+  }<br>
+}<br>
+<br>
 /// Add overload candidates for overloaded operators that are<br>
 /// member functions.<br>
 ///<br>
@@ -7342,8 +7420,8 @@ void Sema::AddSurrogateCandidate(CXXConv<br>
 void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,<br>
                                        SourceLocation OpLoc,<br>
                                        ArrayRef<Expr *> Args,<br>
-                                       OverloadCandidateSet& CandidateSet,<br>
-                                       SourceRange OpRange) {<br>
+                                       OverloadCandidateSet &CandidateSet,<br>
+                                       OverloadCandidateParamOrder PO) {<br>
   DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);<br>
<br>
   // C++ [over.match.oper]p3:<br>
@@ -7378,7 +7456,7 @@ void Sema::AddMemberOperatorCandidates(O<br>
          ++Oper)<br>
       AddMethodCandidate(Oper.getPair(), Args[0]->getType(),<br>
                          Args[0]->Classify(Context), Args.slice(1),<br>
-                         CandidateSet, /*SuppressUserConversion=*/false);<br>
+                         CandidateSet, /*SuppressUserConversion=*/false, PO);<br>
   }<br>
 }<br>
<br>
@@ -8183,10 +8261,16 @@ public:<br>
           if (C->Function->isFunctionTemplateSpecialization())<br>
             continue;<br>
<br>
-          QualType FirstParamType =<br>
-            C->Function->getParamDecl(0)->getType().getUnqualifiedType();<br>
-          QualType SecondParamType =<br>
-            C->Function->getParamDecl(1)->getType().getUnqualifiedType();<br>
+          // We interpret "same parameter-type-list" as applying to the<br>
+          // "synthesized candidate, with the order of the two parameters<br>
+          // reversed", not to the original function.<br>
+          bool Reversed = C->RewriteKind & CRK_Reversed;<br>
+          QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0)<br>
+                                        ->getType()<br>
+                                        .getUnqualifiedType();<br>
+          QualType SecondParamType = C->Function->getParamDecl(Reversed ? 0 : 1)<br>
+                                         ->getType()<br>
+                                         .getUnqualifiedType();<br>
<br>
           // Skip if either parameter isn't of enumeral type.<br>
           if (!FirstParamType->isEnumeralType() ||<br>
@@ -9240,6 +9324,7 @@ bool clang::isBetterOverloadCandidate(<br>
   //   A viable function F1 is defined to be a better function than another<br>
   //   viable function F2 if for all arguments i, ICSi(F1) is not a worse<br>
   //   conversion sequence than ICSi(F2), and then...<br>
+  bool HasWorseConversion = false;<br>
   for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {<br>
     switch (CompareImplicitConversionSequences(S, Loc,<br>
                                                Cand1.Conversions[ArgIdx],<br>
@@ -9250,6 +9335,24 @@ bool clang::isBetterOverloadCandidate(<br>
       break;<br>
<br>
     case ImplicitConversionSequence::Worse:<br>
+      if (Cand1.Function && Cand1.Function == Cand2.Function &&<br>
+          (Cand2.RewriteKind & CRK_Reversed) != 0) {<br>
+        // Work around large-scale breakage caused by considering reversed<br>
+        // forms of operator== in C++20:<br>
+        //<br>
+        // When comparing a function against its reversed form, if we have a<br>
+        // better conversion for one argument and a worse conversion for the<br>
+        // other, we prefer the non-reversed form.<br>
+        //<br>
+        // This prevents a conversion function from being considered ambiguous<br>
+        // with its own reversed form in various where it's only incidentally<br>
+        // heterogeneous.<br>
+        //<br>
+        // We diagnose this as an extension from CreateOverloadedBinOp.<br>
+        HasWorseConversion = true;<br>
+        break;<br>
+      }<br>
+<br>
       // Cand1 can't be better than Cand2.<br>
       return false;<br>
<br>
@@ -9263,6 +9366,8 @@ bool clang::isBetterOverloadCandidate(<br>
   //       ICSj(F2), or, if not that,<br>
   if (HasBetterConversion)<br>
     return true;<br>
+  if (HasWorseConversion)<br>
+    return false;<br>
<br>
   //   -- the context is an initialization by user-defined conversion<br>
   //      (see 8.5, 13.3.1.5) and the standard conversion sequence<br>
@@ -9330,8 +9435,10 @@ bool clang::isBetterOverloadCandidate(<br>
       return BetterTemplate == Cand1.Function->getPrimaryTemplate();<br>
   }<br>
<br>
-  // FIXME: Work around a defect in the C++17 inheriting constructor wording.<br>
-  // A derived-class constructor beats an (inherited) base class constructor.<br>
+  //   -- F1 is a constructor for a class D, F2 is a constructor for a base<br>
+  //      class B of D, and for all arguments the corresponding parameters of<br>
+  //      F1 and F2 have the same type.<br>
+  // FIXME: Implement the "all parameters have the same type" check.<br>
   bool Cand1IsInherited =<br>
       dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl());<br>
   bool Cand2IsInherited =<br>
@@ -9349,6 +9456,16 @@ bool clang::isBetterOverloadCandidate(<br>
     // Inherited from sibling base classes: still ambiguous.<br>
   }<br>
<br>
+  //   -- F2 is a rewritten candidate (12.4.1.2) and F1 is not<br>
+  //   -- F1 and F2 are rewritten candidates, and F2 is a synthesized candidate<br>
+  //      with reversed order of parameters and F1 is not<br>
+  //<br>
+  // We rank reversed + different operator as worse than just reversed, but<br>
+  // that comparison can never happen, because we only consider reversing for<br>
+  // the maximally-rewritten operator (== or <=>).<br>
+  if (Cand1.RewriteKind != Cand2.RewriteKind)<br>
+    return Cand1.RewriteKind < Cand2.RewriteKind;<br>
+<br>
   // Check C++17 tie-breakers for deduction guides.<br>
   {<br>
     auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);<br>
@@ -9544,6 +9661,7 @@ namespace {<br>
 enum OverloadCandidateKind {<br>
   oc_function,<br>
   oc_method,<br>
+  oc_reversed_binary_operator,<br>
   oc_constructor,<br>
   oc_implicit_default_constructor,<br>
   oc_implicit_copy_constructor,<br>
@@ -9561,6 +9679,7 @@ enum OverloadCandidateSelect {<br>
<br>
 static std::pair<OverloadCandidateKind, OverloadCandidateSelect><br>
 ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn,<br>
+                          OverloadCandidateRewriteKind CRK,<br>
                           std::string &Description) {<br>
<br>
   bool isTemplate = Fn->isTemplateDecl() || Found->isTemplateDecl();<br>
@@ -9577,6 +9696,9 @@ ClassifyOverloadCandidate(Sema &S, Named<br>
   }();<br>
<br>
   OverloadCandidateKind Kind = [&]() {<br>
+    if (CRK & CRK_Reversed)<br>
+      return oc_reversed_binary_operator;<br>
+<br>
     if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) {<br>
       if (!Ctor->isImplicit()) {<br>
         if (isa<ConstructorUsingShadowDecl>(Found))<br>
@@ -9701,6 +9823,7 @@ bool Sema::checkAddressOfFunctionIsAvail<br>
<br>
 // Notes the location of an overload candidate.<br>
 void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,<br>
+                                 OverloadCandidateRewriteKind RewriteKind,<br>
                                  QualType DestType, bool TakingAddress) {<br>
   if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn))<br>
     return;<br>
@@ -9710,7 +9833,7 @@ void Sema::NoteOverloadCandidate(NamedDe<br>
<br>
   std::string FnDesc;<br>
   std::pair<OverloadCandidateKind, OverloadCandidateSelect> KSPair =<br>
-      ClassifyOverloadCandidate(*this, Found, Fn, FnDesc);<br>
+      ClassifyOverloadCandidate(*this, Found, Fn, RewriteKind, FnDesc);<br>
   PartialDiagnostic PD = PDiag(diag::note_ovl_candidate)<br>
                          << (unsigned)KSPair.first << (unsigned)KSPair.second<br>
                          << Fn << FnDesc;<br>
@@ -9734,11 +9857,11 @@ void Sema::NoteAllOverloadCandidates(Exp<br>
        I != IEnd; ++I) {<br>
     if (FunctionTemplateDecl *FunTmpl =<br>
                 dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {<br>
-      NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), DestType,<br>
+      NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), CRK_None, DestType,<br>
                             TakingAddress);<br>
     } else if (FunctionDecl *Fun<br>
                       = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {<br>
-      NoteOverloadCandidate(*I, Fun, DestType, TakingAddress);<br>
+      NoteOverloadCandidate(*I, Fun, CRK_None, DestType, TakingAddress);<br>
     }<br>
   }<br>
 }<br>
@@ -9788,7 +9911,8 @@ static void DiagnoseBadConversion(Sema &<br>
<br>
   std::string FnDesc;<br>
   std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =<br>
-      ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);<br>
+      ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,<br>
+                                FnDesc);<br>
<br>
   Expr *FromExpr = Conv.Bad.FromExpr;<br>
   QualType FromTy = Conv.Bad.getFromType();<br>
@@ -10060,7 +10184,7 @@ static void DiagnoseArityMismatch(Sema &<br>
<br>
   std::string Description;<br>
   std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =<br>
-      ClassifyOverloadCandidate(S, Found, Fn, Description);<br>
+      ClassifyOverloadCandidate(S, Found, Fn, CRK_None, Description);<br>
<br>
   if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName())<br>
     S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one)<br>
@@ -10357,7 +10481,8 @@ static void DiagnoseBadTarget(Sema &S, O<br>
<br>
   std::string FnDesc;<br>
   std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =<br>
-      ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, FnDesc);<br>
+      ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, Cand->RewriteKind,<br>
+                                FnDesc);<br>
<br>
   S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)<br>
       << (unsigned)FnKindPair.first << (unsigned)ocs_non_template<br>
@@ -10475,7 +10600,8 @@ static void NoteFunctionCandidate(Sema &<br>
     if (Fn->isDeleted()) {<br>
       std::string FnDesc;<br>
       std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =<br>
-          ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);<br>
+          ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,<br>
+                                    FnDesc);<br>
<br>
       S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)<br>
           << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc<br>
@@ -10485,7 +10611,7 @@ static void NoteFunctionCandidate(Sema &<br>
     }<br>
<br>
     // We don't really have anything else to say about viable candidates.<br>
-    S.NoteOverloadCandidate(Cand->FoundDecl, Fn);<br>
+    S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);<br>
     return;<br>
   }<br>
<br>
@@ -10518,7 +10644,7 @@ static void NoteFunctionCandidate(Sema &<br>
   case ovl_fail_trivial_conversion:<br>
   case ovl_fail_bad_final_conversion:<br>
   case ovl_fail_final_conversion_not_exact:<br>
-    return S.NoteOverloadCandidate(Cand->FoundDecl, Fn);<br>
+    return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);<br>
<br>
   case ovl_fail_bad_conversion: {<br>
     unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);<br>
@@ -10529,7 +10655,7 @@ static void NoteFunctionCandidate(Sema &<br>
     // FIXME: this currently happens when we're called from SemaInit<br>
     // when user-conversion overload fails.  Figure out how to handle<br>
     // those conditions and diagnose them well.<br>
-    return S.NoteOverloadCandidate(Cand->FoundDecl, Fn);<br>
+    return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);<br>
   }<br>
<br>
   case ovl_fail_bad_target:<br>
@@ -10805,8 +10931,10 @@ struct CompareOverloadCandidatesForDispl<br>
 /// CompleteNonViableCandidate - Normally, overload resolution only<br>
 /// computes up to the first bad conversion. Produces the FixIt set if<br>
 /// possible.<br>
-static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,<br>
-                                       ArrayRef<Expr *> Args) {<br>
+static void<br>
+CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,<br>
+                           ArrayRef<Expr *> Args,<br>
+                           OverloadCandidateSet::CandidateSetKind CSK) {<br>
   assert(!Cand->Viable);<br>
<br>
   // Don't do anything on failures other than bad conversion.<br>
@@ -10834,6 +10962,7 @@ static void CompleteNonViableCandidate(S<br>
   bool SuppressUserConversions = false;<br>
<br>
   unsigned ConvIdx = 0;<br>
+  unsigned ArgIdx = 0;<br>
   ArrayRef<QualType> ParamTypes;<br>
<br>
   if (Cand->IsSurrogate) {<br>
@@ -10842,15 +10971,18 @@ static void CompleteNonViableCandidate(S<br>
     if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())<br>
       ConvType = ConvPtrType->getPointeeType();<br>
     ParamTypes = ConvType->castAs<FunctionProtoType>()->getParamTypes();<br>
-    // Conversion 0 is 'this', which doesn't have a corresponding argument.<br>
+    // Conversion 0 is 'this', which doesn't have a corresponding parameter.<br>
     ConvIdx = 1;<br>
   } else if (Cand->Function) {<br>
     ParamTypes =<br>
         Cand->Function->getType()->castAs<FunctionProtoType>()->getParamTypes();<br>
     if (isa<CXXMethodDecl>(Cand->Function) &&<br>
         !isa<CXXConstructorDecl>(Cand->Function)) {<br>
-      // Conversion 0 is 'this', which doesn't have a corresponding argument.<br>
+      // Conversion 0 is 'this', which doesn't have a corresponding parameter.<br>
       ConvIdx = 1;<br>
+      if (CSK == OverloadCandidateSet::CSK_Operator)<br>
+        // Argument 0 is 'this', which doesn't have a corresponding parameter.<br>
+        ArgIdx = 1;<br>
     }<br>
   } else {<br>
     // Builtin operator.<br>
@@ -10859,16 +10991,19 @@ static void CompleteNonViableCandidate(S<br>
   }<br>
<br>
   // Fill in the rest of the conversions.<br>
-  for (unsigned ArgIdx = 0; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {<br>
+  bool Reversed = Cand->RewriteKind & CRK_Reversed;<br>
+  for (unsigned ParamIdx = Reversed ? ParamTypes.size() - 1 : 0;<br>
+       ConvIdx != ConvCount;<br>
+       ++ConvIdx, ++ArgIdx, ParamIdx += (Reversed ? -1 : 1)) {<br>
     if (Cand->Conversions[ConvIdx].isInitialized()) {<br>
       // We've already checked this conversion.<br>
     } else if (ArgIdx < ParamTypes.size()) {<br>
-      if (ParamTypes[ArgIdx]->isDependentType())<br>
+      if (ParamTypes[ParamIdx]->isDependentType())<br>
         Cand->Conversions[ConvIdx].setAsIdentityConversion(<br>
             Args[ArgIdx]->getType());<br>
       else {<br>
         Cand->Conversions[ConvIdx] =<br>
-            TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ArgIdx],<br>
+            TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ParamIdx],<br>
                                   SuppressUserConversions,<br>
                                   /*InOverloadResolution=*/true,<br>
                                   /*AllowObjCWritebackConversion=*/<br>
@@ -10896,7 +11031,7 @@ SmallVector<OverloadCandidate *, 32> Ove<br>
     if (Cand->Viable)<br>
       Cands.push_back(Cand);<br>
     else if (OCD == OCD_AllCandidates) {<br>
-      CompleteNonViableCandidate(S, Cand, Args);<br>
+      CompleteNonViableCandidate(S, Cand, Args, Kind);<br>
       if (Cand->Function || Cand->IsSurrogate)<br>
         Cands.push_back(Cand);<br>
       // Otherwise, this a non-viable builtin candidate.  We do not, in general,<br>
@@ -11453,7 +11588,7 @@ public:<br>
         if (FunctionDecl *Fun =<br>
                 dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))<br>
           if (!functionHasPassObjectSizeParams(Fun))<br>
-            S.NoteOverloadCandidate(*I, Fun, TargetFunctionType,<br>
+            S.NoteOverloadCandidate(*I, Fun, CRK_None, TargetFunctionType,<br>
                                     /*TakingAddress=*/true);<br>
       FailedCandidates.NoteCandidates(S, OvlExpr->getBeginLoc());<br>
     }<br>
@@ -12403,7 +12538,7 @@ Sema::CreateOverloadedUnaryOp(SourceLoca<br>
   OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);<br>
<br>
   // Add the candidates from the given function set.<br>
-  AddFunctionCandidates(Fns, ArgsArray, CandidateSet);<br>
+  AddNonMemberOperatorCandidates(Fns, ArgsArray, CandidateSet);<br>
<br>
   // Add operator candidates that are member functions.<br>
   AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);<br>
@@ -12548,14 +12683,17 @@ Sema::CreateOverloadedUnaryOp(SourceLoca<br>
 ///<br>
 /// \param LHS Left-hand argument.<br>
 /// \param RHS Right-hand argument.<br>
-ExprResult<br>
-Sema::CreateOverloadedBinOp(SourceLocation OpLoc,<br>
-                            BinaryOperatorKind Opc,<br>
-                            const UnresolvedSetImpl &Fns,<br>
-                            Expr *LHS, Expr *RHS, bool PerformADL) {<br>
+ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,<br>
+                                       BinaryOperatorKind Opc,<br>
+                                       const UnresolvedSetImpl &Fns, Expr *LHS,<br>
+                                       Expr *RHS, bool PerformADL,<br>
+                                       bool AllowRewrittenCandidates) {<br>
   Expr *Args[2] = { LHS, RHS };<br>
   LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple<br>
<br>
+  if (!getLangOpts().CPlusPlus2a)<br>
+    AllowRewrittenCandidates = false;<br>
+<br>
   OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);<br>
   DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);<br>
<br>
@@ -12613,23 +12751,61 @@ Sema::CreateOverloadedBinOp(SourceLocati<br>
     return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);<br>
<br>
   // Build an empty overload set.<br>
-  OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);<br>
+  OverloadCandidateSet CandidateSet(<br>
+      OpLoc, OverloadCandidateSet::CSK_Operator,<br>
+      OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates));<br>
<br>
-  // Add the candidates from the given function set.<br>
-  AddFunctionCandidates(Fns, Args, CandidateSet);<br>
+  OverloadedOperatorKind ExtraOp =<br>
+      AllowRewrittenCandidates ? getRewrittenOverloadedOperator(Op) : OO_None;<br>
+<br>
+  // Add the candidates from the given function set. This also adds the<br>
+  // rewritten candidates using these functions if necessary.<br>
+  AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);<br>
<br>
   // Add operator candidates that are member functions.<br>
   AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);<br>
+  if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))<br>
+    AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,<br>
+                                OverloadCandidateParamOrder::Reversed);<br>
+<br>
+  // In C++20, also add any rewritten member candidates.<br>
+  if (ExtraOp) {<br>
+    AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);<br>
+    if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp))<br>
+      AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},<br>
+                                  CandidateSet,<br>
+                                  OverloadCandidateParamOrder::Reversed);<br>
+  }<br>
<br>
   // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not<br>
   // performed for an assignment operator (nor for operator[] nor operator->,<br>
   // which don't get here).<br>
-  if (Opc != BO_Assign && PerformADL)<br>
+  if (Opc != BO_Assign && PerformADL) {<br>
     AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,<br>
                                          /*ExplicitTemplateArgs*/ nullptr,<br>
                                          CandidateSet);<br>
+    if (ExtraOp) {<br>
+      DeclarationName ExtraOpName =<br>
+          Context.DeclarationNames.getCXXOperatorName(ExtraOp);<br>
+      AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args,<br>
+                                           /*ExplicitTemplateArgs*/ nullptr,<br>
+                                           CandidateSet);<br>
+    }<br>
+  }<br>
<br>
   // Add builtin operator candidates.<br>
+  //<br>
+  // FIXME: We don't add any rewritten candidates here. This is strictly<br>
+  // incorrect; a builtin candidate could be hidden by a non-viable candidate,<br>
+  // resulting in our selecting a rewritten builtin candidate. For example:<br>
+  //<br>
+  //   enum class E { e };<br>
+  //   bool operator!=(E, E) requires false;<br>
+  //   bool k = E::e != E::e;<br>
+  //<br>
+  // ... should select the rewritten builtin candidate 'operator==(E, E)'. But<br>
+  // it seems unreasonable to consider rewritten builtin candidates. A core<br>
+  // issue has been filed proposing to removed this requirement.<br>
   AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);<br>
<br>
   bool HadMultipleCandidates = (CandidateSet.size() > 1);<br>
@@ -12641,11 +12817,57 @@ Sema::CreateOverloadedBinOp(SourceLocati<br>
       // We found a built-in operator or an overloaded operator.<br>
       FunctionDecl *FnDecl = Best->Function;<br>
<br>
+      bool IsReversed = (Best->RewriteKind & CRK_Reversed);<br>
+      if (IsReversed)<br>
+        std::swap(Args[0], Args[1]);<br>
+<br>
       if (FnDecl) {<br>
         Expr *Base = nullptr;<br>
         // We matched an overloaded operator. Build a call to that<br>
         // operator.<br>
<br>
+        OverloadedOperatorKind ChosenOp =<br>
+            FnDecl->getDeclName().getCXXOverloadedOperator();<br>
+<br>
+        // C++2a [over.match.oper]p9:<br>
+        //   If a rewritten operator== candidate is selected by overload<br>
+        //   resolution for an operator@, its return type shall be cv bool<br>
+        if (Best->RewriteKind && ChosenOp == OO_EqualEqual &&<br>
+            !FnDecl->getReturnType()->isBooleanType()) {<br>
+          Diag(OpLoc, diag::err_ovl_rewrite_equalequal_not_bool)<br>
+              << FnDecl->getReturnType() << BinaryOperator::getOpcodeStr(Opc)<br>
+              << Args[0]->getSourceRange() << Args[1]->getSourceRange();<br>
+          Diag(FnDecl->getLocation(), diag::note_declared_at);<br>
+          return ExprError();<br>
+        }<br>
+<br>
+        if (AllowRewrittenCandidates && !IsReversed &&<br>
+            CandidateSet.getRewriteInfo().shouldAddReversed(ChosenOp)) {<br>
+          // We could have reversed this operator, but didn't. Check if the<br>
+          // reversed form was a viable candidate, and if so, if it had a<br>
+          // better conversion for either parameter. If so, this call is<br>
+          // formally ambiguous, and allowing it is an extension.<br>
+          for (OverloadCandidate &Cand : CandidateSet) {<br>
+            if (Cand.Viable && Cand.Function == FnDecl &&<br>
+                Cand.RewriteKind & CRK_Reversed) {<br>
+              for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {<br>
+                if (CompareImplicitConversionSequences(<br>
+                        *this, OpLoc, Cand.Conversions[ArgIdx],<br>
+                        Best->Conversions[ArgIdx]) ==<br>
+                    ImplicitConversionSequence::Better) {<br>
+                  Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed)<br>
+                      << BinaryOperator::getOpcodeStr(Opc)<br>
+                      << Args[0]->getType() << Args[1]->getType()<br>
+                      << Args[0]->getSourceRange() << Args[1]->getSourceRange();<br>
+                  Diag(FnDecl->getLocation(),<br>
+                       diag::note_ovl_ambiguous_oper_binary_reversed_candidate);<br>
+                }<br>
+              }<br>
+              break;<br>
+            }<br>
+          }<br>
+        }<br>
+<br>
         // Convert the arguments.<br>
         if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {<br>
           // Best->Access is only meaningful for class members.<br>
@@ -12699,8 +12921,8 @@ Sema::CreateOverloadedBinOp(SourceLocati<br>
         ResultTy = ResultTy.getNonLValueExprType(Context);<br>
<br>
         CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(<br>
-            Context, Op, FnExpr.get(), Args, ResultTy, VK, OpLoc, FPFeatures,<br>
-            Best->IsADLCandidate);<br>
+            Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc,<br>
+            FPFeatures, Best->IsADLCandidate);<br>
<br>
         if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,<br>
                                 FnDecl))<br>
@@ -12722,7 +12944,46 @@ Sema::CreateOverloadedBinOp(SourceLocati<br>
                   isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),<br>
                   VariadicDoesNotApply);<br>
<br>
-        return MaybeBindToTemporary(TheCall);<br>
+        ExprResult R = MaybeBindToTemporary(TheCall);<br>
+        if (R.isInvalid())<br>
+          return ExprError();<br>
+<br>
+        // For a rewritten candidate, we've already reversed the arguments<br>
+        // if needed. Perform the rest of the rewrite now.<br>
+        if ((Best->RewriteKind & CRK_DifferentOperator) ||<br>
+            (Op == OO_Spaceship && IsReversed)) {<br>
+          if (Op == OO_ExclaimEqual) {<br>
+            assert(ChosenOp == OO_EqualEqual && "unexpected operator name");<br>
+            R = CreateBuiltinUnaryOp(OpLoc, UO_LNot, R.get());<br>
+          } else {<br>
+            assert(ChosenOp == OO_Spaceship && "unexpected operator name");<br>
+            llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);<br>
+            Expr *ZeroLiteral =<br>
+                IntegerLiteral::Create(Context, Zero, Context.IntTy, OpLoc);<br>
+<br>
+            Sema::CodeSynthesisContext Ctx;<br>
+            Ctx.Kind = Sema::CodeSynthesisContext::RewritingOperatorAsSpaceship;<br>
+            Ctx.Entity = FnDecl;<br>
+            pushCodeSynthesisContext(Ctx);<br>
+<br>
+            R = CreateOverloadedBinOp(<br>
+                OpLoc, Opc, Fns, IsReversed ? ZeroLiteral : R.get(),<br>
+                IsReversed ? R.get() : ZeroLiteral, PerformADL,<br>
+                /*AllowRewrittenCandidates=*/false);<br>
+<br>
+            popCodeSynthesisContext();<br>
+          }<br>
+          if (R.isInvalid())<br>
+            return ExprError();<br>
+        } else {<br>
+          assert(ChosenOp == Op && "unexpected operator name");<br>
+        }<br>
+<br>
+        // Make a note in the AST if we did any rewriting.<br>
+        if (Best->RewriteKind != CRK_None)<br>
+          R = new (Context) CXXRewrittenBinaryOperator(R.get(), IsReversed);<br>
+<br>
+        return R;<br>
       } else {<br>
         // We matched a built-in operator. Convert the arguments, then<br>
         // break out so that we will build the appropriate built-in<br>
@@ -12812,10 +13073,12 @@ Sema::CreateOverloadedBinOp(SourceLocati<br>
         return ExprError();<br>
       }<br>
       CandidateSet.NoteCandidates(<br>
-          PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper)<br>
-                                         << BinaryOperator::getOpcodeStr(Opc)<br>
-                                         << Args[0]->getSourceRange()<br>
-                                         << Args[1]->getSourceRange()),<br>
+          PartialDiagnosticAt(<br>
+              OpLoc, PDiag(diag::err_ovl_deleted_oper)<br>
+                         << getOperatorSpelling(Best->Function->getDeclName()<br>
+                                                    .getCXXOverloadedOperator())<br>
+                         << Args[0]->getSourceRange()<br>
+                         << Args[1]->getSourceRange()),<br>
           *this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc),<br>
           OpLoc);<br>
       return ExprError();<br>
@@ -13692,8 +13955,8 @@ ExprResult Sema::BuildLiteralOperatorCal<br>
<br>
   OverloadCandidateSet CandidateSet(UDSuffixLoc,<br>
                                     OverloadCandidateSet::CSK_Normal);<br>
-  AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, TemplateArgs,<br>
-                        /*SuppressUserConversions=*/true);<br>
+  AddNonMemberOperatorCandidates(R.asUnresolvedSet(), Args, CandidateSet,<br>
+                                 TemplateArgs);<br>
<br>
   bool HadMultipleCandidates = (CandidateSet.size() > 1);<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Oct 18 17:04:43 2019<br>
@@ -24,6 +24,7 @@<br>
 #include "clang/Basic/TargetInfo.h"<br>
 #include "clang/Sema/DeclSpec.h"<br>
 #include "clang/Sema/Lookup.h"<br>
+#include "clang/Sema/Overload.h"<br>
 #include "clang/Sema/ParsedTemplate.h"<br>
 #include "clang/Sema/Scope.h"<br>
 #include "clang/Sema/SemaInternal.h"<br>
@@ -8488,7 +8489,7 @@ bool Sema::CheckFunctionTemplateSpeciali<br>
     // candidates at once, to get proper sorting and limiting.<br>
     for (auto *OldND : Previous) {<br>
       if (auto *OldFD = dyn_cast<FunctionDecl>(OldND->getUnderlyingDecl()))<br>
-        NoteOverloadCandidate(OldND, OldFD, FD->getType(), false);<br>
+        NoteOverloadCandidate(OldND, OldFD, CRK_None, FD->getType(), false);<br>
     }<br>
     FailedCandidates.NoteCandidates(*this, FD->getLocation());<br>
     return true;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Fri Oct 18 17:04:43 2019<br>
@@ -206,6 +206,7 @@ bool Sema::CodeSynthesisContext::isInsta<br>
   case DefiningSynthesizedFunction:<br>
   case ExceptionSpecEvaluation:<br>
   case ConstraintSubstitution:<br>
+  case RewritingOperatorAsSpaceship:<br>
     return false;<br>
<br>
   // This function should never be called when Kind's value is Memoization.<br>
@@ -682,6 +683,11 @@ void Sema::PrintInstantiationStack() {<br>
       break;<br>
     }<br>
<br>
+    case CodeSynthesisContext::RewritingOperatorAsSpaceship:<br>
+      Diags.Report(Active->Entity->getLocation(),<br>
+                   diag::note_rewriting_operator_as_spaceship);<br>
+      break;<br>
+<br>
     case CodeSynthesisContext::Memoization:<br>
       break;<br>
<br>
@@ -754,6 +760,7 @@ Optional<TemplateDeductionInfo *> Sema::<br>
<br>
     case CodeSynthesisContext::DeclaringSpecialMember:<br>
     case CodeSynthesisContext::DefiningSynthesizedFunction:<br>
+    case CodeSynthesisContext::RewritingOperatorAsSpaceship:<br>
       // This happens in a context unrelated to template instantiation, so<br>
       // there is no SFINAE.<br>
       return None;<br>
<br>
Modified: cfe/trunk/lib/Sema/TreeTransform.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/TreeTransform.h (original)<br>
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Oct 18 17:04:43 2019<br>
@@ -2355,13 +2355,13 @@ public:<br>
<br>
   /// Build a new rewritten operator expression.<br>
   ///<br>
-  /// By default, builds the rewritten operator without performing any semantic<br>
-  /// analysis. Subclasses may override this routine to provide different<br>
-  /// behavior.<br>
-  ExprResult RebuildCXXRewrittenBinaryOperator(Expr *SemanticForm,<br>
-                                             bool IsReversed) {<br>
-    return new (getSema().Context)<br>
-        CXXRewrittenBinaryOperator(SemanticForm, IsReversed);<br>
+  /// By default, performs semantic analysis to build the new expression.<br>
+  /// Subclasses may override this routine to provide different behavior.<br>
+  ExprResult RebuildCXXRewrittenBinaryOperator(<br>
+      SourceLocation OpLoc, BinaryOperatorKind Opcode,<br>
+      const UnresolvedSetImpl &UnqualLookups, Expr *LHS, Expr *RHS) {<br>
+    return getSema().CreateOverloadedBinOp(OpLoc, Opcode, UnqualLookups, LHS,<br>
+                                           RHS, /*RequiresADL*/false);<br>
   }<br>
<br>
   /// Build a new conditional operator expression.<br>
@@ -9783,24 +9783,45 @@ TreeTransform<Derived>::TransformBinaryO<br>
 template <typename Derived><br>
 ExprResult TreeTransform<Derived>::TransformCXXRewrittenBinaryOperator(<br>
     CXXRewrittenBinaryOperator *E) {<br>
-  // FIXME: C++ [temp.deduct]p7 "The substitution proceeds in lexical order and<br>
-  // stops when a condition that causes deduction to fail is encountered."<br>
-  // requires us to substitute into the LHS before the RHS, even in a rewrite<br>
-  // that reversed the operand order.<br>
-  //<br>
-  // We can't decompose back to a binary operator here, because that would lose<br>
-  // the unqualified lookup results from the phase 1 name lookup.<br>
+  CXXRewrittenBinaryOperator::DecomposedForm Decomp = E->getDecomposedForm();<br>
<br>
-  ExprResult SemanticForm = getDerived().TransformExpr(E->getSemanticForm());<br>
-  if (SemanticForm.isInvalid())<br>
+  ExprResult LHS = getDerived().TransformExpr(const_cast<Expr*>(Decomp.LHS));<br>
+  if (LHS.isInvalid())<br>
+    return ExprError();<br>
+<br>
+  ExprResult RHS = getDerived().TransformExpr(const_cast<Expr*>(Decomp.RHS));<br>
+  if (RHS.isInvalid())<br>
     return ExprError();<br>
<br>
   if (!getDerived().AlwaysRebuild() &&<br>
-      SemanticForm.get() == E->getSemanticForm())<br>
+      LHS.get() == Decomp.LHS &&<br>
+      RHS.get() == Decomp.RHS)<br>
     return E;<br>
<br>
-  return getDerived().RebuildCXXRewrittenBinaryOperator(SemanticForm.get(),<br>
-                                                      E->isReversed());<br>
+  // Extract the already-resolved callee declarations so that we can restrict<br>
+  // ourselves to using them as the unqualified lookup results when rebuilding.<br>
+  UnresolvedSet<2> UnqualLookups;<br>
+  Expr *PossibleBinOps[] = {E->getSemanticForm(),<br>
+                            const_cast<Expr *>(Decomp.InnerBinOp)};<br>
+  for (Expr *PossibleBinOp : PossibleBinOps) {<br>
+    auto *Op = dyn_cast<CXXOperatorCallExpr>(PossibleBinOp->IgnoreImplicit());<br>
+    if (!Op)<br>
+      continue;<br>
+    auto *Callee = dyn_cast<DeclRefExpr>(Op->getCallee()->IgnoreImplicit());<br>
+    if (!Callee || isa<CXXMethodDecl>(Callee->getDecl()))<br>
+      continue;<br>
+<br>
+    // Transform the callee in case we built a call to a local extern<br>
+    // declaration.<br>
+    NamedDecl *Found = cast_or_null<NamedDecl>(getDerived().TransformDecl(<br>
+        E->getOperatorLoc(), Callee->getFoundDecl()));<br>
+    if (!Found)<br>
+      return ExprError();<br>
+    UnqualLookups.addDecl(Found);<br>
+  }<br>
+<br>
+  return getDerived().RebuildCXXRewrittenBinaryOperator(<br>
+      E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get());<br>
 }<br>
<br>
 template<typename Derived><br>
<br>
Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp?rev=375306&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp?rev=375306&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp (added)<br>
+++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp Fri Oct 18 17:04:43 2019<br>
@@ -0,0 +1,172 @@<br>
+// RUN: %clang_cc1 -std=c++2a -verify %s<br>
+// RUN: %clang_cc1 -std=c++2a -verify -Wall -DNO_ERRORS %s<br>
+<br>
+#ifndef NO_ERRORS<br>
+namespace bullet3 {<br>
+  // the built-in candidates include all of the candidate operator fnuctions<br>
+  // [...] that, compared to the given operator<br>
+<br>
+  // - do not have the same parameter-type-list as any non-member candidate<br>
+<br>
+  enum E { e };<br>
+<br>
+  // Suppress both builtin operator<=>(E, E) and operator<(E, E).<br>
+  void operator<=>(E, E); // expected-note {{while rewriting}}<br>
+  bool cmp = e < e; // expected-error {{invalid operands to binary expression ('void' and 'int')}}<br>
+<br>
+  // None of the other bullets have anything to test here. In principle we<br>
+  // need to suppress both builtin operator@(A, B) and operator@(B, A) when we<br>
+  // see a user-declared reversible operator@(A, B), and we do, but that's<br>
+  // untestable because the only built-in reversible candidates are<br>
+  // operator<=>(E, E) and operator==(E, E) for E an enumeration type, and<br>
+  // those are both symmetric anyway.<br>
+}<br>
+<br>
+namespace bullet4 {<br>
+  // The rewritten candidate set is determined as follows:<br>
+<br>
+  template<int> struct X {};<br>
+  X<1> x1;<br>
+  X<2> x2;<br>
+<br>
+  struct Y {<br>
+    int operator<=>(X<2>) = delete; // #1member<br>
+    bool operator==(X<2>) = delete; // #2member<br>
+  };<br>
+  Y y;<br>
+<br>
+  // - For the relational operators, the rewritten candidates include all<br>
+  //   non-rewritten candidates for the expression x <=> y.<br>
+  int operator<=>(X<1>, X<2>) = delete; // #1<br>
+<br>
+  // expected-note@#1 5{{candidate function has been explicitly deleted}}<br>
+  // expected-note@#1 5{{candidate function (with reversed parameter order) not viable: no known conversion from 'X<1>' to 'X<2>' for 1st argument}}<br>
+  bool lt = x1 < x2; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool le = x1 <= x2; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool gt = x1 > x2; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool ge = x1 >= x2; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool cmp = x1 <=> x2; // expected-error {{selected deleted operator '<=>'}}<br>
+<br>
+  // expected-note@#1member 5{{candidate function has been explicitly deleted}}<br>
+  // expected-note@#1 5{{candidate function not viable: no known conversion from 'bullet4::Y' to 'X<1>' for 1st argument}}<br>
+  // expected-note@#1 5{{candidate function (with reversed parameter order) not viable: no known conversion from 'bullet4::Y' to 'X<2>' for 1st argument}}<br>
+  bool mem_lt = y < x2; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool mem_le = y <= x2; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool mem_gt = y > x2; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool mem_ge = y >= x2; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool mem_cmp = y <=> x2; // expected-error {{selected deleted operator '<=>'}}<br>
+<br>
+  // - For the relational and three-way comparison operators, the rewritten<br>
+  //   candidates also include a synthesized candidate, with the order of the<br>
+  //   two parameters reversed, for each non-rewritten candidate for the<br>
+  //   expression y <=> x.<br>
+<br>
+  // expected-note@#1 5{{candidate function (with reversed parameter order) has been explicitly deleted}}<br>
+  // expected-note@#1 5{{candidate function not viable: no known conversion from 'X<2>' to 'X<1>' for 1st argument}}<br>
+  bool rlt = x2 < x1; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool rle = x2 <= x1; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool rgt = x2 > x1; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool rge = x2 >= x1; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool rcmp = x2 <=> x1; // expected-error {{selected deleted operator '<=>'}}<br>
+<br>
+  // expected-note@#1member 5{{candidate function (with reversed parameter order) has been explicitly deleted}}<br>
+  // expected-note@#1 5{{candidate function not viable: no known conversion from 'X<2>' to 'X<1>' for 1st argument}}<br>
+  // expected-note@#1 5{{candidate function (with reversed parameter order) not viable: no known conversion from 'bullet4::Y' to 'X<1>' for 2nd argument}}<br>
+  bool mem_rlt = x2 < y; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool mem_rle = x2 <= y; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool mem_rgt = x2 > y; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool mem_rge = x2 >= y; // expected-error {{selected deleted operator '<=>'}}<br>
+  bool mem_rcmp = x2 <=> y; // expected-error {{selected deleted operator '<=>'}}<br>
+<br>
+  // For the != operator, the rewritten candidates include all non-rewritten<br>
+  // candidates for the expression x == y<br>
+  int operator==(X<1>, X<2>) = delete; // #2<br>
+<br>
+  // expected-note@#2 2{{candidate function has been explicitly deleted}}<br>
+  // expected-note@#2 2{{candidate function (with reversed parameter order) not viable: no known conversion from 'X<1>' to 'X<2>' for 1st argument}}<br>
+  bool eq = x1 == x2; // expected-error {{selected deleted operator '=='}}<br>
+  bool ne = x1 != x2; // expected-error {{selected deleted operator '=='}}<br>
+<br>
+  // expected-note@#2member 2{{candidate function has been explicitly deleted}}<br>
+  // expected-note@#2 2{{candidate function not viable: no known conversion from 'bullet4::Y' to 'X<1>' for 1st argument}}<br>
+  // expected-note@#2 2{{candidate function (with reversed parameter order) not viable: no known conversion from 'bullet4::Y' to 'X<2>' for 1st argument}}<br>
+  bool mem_eq = y == x2; // expected-error {{selected deleted operator '=='}}<br>
+  bool mem_ne = y != x2; // expected-error {{selected deleted operator '=='}}<br>
+<br>
+  // For the equality operators, the rewritten candidates also include a<br>
+  // synthesized candidate, with the order of the two parameters reversed, for<br>
+  // each non-rewritten candidate for the expression y == x<br>
+<br>
+  // expected-note@#2 2{{candidate function (with reversed parameter order) has been explicitly deleted}}<br>
+  // expected-note@#2 2{{candidate function not viable: no known conversion from 'X<2>' to 'X<1>' for 1st argument}}<br>
+  bool req = x2 == x1; // expected-error {{selected deleted operator '=='}}<br>
+  bool rne = x2 != x1; // expected-error {{selected deleted operator '=='}}<br>
+<br>
+  // expected-note@#2member 2{{candidate function (with reversed parameter order) has been explicitly deleted}}<br>
+  // expected-note@#2 2{{candidate function not viable: no known conversion from 'X<2>' to 'X<1>' for 1st argument}}<br>
+  // expected-note@#2 2{{candidate function (with reversed parameter order) not viable: no known conversion from 'bullet4::Y' to 'X<1>' for 2nd argument}}<br>
+  bool mem_req = x2 == y; // expected-error {{selected deleted operator '=='}}<br>
+  bool mem_rne = x2 != y; // expected-error {{selected deleted operator '=='}}<br>
+<br>
+  // For all other operators, the rewritten candidate set is empty.<br>
+  X<3> operator+(X<1>, X<2>) = delete; // expected-note {{no known conversion from 'X<2>' to 'X<1>'}}<br>
+  X<3> reversed_add = x2 + x1; // expected-error {{invalid operands}}<br>
+}<br>
+<br>
+// Various C++17 cases that are known to be broken by the C++20 rules.<br>
+namespace problem_cases {<br>
+  // We can have an ambiguity between an operator and its reversed form. This<br>
+  // wasn't intended by the original "consistent comparison" proposal, and we<br>
+  // allow it as extension, picking the non-reversed form.<br>
+  struct A {<br>
+    bool operator==(const A&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}<br>
+  };<br>
+  bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}<br>
+<br>
+  struct B {<br>
+    virtual bool operator==(const B&) const;<br>
+  };<br>
+  struct D : B {<br>
+    bool operator==(const B&) const override; // expected-note {{operator}}<br>
+  };<br>
+  bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}<br>
+<br>
+  template<typename T> struct CRTPBase {<br>
+    bool operator==(const T&) const; // expected-note {{operator}}<br>
+  };<br>
+  struct CRTP : CRTPBase<CRTP> {};<br>
+  bool cmp_crtp = CRTP() == CRTP(); // expected-warning {{ambiguous}}<br>
+<br>
+  // We can select a non-rewriteable operator== for a != comparison, when there<br>
+  // was a viable operator!= candidate we could have used instead.<br>
+  //<br>
+  // Rejecting this seems OK on balance.<br>
+  using UBool = signed char; // ICU uses this.<br>
+  struct ICUBase {<br>
+    virtual UBool operator==(const ICUBase&) const;<br>
+    UBool operator!=(const ICUBase &arg) const { return !operator==(arg); }<br>
+  };<br>
+  struct ICUDerived : ICUBase {<br>
+    UBool operator==(const ICUBase&) const override; // expected-note {{declared here}}<br>
+  };<br>
+  bool cmp_icu = ICUDerived() != ICUDerived(); // expected-error {{not 'bool'}}<br>
+}<br>
+<br>
+#else // NO_ERRORS<br>
+<br>
+namespace problem_cases {<br>
+  // We can select a reversed candidate where we used to select a non-reversed<br>
+  // one, and in the worst case this can dramatically change the meaning of the<br>
+  // program. Make sure we at least warn on the worst cases under -Wall.<br>
+  struct iterator;<br>
+  struct const_iterator {<br>
+    const_iterator(iterator);<br>
+    bool operator==(const const_iterator&) const;<br>
+  };<br>
+  struct iterator {<br>
+    bool operator==(const const_iterator &o) const { // expected-warning {{all paths through this function will call itself}}<br>
+      return o == *this;<br>
+    }<br>
+  };<br>
+}<br>
+#endif // NO_ERRORS<br>
<br>
Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p8-2a.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p8-2a.cpp?rev=375306&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p8-2a.cpp?rev=375306&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p8-2a.cpp (added)<br>
+++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p8-2a.cpp Fri Oct 18 17:04:43 2019<br>
@@ -0,0 +1,70 @@<br>
+// RUN: %clang_cc1 -std=c++2a -verify %s<br>
+<br>
+template<typename L, typename R> struct Op { L l; const char *op; R r; };<br>
+// FIXME: Remove once we implement P1816R0.<br>
+template<typename L, typename R> Op(L, R) -> Op<L, R>;<br>
+<br>
+struct A {};<br>
+struct B {};<br>
+constexpr Op<A, B> operator<=>(A a, B b) { return {a, "<=>", b}; }<br>
+<br>
+template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator<  (Op<T, U> a, V b) { return {a, "<",   b}; }<br>
+template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator<= (Op<T, U> a, V b) { return {a, "<=",  b}; }<br>
+template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator>  (Op<T, U> a, V b) { return {a, ">",   b}; }<br>
+template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator>= (Op<T, U> a, V b) { return {a, ">=",  b}; }<br>
+template<typename T, typename U, typename V> constexpr Op<Op<T, U>, V> operator<=>(Op<T, U> a, V b) { return {a, "<=>", b}; }<br>
+<br>
+template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator<  (T a, Op<U, V> b) { return {a, "<",   b}; }<br>
+template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator<= (T a, Op<U, V> b) { return {a, "<=",  b}; }<br>
+template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator>  (T a, Op<U, V> b) { return {a, ">",   b}; }<br>
+template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator>= (T a, Op<U, V> b) { return {a, ">=",  b}; }<br>
+template<typename T, typename U, typename V> constexpr Op<T, Op<U, V>> operator<=>(T a, Op<U, V> b) { return {a, "<=>", b}; }<br>
+<br>
+constexpr bool same(A, A) { return true; }<br>
+constexpr bool same(B, B) { return true; }<br>
+constexpr bool same(int a, int b) { return a == b; }<br>
+template<typename T, typename U><br>
+constexpr bool same(Op<T, U> x, Op<T, U> y) {<br>
+  return same(x.l, y.l) && __builtin_strcmp(x.op, y.op) == 0 && same(x.r, y.r);<br>
+}<br>
+<br>
+// x @ y is interpreted as:<br>
+void f(A x, B y) {<br>
+  //   --  (x <=> y) @ 0 if not reversed<br>
+  static_assert(same(x < y, (x <=> y) < 0));<br>
+  static_assert(same(x <= y, (x <=> y) <= 0));<br>
+  static_assert(same(x > y, (x <=> y) > 0));<br>
+  static_assert(same(x >= y, (x <=> y) >= 0));<br>
+  static_assert(same(x <=> y, x <=> y)); // (not rewritten)<br>
+}<br>
+<br>
+void g(B x, A y) {<br>
+  //   --  0 @ (y <=> x) if reversed<br>
+  static_assert(same(x < y, 0 < (y <=> x)));<br>
+  static_assert(same(x <= y, 0 <= (y <=> x)));<br>
+  static_assert(same(x > y, 0 > (y <=> x)));<br>
+  static_assert(same(x >= y, 0 >= (y <=> x)));<br>
+  static_assert(same(x <=> y, 0 <=> (y <=> x)));<br>
+}<br>
+<br>
+<br>
+// We can rewrite into a call involving a builtin operator.<br>
+struct X { int result; };<br>
+struct Y {};<br>
+constexpr int operator<=>(X x, Y) { return x.result; }<br>
+static_assert(X{-1} < Y{});<br>
+static_assert(X{0} < Y{}); // expected-error {{failed}}<br>
+static_assert(X{0} <= Y{});<br>
+static_assert(X{1} <= Y{}); // expected-error {{failed}}<br>
+static_assert(X{1} > Y{});<br>
+static_assert(X{0} > Y{}); // expected-error {{failed}}<br>
+static_assert(X{0} >= Y{});<br>
+static_assert(X{-1} >= Y{}); // expected-error {{failed}}<br>
+static_assert(Y{} < X{1});<br>
+static_assert(Y{} < X{0}); // expected-error {{failed}}<br>
+static_assert(Y{} <= X{0});<br>
+static_assert(Y{} <= X{-1}); // expected-error {{failed}}<br>
+static_assert(Y{} > X{-1});<br>
+static_assert(Y{} > X{0}); // expected-error {{failed}}<br>
+static_assert(Y{} >= X{0});<br>
+static_assert(Y{} >= X{1}); // expected-error {{failed}}<br>
<br>
Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p9-2a.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p9-2a.cpp?rev=375306&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p9-2a.cpp?rev=375306&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p9-2a.cpp (added)<br>
+++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.oper/p9-2a.cpp Fri Oct 18 17:04:43 2019<br>
@@ -0,0 +1,38 @@<br>
+// RUN: %clang_cc1 -std=c++2a -verify %s<br>
+<br>
+// ... return type shall be cv bool ...<br>
+namespace not_bool {<br>
+  struct X {} x;<br>
+  struct Y {} y;<br>
+  int operator==(X, Y); // expected-note 4{{here}}<br>
+  bool a = x == y; // ok<br>
+  bool b = y == x; // expected-error {{return type 'int' of selected 'operator==' function for rewritten '==' comparison is not 'bool'}}<br>
+  bool c = x != y; // expected-error {{return type 'int' of selected 'operator==' function for rewritten '!=' comparison is not 'bool'}}<br>
+  bool d = y != x; // expected-error {{return type 'int' of selected 'operator==' function for rewritten '!=' comparison is not 'bool'}}<br>
+<br>
+  // cv-qualifiers are OK<br>
+  const bool operator==(Y, X);<br>
+  bool e = y != x; // ok<br>
+<br>
+  // We don't prefer a function with bool return type over one witn non-bool return type.<br>
+  bool f = x != y; // expected-error {{return type 'int' of selected 'operator==' function for rewritten '!=' comparison is not 'bool'}}<br>
+}<br>
+<br>
+struct X { bool equal; };<br>
+struct Y {};<br>
+constexpr bool operator==(X x, Y) { return x.equal; }<br>
+<br>
+static_assert(X{true} == Y{});<br>
+static_assert(X{false} == Y{}); // expected-error {{failed}}<br>
+<br>
+// x == y -> y == x<br>
+static_assert(Y{} == X{true});<br>
+static_assert(Y{} == X{false}); // expected-error {{failed}}<br>
+<br>
+// x != y -> !(x == y)<br>
+static_assert(X{true} != Y{}); // expected-error {{failed}}<br>
+static_assert(X{false} != Y{});<br>
+<br>
+// x != y -> !(y == x)<br>
+static_assert(Y{} != X{true}); // expected-error {{failed}}<br>
+static_assert(Y{} != X{false});<br>
<br>
Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp (original)<br>
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp Fri Oct 18 17:04:43 2019<br>
@@ -1,4 +1,5 @@<br>
 // RUN: %clang_cc1 -std=c++11 -verify %s<br>
+// RUN: %clang_cc1 -std=c++2a -verify %s<br>
<br>
 struct Q { typedef int type; };<br>
<br>
@@ -20,3 +21,36 @@ template<typename T, template<typename T<br>
 int &c(...);<br>
 int &c_disabled = c(0);<br>
 int &c_enabled = c(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}<br>
+<br>
+// The substitution proceeds in lexical order and stops when a condition that<br>
+// causes deduction to fail is encountered.<br>
+#if __cplusplus > 201702L<br>
+namespace reversed_operator_substitution_order {<br>
+  struct X { X(int); };<br>
+  struct Y { Y(int); };<br>
+  struct Cat {};<br>
+  namespace no_adl {<br>
+    Cat operator<=>(Y, X);<br>
+    bool operator<(int, Cat);<br>
+<br>
+    template<typename T> struct indirect_sizeof {<br>
+      static_assert(sizeof(T) != 0);<br>
+      static const auto value = sizeof(T);<br>
+    };<br>
+<br>
+    // We should substitute into the construction of the X object before the<br>
+    // construction of the Y object, so this is a SFINAE case rather than a<br>
+    // hard error. This requires substitution to proceed in lexical order<br>
+    // despite the prior rewrite to<br>
+    //    0 < (Y(...) <=> X(...))<br>
+    template<typename T> float &f(<br>
+        decltype(<br>
+          X(sizeof(T)) < Y(indirect_sizeof<T>::value)<br>
+        )<br>
+    );<br>
+    template<typename T> int &f(...);<br>
+  }<br>
+  int &r = no_adl::f<void>(true);<br>
+  float &s = no_adl::f<int>(true);<br>
+}<br>
+#endif<br>
<br>
Added: cfe/trunk/test/CodeGenCXX/mangle-cxx2a.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-cxx2a.cpp?rev=375306&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-cxx2a.cpp?rev=375306&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/mangle-cxx2a.cpp (added)<br>
+++ cfe/trunk/test/CodeGenCXX/mangle-cxx2a.cpp Fri Oct 18 17:04:43 2019<br>
@@ -0,0 +1,11 @@<br>
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-linux-gnu -std=c++2a | FileCheck %s<br>
+<br>
+namespace spaceship {<br>
+  struct X {};<br>
+  struct Y {};<br>
+  int operator<=>(X, Y);<br>
+<br>
+  // CHECK-LABEL: define {{.*}} @_ZN9spaceship1fIiEEvDTcmltcvNS_1YE_EcvNS_1XE_EcvT__EE<br>
+  template<typename T> void f(decltype(Y() < X(), T()) x) {}<br>
+  template void f<int>(int);<br>
+}<br>
<br>
Modified: cfe/trunk/test/PCH/cxx2a-compare.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx2a-compare.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx2a-compare.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/PCH/cxx2a-compare.cpp (original)<br>
+++ cfe/trunk/test/PCH/cxx2a-compare.cpp Fri Oct 18 17:04:43 2019<br>
@@ -15,6 +15,16 @@ inline auto bar(int x) {<br>
   return (1 <=> x);<br>
 }<br>
<br>
+struct X {<br>
+  int a;<br>
+  friend constexpr std::strong_ordering operator<=>(const X &x, const X &y) {<br>
+    return x.a <=> y.a;<br>
+  }<br>
+};<br>
+constexpr auto baz(int x) {<br>
+  return X{3} < X{x};<br>
+}<br>
+<br>
 #else<br>
<br>
 // expected-no-diagnostics<br>
@@ -25,4 +35,7 @@ auto bar2(int x) {<br>
   return bar(x);<br>
 }<br>
<br>
+static_assert(!baz(3));<br>
+static_assert(baz(4));<br>
+<br>
 #endif<br>
<br>
Modified: cfe/trunk/test/SemaCXX/compare-cxx2a.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/compare-cxx2a.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/compare-cxx2a.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/compare-cxx2a.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/compare-cxx2a.cpp Fri Oct 18 17:04:43 2019<br>
@@ -298,11 +298,11 @@ void test_enum_enum_compare_no_builtin()<br>
<br>
 template <int><br>
 struct Tag {};<br>
-// expected-note@+1 {{candidate}}<br>
-Tag<0> operator<=>(EnumA, EnumA) {<br>
+Tag<0> operator<=>(EnumA, EnumA) { // expected-note {{not viable}}<br>
   return {};<br>
 }<br>
-Tag<1> operator<=>(EnumA, EnumB) {<br>
+// expected-note@+1 {{while rewriting comparison as call to 'operator<=>' declared here}}<br>
+Tag<1> operator<=>(EnumA, EnumB) { // expected-note {{not viable}}<br>
   return {};<br>
 }<br>
<br>
@@ -311,7 +311,7 @@ void test_enum_ovl_provided() {<br>
   ASSERT_EXPR_TYPE(r1, Tag<0>);<br>
   auto r2 = (EnumA::A <=> EnumB::B);<br>
   ASSERT_EXPR_TYPE(r2, Tag<1>);<br>
-  (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}}<br>
+  (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('int' and 'Tag<1>')}}<br>
 }<br>
<br>
 void enum_float_test() {<br>
<br>
Modified: cfe/trunk/test/SemaCXX/self-comparison.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/self-comparison.cpp?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/self-comparison.cpp?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/self-comparison.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/self-comparison.cpp Fri Oct 18 17:04:43 2019<br>
@@ -5,7 +5,7 @@ int foo(int x) {<br>
 }<br>
<br>
 struct X {<br>
-  bool operator==(const X &x);<br>
+  bool operator==(const X &x) const;<br>
 };<br>
<br>
 struct A {<br>
<br>
Modified: cfe/trunk/www/cxx_status.html<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=375306&r1=375305&r2=375306&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=375306&r1=375305&r2=375306&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/www/cxx_status.html (original)<br>
+++ cfe/trunk/www/cxx_status.html Fri Oct 18 17:04:43 2019<br>
@@ -920,23 +920,26 @@ as the draft C++2a standard evolves.<br>
     <tr><br>
       <td rowspan="6">Consistent comparison (<tt>operator&lt;=&gt;</tt>)</td><br>
       <td><a href="<a href="http://wg21.link/p0515r3" rel="noreferrer" target="_blank">http://wg21.link/p0515r3</a>">P0515R3</a></td><br>
-      <td rowspan="3" class="partial" align="center">Partial</td><br>
+      <td class="partial" align="center">Partial</td><br>
     </tr><br>
       <tr> <!-- from Jacksonville --><br>
         <td><a href="<a href="http://wg21.link/p0905r1" rel="noreferrer" target="_blank">http://wg21.link/p0905r1</a>">P0905R1</a></td><br>
+        <td class="svn" align="center">Clang 10</td><br>
       </tr><br>
       <tr> <!-- from Rapperswil --><br>
         <td><a href="<a href="http://wg21.link/p1120r0" rel="noreferrer" target="_blank">http://wg21.link/p1120r0</a>">P1120R0</a></td><br>
+        <td rowspan="2" class="partial" align="center">Partial</td><br>
       </tr><br>
       <tr> <!-- from Kona 2019 --><br>
         <td><a href="<a href="http://wg21.link/p1185r2" rel="noreferrer" target="_blank">http://wg21.link/p1185r2</a>">P1185R2</a></td><br>
-        <td rowspan="3" class="none" align="center">No</td><br>
       </tr><br>
       <tr> <!-- from Cologne --><br>
         <td><a href="<a href="http://wg21.link/p1186r3" rel="noreferrer" target="_blank">http://wg21.link/p1186r3</a>">P1186R3</a></td><br>
+        <td class="none" align="center">No</td><br>
       </tr><br>
       <tr><br>
         <td><a href="<a href="http://wg21.link/p1630r1" rel="noreferrer" target="_blank">http://wg21.link/p1630r1</a>">P1630R1</a></td><br>
+        <td class="partial" align="center">Partial</td><br>
       </tr><br>
     <tr><br>
       <td>Access checking on specializations</td><br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><div dir="ltr">-- <div>Peter</div></div></div></div>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><div dir="ltr">-- <div>Peter</div></div></div></div>