Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -886,6 +886,9 @@ setIsUnique(false); } + /// Create an OpaqueValueExpr representing the specified source expression + static OpaqueValueExpr *Create(const ASTContext &Ctx, Expr *Source); + /// Given an expression which invokes a copy constructor --- i.e. a /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups --- /// find the OpaqueValueExpr that's the source of the construction. Index: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -87,6 +87,8 @@ SourceRange getSourceRangeImpl() const LLVM_READONLY; public: + friend class ASTReader; + friend class ASTWriter; friend class ASTStmtReader; friend class ASTStmtWriter; @@ -4207,6 +4209,71 @@ child_range children() { return child_range(SubExprs, SubExprs + 2); } }; +class CXXRewrittenExpr : public Expr { + +public: + enum RewrittenKind { Comparison }; + + struct ComparisonBits { + /// Whether this rewritten comparison expression has reverse-order + /// parameters. + unsigned IsSynthesized : 1; + }; + + union ExtraRewrittenBits { + ComparisonBits CompareBits; + }; + +private: + friend class ASTReader; + friend class ASTStmtReader; + friend class ASTStmtWriter; + + Stmt *SubExprs[2]; + ExtraRewrittenBits ExtraBits; + + CXXRewrittenExpr(EmptyShell Empty) : Expr(CXXRewrittenExprClass, Empty) {} + +public: + CXXRewrittenExpr(RewrittenKind Kind, Expr *Original, Expr *Rewritten, + ExtraRewrittenBits ExtraBits) + : Expr(CXXRewrittenExprClass, Rewritten->getType(), + Rewritten->getValueKind(), Rewritten->getObjectKind(), + /*Dependent*/ Rewritten->isTypeDependent(), + Rewritten->isValueDependent(), + Original->isInstantiationDependent(), + Rewritten->containsUnexpandedParameterPack()), + ExtraBits(ExtraBits) { + SubExprs[0] = Original; + SubExprs[1] = Rewritten; + } + + RewrittenKind getRewrittenKind() const { + return static_cast(CXXRewrittenBits.Kind); + } + void setRewrittenKind(RewrittenKind Kind) { CXXRewrittenBits.Kind = Kind; } + + ExtraRewrittenBits *getRewrittenInfo() { return &ExtraBits; } + const ExtraRewrittenBits *getRewrittenInfo() const { return &ExtraBits; } + + Expr *getOriginalExpr() const { return static_cast(SubExprs[0]); } + Expr *getRewrittenExpr() const { + return static_cast(SubExprs[1]); + } + + SourceLocation getLocStart() const { + return getOriginalExpr()->getLocStart(); + } + SourceLocation getLocEnd() const { return getOriginalExpr()->getLocEnd(); } + SourceLocation getExprLoc() const { return getOriginalExpr()->getExprLoc(); } + + child_range children() { return child_range(SubExprs, SubExprs + 2); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXRewrittenExprClass; + } +}; + /// \brief Represents an expression that might suspend coroutine execution; /// either a co_await or co_yield expression. /// Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2549,6 +2549,14 @@ DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) +DEF_TRAVERSE_STMT(CXXRewrittenExpr, { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOriginalExpr()); + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRewrittenExpr()); + } + ShouldVisitChildren = false; +}) + // For coroutines expressions, traverse either the operand // as written or the implied calls, depending on what the // derived class requests. Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -246,6 +246,13 @@ /// bit is set to true. unsigned IsUnique : 1; }; + class CXXRewrittenExprBitfields { + friend class CXXRewrittenExpr; + + unsigned : NumExprBits; + + unsigned Kind : 1; + }; class ObjCIndirectCopyRestoreExprBitfields { friend class ObjCIndirectCopyRestoreExpr; @@ -309,6 +316,7 @@ InitListExprBitfields InitListExprBits; TypeTraitExprBitfields TypeTraitExprBits; CoawaitExprBitfields CoawaitBits; + CXXRewrittenExprBitfields CXXRewrittenBits; }; public: Index: include/clang/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -146,6 +146,7 @@ def MaterializeTemporaryExpr : DStmt; def LambdaExpr : DStmt; def CXXFoldExpr : DStmt; +def CXXRewrittenExpr : DStmt; // C++ Coroutines TS expressions def CoroutineSuspendExpr : DStmt; Index: include/clang/Sema/Overload.h =================================================================== --- include/clang/Sema/Overload.h +++ include/clang/Sema/Overload.h @@ -72,6 +72,17 @@ OCD_ViableCandidates }; + /// OperatorOverloadCandidateKind - The kind of the operator candidate in + /// accordance with [over.match.oper]. + enum RewrittenOverloadCandidateKind : unsigned char { + /// Not a rewritten candidate. + ROC_None, + /// Rewritten but not synthesized. + ROC_Rewritten, + /// Both rewritten and synthesized. + ROC_Synthesized + }; + /// ImplicitConversionKind - The kind of implicit conversion used to /// convert an argument to a parameter's type. The enumerator values /// match with the table titled 'Conversions' in [over.ics.scs] and are listed @@ -755,12 +766,12 @@ ConversionFixItGenerator Fix; /// Viable - True to indicate that this overload candidate is viable. - bool Viable; + bool Viable : 1; /// IsSurrogate - True to indicate that this candidate is a /// surrogate for a conversion to a function pointer or reference /// (C++ [over.call.object]). - bool IsSurrogate; + bool IsSurrogate : 1; /// IgnoreObjectArgument - True to indicate that the first /// argument's conversion, which for this function represents the @@ -769,7 +780,11 @@ /// implicit object argument is just a placeholder) or a /// non-static member function when the call doesn't have an /// object argument. - bool IgnoreObjectArgument; + bool IgnoreObjectArgument : 1; + + /// RewrittenKind - For rewritten operator candidates, the kind of rewritten + /// candidate it is: rewritten or synthesized. + unsigned char RewrittenOpKind : 2; /// FailureKind - The reason why this candidate is not viable. /// Actually an OverloadFailureKind. @@ -812,6 +827,24 @@ return CanFix; } + /// \brief Return the index of the conversion corresponding to the specified + /// argument index. If this is not a synthesized candidate, 'Idx' is + /// returned. Otherwise the index corresponding to the reversed parameter + /// is returned. + unsigned getConversionIndexForArgIndex(unsigned Idx) const; + + /// \brief Return the conversion sequence for the specified argument index. + /// If this is a synthesized candidate, the argument index is reversed. + const ImplicitConversionSequence &getConversion(unsigned ArgIdx) const; + + /// \brief Returns the parameter type corresponding to the specified index. + /// (The index is not reversed for synthesized candidates). + QualType getParamType(unsigned Idx) const { + if (Function) + return Function->getParamDecl(Idx)->getType(); + return BuiltinParamTypes[Idx]; + } + unsigned getNumParams() const { if (IsSurrogate) { auto STy = Surrogate->getConversionType(); @@ -823,6 +856,10 @@ return Function->getNumParams(); return ExplicitCallArguments; } + + RewrittenOverloadCandidateKind getRewrittenKind() const { + return static_cast(RewrittenOpKind); + } }; /// OverloadCandidateSet - A set of overload candidates, used in C++ @@ -853,8 +890,10 @@ private: SmallVector Candidates; - llvm::SmallPtrSet Functions; + using DeclSet = llvm::SmallPtrSet; + DeclSet Functions; + private: // Allocator for ConversionSequenceLists. We store the first few of these // inline to avoid allocation for small sets. llvm::BumpPtrAllocator SlabAllocator; @@ -896,6 +935,31 @@ void destroyCandidates(); public: + /// \brief RewrittenCandidateContextGuard - Enter a context suitable for + /// adding rewritten overload candidates. Rewritten candidates can + /// re-consider previously seen functions, so save and clear the list of + /// considered functions, and restore it when the rewritten context is + /// exited. + struct RewrittenCandidateContextGuard { + RewrittenCandidateContextGuard(OverloadCandidateSet &CS) + : CandidateSet(CS) { + assert(CS.Kind == CSK_Operator && + "rewritten expressions can only occur for operators"); + OldFunctions = std::move(CandidateSet.Functions); + } + + ~RewrittenCandidateContextGuard() { + CandidateSet.Functions.insert(OldFunctions.begin(), OldFunctions.end()); + } + + private: + OverloadCandidateSet &CandidateSet; + DeclSet OldFunctions; + }; + + friend struct RewrittenCandidateContextGuard; + + public: OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK) : Loc(Loc), Kind(CSK) {} OverloadCandidateSet(const OverloadCandidateSet &) = delete; @@ -952,8 +1016,9 @@ } /// Find the best viable function on this overload set, if it exists. - OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, - OverloadCandidateSet::iterator& Best); + OverloadingResult BestViableFunction( + Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator &Best, + SmallVectorImpl *EquivalentCands = nullptr); void NoteCandidates(Sema &S, OverloadCandidateDisplayKind OCD, Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2784,7 +2784,12 @@ TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); - + void AddRewrittenOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, + ArrayRef InputArgs, + const UnresolvedSetImpl &Fns, + OverloadCandidateSet &CandidateSet, + bool PerformADL); // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, QualType DestType = QualType(), @@ -2920,16 +2925,21 @@ const UnresolvedSetImpl &Fns, Expr *input, bool RequiresADL = true); - ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, - BinaryOperatorKind Opc, - const UnresolvedSetImpl &Fns, - Expr *LHS, Expr *RHS, - bool RequiresADL = true); + ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, + const UnresolvedSetImpl &Fns, Expr *LHS, + Expr *RHS, bool RequiresADL = true, + bool AllowRewrittenCandidates = true); ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, Expr *Base,Expr *Idx); + ExprResult BuildBinaryOperatorCandidate(SourceLocation OpLoc, + BinaryOperatorKind Opc, + const OverloadCandidate &Ovl, + Expr *LHS, Expr *RHS, + bool HadMultipleCandidates); + ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -1811,6 +1811,7 @@ EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr EXPR_CXX_FOLD, // CXXFoldExpr + EXPR_CXX_REWRITTEN_OPERATOR, // CXXRewrittenExpr // CUDA EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -3187,6 +3187,11 @@ return false; } + case CXXRewrittenExprClass: { + const auto *RO = cast(this); + return RO->getRewrittenExpr()->HasSideEffects(Ctx, IncludePossibleEffects); + } + case PseudoObjectExprClass: { // Only look for side-effects in the semantic form, and look past // OpaqueValueExpr bindings in that form. @@ -3897,6 +3902,11 @@ } } +OpaqueValueExpr *OpaqueValueExpr::Create(const ASTContext &Ctx, Expr *E) { + return new (Ctx) OpaqueValueExpr(E->getExprLoc(), E->getType(), + E->getValueKind(), E->getObjectKind(), E); +} + const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { if (const ExprWithCleanups *ewc = dyn_cast(e)) e = ewc->getSubExpr(); Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -287,7 +287,8 @@ if (cast(E)->isResultDependent()) return Cl::CL_PRValue; return ClassifyInternal(Ctx,cast(E)->getResultExpr()); - + case Expr::CXXRewrittenExprClass: + return ClassifyInternal(Ctx, cast(E)->getRewrittenExpr()); case Expr::BinaryOperatorClass: case Expr::CompoundAssignOperatorClass: // C doesn't have any binary expressions that are lvalues. Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -5059,6 +5059,10 @@ return; VisitIgnoredValue(E); } + + bool VisitCXXRewrittenExpr(const CXXRewrittenExpr *E) { + return StmtVisitorTy::Visit(E->getRewrittenExpr()); + } }; } // namespace @@ -10858,6 +10862,8 @@ case Expr::ChooseExprClass: { return CheckICE(cast(E)->getChosenSubExpr(), Ctx); } + case Expr::CXXRewrittenExprClass: + return CheckICE(cast(E)->getRewrittenExpr(), Ctx); } llvm_unreachable("Invalid StmtClass!"); Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -3516,9 +3516,13 @@ } // These are used for internal purposes and cannot be meaningfully mangled. - case Expr::OpaqueValueExprClass: - llvm_unreachable("cannot mangle opaque value; mangling wrong thing?"); - + case Expr::OpaqueValueExprClass: { + const OpaqueValueExpr *OVE = cast(E); + assert(OVE->getSourceExpr() && "cannot mangle opaque value without a " + "source expression; mangling wrong thing?"); + mangleExpression(OVE->getSourceExpr()); + break; + } case Expr::InitListExprClass: { Out << "il"; mangleInitListElements(cast(E)); @@ -3559,6 +3563,10 @@ mangleExpression(cast(E)->getSubExpr(), Arity); break; + case Expr::CXXRewrittenExprClass: + mangleExpression(cast(E)->getOriginalExpr(), Arity); + break; + case Expr::SubstNonTypeTemplateParmExprClass: mangleExpression(cast(E)->getReplacement(), Arity); Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -2588,6 +2588,13 @@ OS << ")"; } +void StmtPrinter::VisitCXXRewrittenExpr(CXXRewrittenExpr *E) { + // FIXME(EricWF): Are there ever cases where we want to display the rewritten + // code? For example when producing diagnostics on implicitly generated + // expressions? + Visit(E->getOriginalExpr()); +} + // C++ Coroutines TS void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -1816,6 +1816,11 @@ ID.AddInteger(S->getOperator()); } +void StmtProfiler::VisitCXXRewrittenExpr(const CXXRewrittenExpr *S) { + VisitExpr(S); + VisitExpr(S->getRewrittenExpr()); +} + void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) { VisitStmt(S); } Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -541,6 +541,10 @@ return EmitScalarPrePostIncDec(E, LV, true, true); } + Value *VisitCXXRewrittenExpr(const CXXRewrittenExpr *E) { + return Visit(E->getRewrittenExpr()); + } + llvm::Value *EmitIncDecConsiderOverflowBehavior(const UnaryOperator *E, llvm::Value *InVal, bool IsInc); Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -1174,6 +1174,9 @@ case Expr::VAArgExprClass: return canSubExprsThrow(*this, E); + case Expr::CXXRewrittenExprClass: + return canThrow(cast(E)->getRewrittenExpr()); + // Some might be dependent for other reasons. case Expr::ArraySubscriptExprClass: case Expr::OMPArraySectionExprClass: Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12372,7 +12372,12 @@ if (Sc && OverOp != OO_None && OverOp != OO_Equal) S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(), RHS->getType(), Functions); - + if (S.getLangOpts().CPlusPlus2a) { + if (Sc && Opc != BO_Cmp && BinaryOperator::isRelationalOp(Opc)) { + S.LookupOverloadedOperatorName(OO_Spaceship, Sc, LHS->getType(), + RHS->getType(), Functions); + } + } // Build the (potentially-overloaded, potentially-dependent) // binary operation. return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS); Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -831,6 +831,19 @@ } } +const ImplicitConversionSequence & +OverloadCandidate::getConversion(unsigned ArgIdx) const { + return Conversions[getConversionIndexForArgIndex(ArgIdx)]; +} + +unsigned OverloadCandidate::getConversionIndexForArgIndex(unsigned Idx) const { + if (getRewrittenKind() != ROC_Synthesized) + return Idx; + // FIXME(EricWF): Handle these cases. + assert(Idx < 2); + return Idx == 0 ? 1 : 0; +} + void OverloadCandidateSet::destroyCandidates() { for (iterator i = begin(), e = end(); i != e; ++i) { for (auto &C : i->Conversions) @@ -5942,13 +5955,15 @@ // (possibly cv-qualified) T2", when T2 is an enumeration type, are // candidate functions. if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator && - !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args)) + !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args)) { return; + } // C++11 [class.copy]p11: [DR1402] // A defaulted move constructor that is defined as deleted is ignored by // overload resolution. CXXConstructorDecl *Constructor = dyn_cast(Function); + if (Constructor && Constructor->isDefaulted() && Constructor->isDeleted() && Constructor->isMoveConstructor()) return; @@ -5964,6 +5979,7 @@ Candidate.Function = Function; Candidate.Viable = true; Candidate.IsSurrogate = false; + Candidate.RewrittenOpKind = ROC_None; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); @@ -6654,6 +6670,7 @@ Candidate.Function = MethodTmpl->getTemplatedDecl(); Candidate.Viable = false; Candidate.IsSurrogate = false; + Candidate.RewrittenOpKind = ROC_None; Candidate.IgnoreObjectArgument = cast(Candidate.Function)->isStatic() || ObjectType.isNull(); @@ -6718,6 +6735,7 @@ Candidate.Function = FunctionTemplate->getTemplatedDecl(); Candidate.Viable = false; Candidate.IsSurrogate = false; + Candidate.RewrittenOpKind = ROC_None; // Ignore the object argument if there is one, since we don't have an object // type. Candidate.IgnoreObjectArgument = @@ -6889,6 +6907,7 @@ Candidate.FoundDecl = FoundDecl; Candidate.Function = Conversion; Candidate.IsSurrogate = false; + Candidate.RewrittenOpKind = ROC_None; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); Candidate.FinalConversion.setFromType(ConvType); @@ -7050,6 +7069,7 @@ Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; + Candidate.RewrittenOpKind = ROC_None; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = 1; Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, @@ -7090,6 +7110,7 @@ Candidate.Surrogate = Conversion; Candidate.Viable = true; Candidate.IsSurrogate = true; + Candidate.RewrittenOpKind = ROC_None; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); @@ -7247,6 +7268,7 @@ Candidate.FoundDecl = DeclAccessPair::make(nullptr, AS_none); Candidate.Function = nullptr; Candidate.IsSurrogate = false; + Candidate.RewrittenOpKind = ROC_None; Candidate.IgnoreObjectArgument = false; std::copy(ParamTys, ParamTys + Args.size(), Candidate.BuiltinParamTypes); @@ -8862,6 +8884,67 @@ } } +/// Add the rewritten and synthesized candidates for binary comparison +/// operators. No additional semantic checking is done to see if the candidate +/// is well formed. +void Sema::AddRewrittenOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, + ArrayRef InputArgs, + const UnresolvedSetImpl &Fns, + OverloadCandidateSet &CandidateSet, + bool PerformADL) { + auto Opc = BinaryOperator::getOverloadedOpcode(Op); + + bool IsRelationalOrEquality = + BinaryOperator::isRelationalOp(Opc) || BinaryOperator::isEqualityOp(Opc); + if (!IsRelationalOrEquality && Opc != BO_Cmp) + return; + assert(InputArgs.size() == 2); + + OverloadedOperatorKind CmpOp = OO_Spaceship; + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(CmpOp); + + // AddCandidates - Add operator<=> candidates for the specified set of args, + // and mark all newly generated candidates as having the specified + // 'RewrittenOverloadCandidateKind'. + auto AddCandidates = [&](ArrayRef Args, + RewrittenOverloadCandidateKind Kind) { + OverloadCandidateSet::RewrittenCandidateContextGuard Guard(CandidateSet); + + unsigned InitialSize = CandidateSet.size(); + AddFunctionCandidates(Fns, Args, CandidateSet); + AddMemberOperatorCandidates(CmpOp, OpLoc, Args, CandidateSet); + if (PerformADL) + AddArgumentDependentLookupCandidates(OpName, OpLoc, Args, + /*ExplicitTemplateArgs*/ nullptr, + CandidateSet); + AddBuiltinOperatorCandidates(CmpOp, OpLoc, Args, CandidateSet); + + for (auto It = std::next(CandidateSet.begin(), InitialSize); + It != CandidateSet.end(); ++It) { + OverloadCandidate &Ovl = *It; + Ovl.RewrittenOpKind = Kind; + } + }; + + // If we have a relational or equality operation, add the rewritten candidates + // of the form: (LHS <=> RHS) @ 0 + if (IsRelationalOrEquality) + AddCandidates(InputArgs, ROC_Rewritten); + + // TODO: We should be able to avoid adding synthesized candidates when LHS and + // RHS have the same type, value category, and other relevent properties. + // In that case synthesized candidates for <=> should be the same as the + // rewritten ones. Note: It's still possible for the result of operator<=> to + // be usable only on the left or right side of the expression (0 @ ) + // or ( @ 0). + + // For relational, equality, and three-way comparisons, add the rewritten and + // synthesized candidates of the form: 0 @ (RHS <=> LHS) + SmallVector ReverseArgs(InputArgs.rbegin(), InputArgs.rend()); + AddCandidates(ReverseArgs, ROC_Synthesized); +} + /// \brief Add function candidates found via argument-dependent lookup /// to the set of overloading candidates. /// @@ -8869,13 +8952,10 @@ /// given function name (which may also be an operator name) and adds /// all of the overload candidates found by ADL to the overload /// candidate set (C++ [basic.lookup.argdep]). -void -Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, - SourceLocation Loc, - ArrayRef Args, +void Sema::AddArgumentDependentLookupCandidates( + DeclarationName Name, SourceLocation Loc, ArrayRef Args, TemplateArgumentListInfo *ExplicitTemplateArgs, - OverloadCandidateSet& CandidateSet, - bool PartialOverloading) { + OverloadCandidateSet &CandidateSet, bool PartialOverloading) { ADLResult Fns; // FIXME: This approach for uniquing ADL results (and removing @@ -9008,8 +9088,8 @@ assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch"); bool HasBetterConversion = false; for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { - bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]); - bool Cand2Bad = IsIllFormedConversion(Cand2.Conversions[ArgIdx]); + bool Cand1Bad = IsIllFormedConversion(Cand1.getConversion(ArgIdx)); + bool Cand2Bad = IsIllFormedConversion(Cand2.getConversion(ArgIdx)); if (Cand1Bad != Cand2Bad) { if (Cand1Bad) return false; @@ -9026,8 +9106,8 @@ // conversion sequence than ICSi(F2), and then... for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { switch (CompareImplicitConversionSequences(S, Loc, - Cand1.Conversions[ArgIdx], - Cand2.Conversions[ArgIdx])) { + Cand1.getConversion(ArgIdx), + Cand2.getConversion(ArgIdx))) { case ImplicitConversionSequence::Better: // Cand1 has a better conversion sequence. HasBetterConversion = true; @@ -9133,6 +9213,48 @@ // Inherited from sibling base classes: still ambiguous. } + // Check C++2a tie-breakers for rewritten candidates + { + // --- F2 is a rewritten candidate ([over.match.oper]) and F1 is not. + RewrittenOverloadCandidateKind C1Roc = Cand1.getRewrittenKind(); + RewrittenOverloadCandidateKind C2Roc = Cand2.getRewrittenKind(); + if (C1Roc || C2Roc) { + if (!C1Roc || !C2Roc) + return !C1Roc; + // --- F1 and F2 are rewritten candidates, and F2 is a synthesized + // candidate with reversed order of parameters and F1 is not. + if ((C1Roc == ROC_Synthesized || C2Roc == ROC_Synthesized) && + C1Roc != C2Roc) { + auto GetParamTypes = [&](const OverloadCandidate &Ovl) { + SmallVector Types; + // If the candidate is a method, compute the implicit object type. + if (const auto *MD = dyn_cast_or_null(Ovl.Function)) { + assert(Ovl.Conversions[0].isStandard()); + QualType Ty = Ovl.Conversions[0].Standard.getToType(2); + assert(!Ty->isReferenceType()); + const auto *FTP = MD->getType()->getAs(); + switch (FTP->getRefQualifier()) { + case RQ_LValue: + case RQ_None: + Types.push_back(S.Context.getLValueReferenceType(Ty)); + break; + case RQ_RValue: + Types.push_back(S.Context.getRValueReferenceType(Ty)); + break; + } + } + for (unsigned I = 0; I < Ovl.getNumParams(); ++I) + Types.push_back(Ovl.getParamType(I).getCanonicalType()); + if (Ovl.getRewrittenKind() == ROC_Synthesized) + llvm::reverse(Types); + return Types; + }; + if (GetParamTypes(Cand1) == GetParamTypes(Cand2)) + return C2Roc == ROC_Synthesized; + } + } + } + // Check C++17 tie-breakers for deduction guides. { auto *Guide1 = dyn_cast_or_null(Cand1.Function); @@ -9245,9 +9367,9 @@ /// function, \p Best points to the candidate function found. /// /// \returns The result of overload resolution. -OverloadingResult -OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, - iterator &Best) { +OverloadingResult OverloadCandidateSet::BestViableFunction( + Sema &S, SourceLocation Loc, iterator &Best, + SmallVectorImpl *EquivalentCands) { llvm::SmallVector Candidates; std::transform(begin(), end(), std::back_inserter(Candidates), [](OverloadCandidate &Cand) { return &Cand; }); @@ -9289,23 +9411,32 @@ if (Best == end()) return OR_No_Viable_Function; - llvm::SmallVector EquivalentCands; - + llvm::SmallVector EquivalentFunctionCands; + if (EquivalentCands) + EquivalentCands->push_back(&(*Best)); // Make sure that this function is better than every other viable // function. If not, we have an ambiguity. for (auto *Cand : Candidates) { if (Cand->Viable && Cand != Best && !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) { + if (EquivalentCands) + EquivalentCands->push_back(Cand); if (S.isEquivalentInternalLinkageDeclaration(Best->Function, Cand->Function)) { - EquivalentCands.push_back(Cand->Function); + EquivalentFunctionCands.push_back(Cand->Function); continue; } + if (EquivalentCands) + continue; Best = end(); return OR_Ambiguous; } } + if (EquivalentCands && EquivalentCands->size() > 1) { + Best = end(); + return OR_Ambiguous; + } // Best is the best viable function. if (Best->Function && @@ -9313,9 +9444,9 @@ S.isFunctionConsideredUnavailable(Best->Function))) return OR_Deleted; - if (!EquivalentCands.empty()) + if (!EquivalentFunctionCands.empty()) S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, - EquivalentCands); + EquivalentFunctionCands); return OR_Success; } @@ -12228,6 +12359,325 @@ return CreateBuiltinUnaryOp(OpLoc, Opc, Input); } +ExprResult Sema::BuildBinaryOperatorCandidate(SourceLocation OpLoc, + BinaryOperatorKind Opc, + const OverloadCandidate &Ovl, + Expr *LHSE, Expr *RHSE, + bool HadMultipleCandidates) { + Expr *Args[2] = {LHSE, RHSE}; + OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc); + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Ovl.Function; + + if (FnDecl) { + Expr *Base = nullptr; + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { + // Ovl.Access is only meaningful for class members. + CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Ovl.FoundDecl); + + ExprResult Arg1 = + PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, FnDecl->getParamDecl(0)), + SourceLocation(), Args[1]); + if (Arg1.isInvalid()) + return ExprError(); + + ExprResult Arg0 = PerformObjectArgumentInitialization( + Args[0], /*Qualifier=*/nullptr, Ovl.FoundDecl, Method); + if (Arg0.isInvalid()) + return ExprError(); + Base = Args[0] = Arg0.getAs(); + Args[1] = Arg1.getAs(); + } else { + // Convert the arguments. + ExprResult Arg0 = + PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, FnDecl->getParamDecl(0)), + SourceLocation(), Args[0]); + if (Arg0.isInvalid()) + return ExprError(); + + ExprResult Arg1 = + PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, FnDecl->getParamDecl(1)), + SourceLocation(), Args[1]); + if (Arg1.isInvalid()) + return ExprError(); + Args[0] = Arg0.getAs(); + Args[1] = Arg1.getAs(); + } + + // Build the actual expression node. + ExprResult FnExpr = CreateFunctionRefExpr( + *this, FnDecl, Ovl.FoundDecl, Base, HadMultipleCandidates, OpLoc); + if (FnExpr.isInvalid()) + return ExprError(); + + // Determine the result type. + QualType ResultTy = FnDecl->getReturnType(); + ExprValueKind VK = Expr::getValueKindForType(ResultTy); + ResultTy = ResultTy.getNonLValueExprType(Context); + + CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr( + Context, Op, FnExpr.get(), Args, ResultTy, VK, OpLoc, FPFeatures); + + if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) + return ExprError(); + + ArrayRef ArgsArray(Args, 2); + const Expr *ImplicitThis = nullptr; + // Cut off the implicit 'this'. + if (isa(FnDecl)) { + ImplicitThis = ArgsArray[0]; + ArgsArray = ArgsArray.slice(1); + } + + // Check for a self move. + if (Op == OO_Equal) + DiagnoseSelfMove(Args[0], Args[1], OpLoc); + + checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray, + isa(FnDecl), OpLoc, TheCall->getSourceRange(), + Sema::VariadicDoesNotApply); + + return MaybeBindToTemporary(TheCall); + + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + ExprResult ArgsRes0 = + PerformImplicitConversion(Args[0], Ovl.BuiltinParamTypes[0], + Ovl.Conversions[0], Sema::AA_Passing); + if (ArgsRes0.isInvalid()) + return ExprError(); + Args[0] = ArgsRes0.get(); + + ExprResult ArgsRes1 = + PerformImplicitConversion(Args[1], Ovl.BuiltinParamTypes[1], + Ovl.Conversions[1], Sema::AA_Passing); + if (ArgsRes1.isInvalid()) + return ExprError(); + Args[1] = ArgsRes1.get(); + } + // We matched a built-in operator; build it. + return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); +} + +namespace { + +/// \brief RewrittenOverloadResolver - This class handles initial +/// overload resolution for candidate sets which include rewritten candidates. +/// +/// Rewritten candidates haven't been fully checked for validity. They may still +/// be invalid if: +/// (A) The rewritten candidate is a builtin, but semantic checking of the +/// builtin would fail. +/// (B) The result of the "partially rewritten expression" +/// (ie the (LHS <=> RHS) part) is ill-formed when used as an operand to +/// ( @ 0) or (0 @ ). +/// +/// TODO: Separate out the bits of semantic checking for builtin spaceship +/// operators which determine validity and the return type, and use that instead +/// of building the full expression to check validity. +class RewrittenOverloadResolver { + enum CheckOverloadResult { Done, Continue }; + +public: + RewrittenOverloadResolver(Sema &S, SourceLocation OpLoc, + BinaryOperatorKind Opc, ArrayRef Args, + const UnresolvedSetImpl &Fns, bool PerformADL, + OverloadCandidateSet &CS) + : S(S), OpLoc(OpLoc), Opc(Opc), Args(Args), Fns(Fns), + PerformADL(PerformADL), CandidateSet(CS) {} + + ExprResult ResolveRewrittenCandidates() { + ExprResult FinalResult = ExprError(); + OverloadCandidateSet::iterator Best; + OverloadingResult OvlRes; + llvm::SmallVector EquivCands; + do { + EquivCands.clear(); + OvlRes = CandidateSet.BestViableFunction(S, OpLoc, Best, &EquivCands); + } while (Continue == RemoveNonViableRewrittenCandidates( + OvlRes, Best, EquivCands, FinalResult)); + return FinalResult; + } +private: + CheckOverloadResult RemoveNonViableRewrittenCandidates( + OverloadingResult OvlRes, OverloadCandidateSet::iterator Best, + ArrayRef EquivCands, ExprResult &FinalResult); + ExprResult BuildRewrittenCandidate(const OverloadCandidate &Ovl); + + RewrittenOverloadResolver(RewrittenOverloadResolver const &) = delete; + RewrittenOverloadResolver & + operator=(RewrittenOverloadResolver const &) = delete; + +private: + Sema &S; + SourceLocation OpLoc; + BinaryOperatorKind Opc; + ArrayRef Args; + const UnresolvedSetImpl &Fns; + bool PerformADL; + OverloadCandidateSet &CandidateSet; +}; +} // end namespace + +ExprResult RewrittenOverloadResolver::BuildRewrittenCandidate( + const OverloadCandidate &Ovl) { + Expr *RewrittenArgs[2] = {Args[0], Args[1]}; + assert(Ovl.getRewrittenKind()); + bool IsSynthesized = Ovl.getRewrittenKind() == ROC_Synthesized; + if (IsSynthesized) + std::swap(RewrittenArgs[0], RewrittenArgs[1]); + + // Supress diagnostics when building the expressions for the specified + // candidate. If evaluation fails the candidate will be marked non-viable + // and the best viable candidate re-computed. + Sema::TentativeAnalysisScope DiagnosticScopeGuard(S); + + // Build the '(LHS <=> RHS)' operand to the full expression. + ExprResult RewrittenRes = S.BuildBinaryOperatorCandidate( + OpLoc, BO_Cmp, Ovl, RewrittenArgs[0], RewrittenArgs[1], + /*HadMultipleCandidates*/ false); + if (RewrittenRes.isInvalid()) + return ExprError(); + + if (Opc != BO_Cmp) { + // Now attempt to build the full expression '(LHS <=> RHS) @ 0' using the + // evaluated operand and the literal 0. + llvm::APInt I = + llvm::APInt::getNullValue(S.Context.getIntWidth(S.Context.IntTy)); + Expr *Zero = + IntegerLiteral::Create(S.Context, I, S.Context.IntTy, SourceLocation()); + + Expr *NewLHS = RewrittenRes.get(); + Expr *NewRHS = Zero; + if (Ovl.getRewrittenKind() == ROC_Synthesized) + std::swap(NewLHS, NewRHS); + + RewrittenRes = + S.CreateOverloadedBinOp(OpLoc, Opc, Fns, NewLHS, NewRHS, PerformADL, + /*AllowRewrittenCandidates*/ false); + if (RewrittenRes.isInvalid()) + return ExprError(); + } + Expr *Rewritten = RewrittenRes.get(); + + // Create a dummy expression representing the original expression as written. + // FIXME(EricWF): This doesn't actually really represent the expression as + // written, because it may not result in a to a builtin operator. + Expr *Original = new (S.Context) + BinaryOperator(OpaqueValueExpr::Create(S.Context, Args[0]), + OpaqueValueExpr::Create(S.Context, Args[1]), Opc, + Rewritten->getType(), Rewritten->getValueKind(), + Rewritten->getObjectKind(), OpLoc, S.FPFeatures); + + CXXRewrittenExpr::ExtraRewrittenBits ExtraBits; + ExtraBits.CompareBits.IsSynthesized = IsSynthesized; + return new (S.Context) CXXRewrittenExpr(CXXRewrittenExpr::Comparison, + Original, Rewritten, ExtraBits); +} + +/// Rewritten candidates have been added but not checked for validity. They +/// could still be non-viable if: +/// (A) The rewritten call (x <=> y) is a builtin, but it will be ill-formed +/// when built (for example it has narrowing conversions). +/// (B) The expression (x <=> y) @ 0 is ill-formed for the result of (x <=> y). +/// +/// If either is the case, this function should be considered non-viable and +/// another best viable function needs to be computed. +/// +/// Therefore, we do the following: +/// (1) If we have no viable candidate, or a deleted candidate, stop. +/// Otherwise, if we have a best viable candidate or a set of ambiguous +/// candidates and none of them are rewritten, stop. +/// +/// (2) If the best viable candidate is a rewritten candidate, build and +/// check the full expression for that candidate. If it succeeds return +/// the result. Otherwise, mark the candidate as non-viable, re-compute +/// the best viable function, and continue. +/// +/// (3) If we have ambiguity attempt to resolve it by evaluating each rewritten +/// candidate causing ambiguity: +/// +/// (3.1) build the full expression for the specified candidate. +/// (3.2) If the result is invalid, mark the candidate as non-viable. +/// +/// If only one viable candidate remains, stop. If the viable candidate is +/// rewritten, return the previously computed full expression. Otherwise, +/// if we have more than one viable candidate, stop. If no viable candidates +/// remain from the initial set of equally ranked candidates, recompute the +/// new best viable overload and continue. +RewrittenOverloadResolver::CheckOverloadResult +RewrittenOverloadResolver::RemoveNonViableRewrittenCandidates( + OverloadingResult OvlRes, OverloadCandidateSet::iterator Best, + ArrayRef EquivCands, ExprResult &FinalResult) { + auto Success = [&](ExprResult Res) { + FinalResult = Res; + return Done; + }; + switch (OvlRes) { + case OR_Deleted: + // FIXME(EricWF): If we've found a deleted rewritten operator, it's + // possible we should have never considered it a viable candidate. + case OR_No_Viable_Function: + return Done; + + case OR_Success: { + OverloadCandidate &Ovl = *Best; + if (!Ovl.getRewrittenKind()) + return Done; + // Build the full expression for the rewritten candidate, and return it if + // it's valid. Otherwise mark this candidate as non-viable and continue. + ExprResult Res = BuildRewrittenCandidate(Ovl); + if (Res.isInvalid()) { + Ovl.Viable = false; + return Continue; + } + return Success(Res); + } + case OR_Ambiguous: { + assert(EquivCands.size() > 1); + // If none of the viable candidates are rewritten, stop. + if (llvm::none_of(EquivCands, [](const OverloadCandidate *Cand) { + return (bool)Cand->getRewrittenKind(); + })) + return Done; + int NumViableCandidates = 0; + ExprResult ViableRewritten = ExprError(); + for (auto *Cand : EquivCands) { + OverloadCandidate &Ovl = *Cand; + if (Ovl.getRewrittenKind()) { + ExprResult Res = BuildRewrittenCandidate(Ovl); + if (Res.isInvalid()) { + Ovl.Viable = false; + continue; + } + ViableRewritten = Res; + } + ++NumViableCandidates; + } + // If only one of the candidates turns out to be viable, and it's a + // rewritten candidate, return that candidate as the result. + if (NumViableCandidates == 1 && !ViableRewritten.isInvalid()) + return Success(ViableRewritten); + // If we still have ambiguity, return and let the caller diagnose it. + if (NumViableCandidates > 1) + return Done; + // All of the equally ranked candidates are invalid. Loop and try overload + // resolution again. + return Continue; + } + } + llvm_unreachable("unhandled case"); +} + /// \brief Create a binary operation that may resolve to an overloaded /// operator. /// @@ -12244,11 +12694,11 @@ /// /// \param LHS Left-hand argument. /// \param RHS Right-hand argument. -ExprResult -Sema::CreateOverloadedBinOp(SourceLocation OpLoc, +ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, - const UnresolvedSetImpl &Fns, - Expr *LHS, Expr *RHS, bool PerformADL) { + const UnresolvedSetImpl &Fns, Expr *LHS, + Expr *RHS, bool PerformADL, + bool AllowRewrittenCandidates) { Expr *Args[2] = { LHS, RHS }; LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple @@ -12310,11 +12760,27 @@ if (Opc == BO_PtrMemD) return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); + UnresolvedSet<6> OrigFuncs; + UnresolvedSet<6> ThreeWayFuncs; + for (NamedDecl *D : Fns) { + FunctionDecl *FD = D->getAsFunction(); + if (FD) { + assert(FD->isOverloadedOperator()); + if (FD->getOverloadedOperator() == OO_Spaceship) { + ThreeWayFuncs.addDecl(D); + if (Op == OO_Spaceship) + OrigFuncs.addDecl(D); + } else + OrigFuncs.addDecl(D); + } else + OrigFuncs.addDecl(D); + } + // Build an empty overload set. OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator); // Add the candidates from the given function set. - AddFunctionCandidates(Fns, Args, CandidateSet); + AddFunctionCandidates(OrigFuncs, Args, CandidateSet); // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); @@ -12330,119 +12796,43 @@ // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet); - bool HadMultipleCandidates = (CandidateSet.size() > 1); - - // Perform overload resolution. - OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { - case OR_Success: { - // We found a built-in operator or an overloaded operator. - FunctionDecl *FnDecl = Best->Function; - - if (FnDecl) { - Expr *Base = nullptr; - // We matched an overloaded operator. Build a call to that - // operator. - - // Convert the arguments. - if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { - // Best->Access is only meaningful for class members. - CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Best->FoundDecl); - - ExprResult Arg1 = - PerformCopyInitialization( - InitializedEntity::InitializeParameter(Context, - FnDecl->getParamDecl(0)), - SourceLocation(), Args[1]); - if (Arg1.isInvalid()) - return ExprError(); - - ExprResult Arg0 = - PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr, - Best->FoundDecl, Method); - if (Arg0.isInvalid()) - return ExprError(); - Base = Args[0] = Arg0.getAs(); - Args[1] = RHS = Arg1.getAs(); - } else { - // Convert the arguments. - ExprResult Arg0 = PerformCopyInitialization( - InitializedEntity::InitializeParameter(Context, - FnDecl->getParamDecl(0)), - SourceLocation(), Args[0]); - if (Arg0.isInvalid()) - return ExprError(); - - ExprResult Arg1 = - PerformCopyInitialization( - InitializedEntity::InitializeParameter(Context, - FnDecl->getParamDecl(1)), - SourceLocation(), Args[1]); - if (Arg1.isInvalid()) - return ExprError(); - Args[0] = LHS = Arg0.getAs(); - Args[1] = RHS = Arg1.getAs(); + // C++2a Add rewritten and synthesized operator candidates. + bool HasRewrittenCandidates = false; + if (getLangOpts().CPlusPlus2a && AllowRewrittenCandidates && + BinaryOperator::isComparisonOp(Opc)) { + unsigned BeforeRewrittenSize = CandidateSet.size(); + AddRewrittenOperatorCandidates(Op, OpLoc, Args, ThreeWayFuncs, CandidateSet, + PerformADL); + HasRewrittenCandidates = BeforeRewrittenSize != CandidateSet.size(); } - // Build the actual expression node. - ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, - Best->FoundDecl, Base, - HadMultipleCandidates, OpLoc); - if (FnExpr.isInvalid()) - return ExprError(); - - // Determine the result type. - QualType ResultTy = FnDecl->getReturnType(); - ExprValueKind VK = Expr::getValueKindForType(ResultTy); - ResultTy = ResultTy.getNonLValueExprType(Context); - - CXXOperatorCallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(), - Args, ResultTy, VK, OpLoc, - FPFeatures); - - if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, - FnDecl)) - return ExprError(); - - ArrayRef ArgsArray(Args, 2); - const Expr *ImplicitThis = nullptr; - // Cut off the implicit 'this'. - if (isa(FnDecl)) { - ImplicitThis = ArgsArray[0]; - ArgsArray = ArgsArray.slice(1); - } - - // Check for a self move. - if (Op == OO_Equal) - DiagnoseSelfMove(Args[0], Args[1], OpLoc); - - checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray, - isa(FnDecl), OpLoc, TheCall->getSourceRange(), - VariadicDoesNotApply); + if (HasRewrittenCandidates) { + RewrittenOverloadResolver RewrittenOvlResolver(*this, OpLoc, Opc, Args, Fns, + PerformADL, CandidateSet); - return MaybeBindToTemporary(TheCall); - } else { - // We matched a built-in operator. Convert the arguments, then - // break out so that we will build the appropriate built-in - // operator node. - ExprResult ArgsRes0 = - PerformImplicitConversion(Args[0], Best->BuiltinParamTypes[0], - Best->Conversions[0], AA_Passing); - if (ArgsRes0.isInvalid()) - return ExprError(); - Args[0] = ArgsRes0.get(); + // Perform initial overload resolution that includes partially checked + // rewritten candidates, removing rewritten candidates which turn out to be + // invalid as needed. + ExprResult RewrittenResult = + RewrittenOvlResolver.ResolveRewrittenCandidates(); - ExprResult ArgsRes1 = - PerformImplicitConversion(Args[1], Best->BuiltinParamTypes[1], - Best->Conversions[1], AA_Passing); - if (ArgsRes1.isInvalid()) - return ExprError(); - Args[1] = ArgsRes1.get(); - break; - } + // If overload resolution was successful and the result was a re-written + // overload candidate, then that candidate was evaluated and we can return + // the result directly. + if (!RewrittenResult.isInvalid()) + return RewrittenResult; } + // Perform final overload resolution. + bool HadMultipleCandidates = (CandidateSet.size() > 1); + OverloadCandidateSet::iterator Best; + switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { + case OR_Success: + assert( + !Best->getRewrittenKind() && + "rewritten candidates should have already been resolved and evaluated"); + return BuildBinaryOperatorCandidate(OpLoc, Opc, *Best, Args[0], Args[1], + HadMultipleCandidates); case OR_No_Viable_Function: { // C++ [over.match.oper]p9: // If the operator is the operator , [...] and there are no @@ -12455,15 +12845,15 @@ // operator do not fall through to handling in built-in, but report that // no overloaded assignment operator found ExprResult Result = ExprError(); - if (Args[0]->getType()->isRecordType() && - Opc >= BO_Assign && Opc <= BO_OrAssign) { + if (Args[0]->getType()->isRecordType() && Opc >= BO_Assign && + Opc <= BO_OrAssign) { Diag(OpLoc, diag::err_ovl_no_viable_oper) - << BinaryOperator::getOpcodeStr(Opc) - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() + << Args[1]->getSourceRange(); if (Args[0]->getType()->isIncompleteType()) { Diag(OpLoc, diag::note_assign_lhs_incomplete) - << Args[0]->getType() - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + << Args[0]->getType() << Args[0]->getSourceRange() + << Args[1]->getSourceRange(); } } else { // This is an erroneous use of an operator which can be overloaded by @@ -12484,12 +12874,11 @@ BinaryOperator::getOpcodeStr(Opc), OpLoc); return Result; } - case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper_binary) - << BinaryOperator::getOpcodeStr(Opc) - << Args[0]->getType() << Args[1]->getType() - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getType() + << Args[1]->getType() << Args[0]->getSourceRange() + << Args[1]->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -12507,8 +12896,7 @@ return ExprError(); } else { Diag(OpLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() - << BinaryOperator::getOpcodeStr(Opc) + << Best->Function->isDeleted() << BinaryOperator::getOpcodeStr(Opc) << getDeletedOrUnavailableSuffix(Best->Function) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -3217,6 +3217,14 @@ return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator); } + ExprResult + RebuildCXXRewrittenExpr(CXXRewrittenExpr::RewrittenKind Kind, Expr *Original, + Expr *Rewritten, + CXXRewrittenExpr::ExtraRewrittenBits ExtraBits) { + return new (SemaRef.Context) + CXXRewrittenExpr(Kind, Original, Rewritten, ExtraBits); + } + /// \brief Build a new atomic operation expression. /// /// By default, performs semantic analysis to build the new expression. @@ -11515,6 +11523,68 @@ return getDerived().TransformExpr(E->GetTemporaryExpr()); } +static Expr *extractOperand(Expr *E, unsigned Idx) { + assert(Idx < 2); + if (auto *BO = dyn_cast(E)) { + if (Idx == 0) + return BO->getLHS(); + return BO->getRHS(); + } + if (auto *CE = dyn_cast(E)) { + assert(CE->getNumArgs() == 2); + return CE->getArg(Idx); + } + llvm_unreachable("unhandled case"); +} +static std::pair +extractOriginalOperandsFromRewrittenComparison(Expr *E, bool IsThreeWay, + bool IsSynthesized) { + if (IsThreeWay) + return {extractOperand(E, IsSynthesized ? 1 : 0), + extractOperand(E, IsSynthesized ? 0 : 1)}; + return extractOriginalOperandsFromRewrittenComparison( + extractOperand(E, IsSynthesized ? 1 : 0), true, IsSynthesized); +} + +template +ExprResult +TreeTransform::TransformCXXRewrittenExpr(CXXRewrittenExpr *E) { + + // FIXME(EricWF): Is there a case where the underlying expression has been + // transformed in such a way that we need to re-compute the rewritten + // expression? (and not just re-build it). + ExprResult RewrittenRes = getDerived().TransformExpr(E->getRewrittenExpr()); + if (RewrittenRes.isInvalid()) + return ExprError(); + Expr *Rewritten = RewrittenRes.get(); + + if (Rewritten == E->getRewrittenExpr() && !getDerived().AlwaysRebuild()) + return E; + + Expr *Original; + switch (E->getRewrittenKind()) { + case CXXRewrittenExpr::Comparison: { + BinaryOperator *Op = cast(E->getOriginalExpr()); + + // Extract the already transformed operands from the rewritten expression. + std::pair OrigArgs = + extractOriginalOperandsFromRewrittenComparison( + Rewritten, Op->getOpcode() == BO_Cmp, + E->getRewrittenInfo()->CompareBits.IsSynthesized); + + // Build a dummy node representing the expression as written. + Original = new (SemaRef.Context) BinaryOperator( + OpaqueValueExpr::Create(SemaRef.Context, OrigArgs.first), + OpaqueValueExpr::Create(SemaRef.Context, OrigArgs.second), + Op->getOpcode(), Rewritten->getType(), Rewritten->getValueKind(), + Rewritten->getObjectKind(), Op->getOperatorLoc(), Op->getFPFeatures()); + break; + } + } + return getDerived().RebuildCXXRewrittenExpr( + E->getRewrittenKind(), Original, Rewritten, *E->getRewrittenInfo()); +} + template ExprResult TreeTransform::TransformCXXFoldExpr(CXXFoldExpr *E) { Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -1705,6 +1705,21 @@ E->Opcode = (BinaryOperatorKind)Record.readInt(); } +void ASTStmtReader::VisitCXXRewrittenExpr(CXXRewrittenExpr *E) { + VisitExpr(E); + E->setRewrittenKind( + static_cast(Record.readInt())); + E->SubExprs[0] = Record.readSubExpr(); + E->SubExprs[1] = Record.readSubExpr(); + switch (E->getRewrittenKind()) { + case CXXRewrittenExpr::Comparison: { + CXXRewrittenExpr::ComparisonBits &Bits = E->ExtraBits.CompareBits; + Bits.IsSynthesized = Record.readInt(); + break; + } + } +} + void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); E->SourceExpr = Record.readSubExpr(); @@ -4074,6 +4089,9 @@ S = new (Context) CXXFoldExpr(Empty); break; + case EXPR_CXX_REWRITTEN_OPERATOR: + S = new (Context) CXXRewrittenExpr(Empty); + case EXPR_OPAQUE_VALUE: S = new (Context) OpaqueValueExpr(Empty); break; Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -1695,6 +1695,21 @@ Code = serialization::EXPR_CXX_FOLD; } +void ASTStmtWriter::VisitCXXRewrittenExpr(CXXRewrittenExpr *E) { + VisitExpr(E); + Record.push_back(E->getRewrittenKind()); + Record.AddStmt(E->SubExprs[0]); + Record.AddStmt(E->SubExprs[1]); + switch (E->getRewrittenKind()) { + case CXXRewrittenExpr::Comparison: { + CXXRewrittenExpr::ComparisonBits Bits = E->ExtraBits.CompareBits; + Record.push_back(Bits.IsSynthesized); + break; + } + } + Code = serialization::EXPR_CXX_REWRITTEN_OPERATOR; +} + void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); Record.AddStmt(E->getSourceExpr()); Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1289,6 +1289,7 @@ case Stmt::PackExpansionExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: case Stmt::FunctionParmPackExprClass: + case Stmt::CXXRewrittenExprClass: case Stmt::CoroutineBodyStmtClass: case Stmt::CoawaitExprClass: case Stmt::DependentCoawaitExprClass: @@ -2897,43 +2898,6 @@ const ProgramPointTag *tag, QualType LoadTy) { assert(!location.getAs() && "location cannot be a NonLoc."); - - // Are we loading from a region? This actually results in two loads; one - // to fetch the address of the referenced value and one to fetch the - // referenced value. - if (const auto *TR = - dyn_cast_or_null(location.getAsRegion())) { - - QualType ValTy = TR->getValueType(); - if (const ReferenceType *RT = ValTy->getAs()) { - static SimpleProgramPointTag - loadReferenceTag(TagProviderName, "Load Reference"); - ExplodedNodeSet Tmp; - evalLoadCommon(Tmp, NodeEx, BoundEx, Pred, state, - location, &loadReferenceTag, - getContext().getPointerType(RT->getPointeeType())); - - // Perform the load from the referenced value. - for (const auto I : Tmp) { - state = I->getState(); - location = state->getSVal(BoundEx, I->getLocationContext()); - evalLoadCommon(Dst, NodeEx, BoundEx, I, state, location, tag, LoadTy); - } - return; - } - } - - evalLoadCommon(Dst, NodeEx, BoundEx, Pred, state, location, tag, LoadTy); -} - -void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, - const Expr *NodeEx, - const Expr *BoundEx, - ExplodedNode *Pred, - ProgramStateRef state, - SVal location, - const ProgramPointTag *tag, - QualType LoadTy) { assert(NodeEx); assert(BoundEx); // Evaluate the location (checks for bad dereferences). Index: test/CodeGenCXX/cxx2a-compare.cpp =================================================================== --- test/CodeGenCXX/cxx2a-compare.cpp +++ test/CodeGenCXX/cxx2a-compare.cpp @@ -184,3 +184,17 @@ } } // namespace ComplexTest + +namespace RewrittenTest { +struct U { + int x; + std::strong_ordering operator<=>(U const &) const; +}; +// FIXME(EricWF): Write this test +auto test(U t1, U t2) { + return (t1 < t2); +} + +} // namespace RewrittenTest + + Index: test/SemaCXX/compare-cxx2a.cpp =================================================================== --- test/SemaCXX/compare-cxx2a.cpp +++ test/SemaCXX/compare-cxx2a.cpp @@ -293,20 +293,21 @@ template struct Tag {}; -// expected-note@+1 {{candidate}} -Tag<0> operator<=>(EnumA, EnumA) { - return {}; +std::strong_ordering operator<=>(EnumA, EnumA) { + return std::strong_ordering::equal; } -Tag<1> operator<=>(EnumA, EnumB) { - return {}; +// expected-note@+1 {{candidate function}}, +std::strong_ordering operator<=>(EnumA a, EnumB b) { + return ((int)a <=> (int)b); } void test_enum_ovl_provided() { auto r1 = (EnumA::A <=> EnumA::A); - ASSERT_EXPR_TYPE(r1, Tag<0>); + ASSERT_EXPR_TYPE(r1, std::strong_ordering); auto r2 = (EnumA::A <=> EnumB::B); - ASSERT_EXPR_TYPE(r2, Tag<1>); - (void)(EnumB::B <=> EnumA::A); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumA')}} + ASSERT_EXPR_TYPE(r2, std::strong_ordering); + (void)(EnumB::B <=> EnumA::A); // OK, chooses reverse order synthesized candidate. + (void)(EnumB::B <=> EnumC::C); // expected-error {{invalid operands to binary expression ('EnumCompareTests::EnumB' and 'EnumCompareTests::EnumC')}} } void enum_float_test() { @@ -422,3 +423,116 @@ } } // namespace ComplexTest + +namespace TestRewritting { + +struct T { + int x; + // expected-note@+1 {{candidate}} + constexpr std::strong_ordering operator<=>(T y) const { + return (x <=> y.x); + } +}; + +struct U { + int x; + // FIXME: This diagnostic is wrong-ish. + // expected-note@+1 {{candidate function not viable: requires single argument 'y', but 2 arguments were provided}} + constexpr std::strong_equality operator<=>(T y) const { + if (x == y.x) + return std::strong_equality::equal; + return std::strong_equality::nonequal; + } +}; + +struct X { int x; }; +struct Y { int x; }; +template +struct Tag {}; +// expected-note@+1 2 {{candidate}} +Tag<0> operator<=>(X, Y) { + return {}; +} +// expected-note@+1 2 {{candidate}} +constexpr auto operator<=>(Y y, X x) { + return y.x <=> x.x; +} + +void foo() { + T t{42}; + T t2{0}; + U u{101}; + auto r1 = (t <=> u); + ASSERT_EXPR_TYPE(r1, std::strong_equality); + auto r2 = (t <=> t2); + ASSERT_EXPR_TYPE(r2, std::strong_ordering); + + auto r3 = t == u; + ASSERT_EXPR_TYPE(r3, bool); + + (void)(t < u); // expected-error {{invalid operands to binary expression ('TestRewritting::T' and 'TestRewritting::U')}} + + constexpr X x{1}; + constexpr Y y{2}; + constexpr auto r4 = (y < x); + static_assert(r4 == false); + constexpr auto r5 = (x < y); + static_assert(r5 == true); +} + +} // namespace TestRewritting + +// The implicit object parameter is not considered when performing partial +// ordering. That makes the reverse synthesized candidates ambiguous with the +// rewritten candidates if any of them resolve to a member function. +namespace TestOvlMatchingIgnoresImplicitObject { +struct U; +// expected-note@+2 {{candidate}} +struct T { + std::strong_ordering operator<=>(U const &RHS) const; +}; +// expected-note@+2 {{candidate}} +struct U { + std::strong_ordering operator<=>(T const &RHS) const; +}; + +struct V { + int x; +}; +auto operator<=>(V const &LHS, V &&RHS) { // expected-note 4 {{candidate}} + return LHS.x <=> RHS.x; +} +auto operator<(V const &, V &&) { // expected-note {{candidate}} + return std::strong_equality::equal; +} + +void test() { + // expected-error@+1 {{use of overloaded operator '<' is ambiguous}} + (void)(T{} < U{}); + // expected-error@+1 {{use of overloaded operator '<' is ambiguous}} + (void)(V{} < V{}); + // expected-error@+1 {{use of overloaded operator '<=>' is ambiguous}} + (void)(V{} <=> V{}); +} + +} // namespace TestOvlMatchingIgnoresImplicitObject + +namespace TestRewrittenTemplate { + +template +auto test(T const &LHS, T const &RHS) { + // expected-error@+1 {{invalid operands to binary expression ('const TestRewrittenTemplate::None'}} + return LHS < RHS; +} +struct None {}; +template auto test(None const &, None const &); // expected-note {{requested here}} + +struct Relational {}; +bool operator<(Relational, Relational); +template auto test(Relational const &, Relational const &); + +struct ThreeWay {}; +std::strong_ordering operator<=>(ThreeWay, ThreeWay); +template auto test(ThreeWay const &, ThreeWay const &); + +} // namespace TestRewrittenTemplate