diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7747,16 +7747,11 @@ if (Args[0]->getType()->isOverloadableType()) S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args); - else if (OO == OO_EqualEqual || - !Args[0]->getType()->isFunctionPointerType()) { + else // FIXME: We determine whether this is a valid expression by checking to // see if there's a viable builtin operator candidate for it. That isn't // really what the rules ask us to do, but should give the right results. - // - // Note that the builtin operator for relational comparisons on function - // pointers is the only known case which cannot be used. S.AddBuiltinOperatorCandidates(OO, FD->getLocation(), Args, CandidateSet); - } Result R; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -7834,10 +7834,10 @@ SemaRef(SemaRef), Context(SemaRef.Context) { } - void AddTypesConvertedFrom(QualType Ty, - SourceLocation Loc, + void AddTypesConvertedFrom(QualType Ty, SourceLocation Loc, bool AllowUserConversions, bool AllowExplicitConversions, + bool DisallowNonRelationalComparableTypes, const Qualifiers &VisibleTypeConversionsQuals); llvm::iterator_range pointer_types() { return PointerTypes; } @@ -7974,15 +7974,14 @@ /// primarily interested in pointer types and enumeration types. We also /// take member pointer types, for the conditional operator. /// AllowUserConversions is true if we should look at the conversion -/// functions of a class type, and AllowExplicitConversions if we +/// functions of a class type, AllowExplicitConversions if we /// should also include the explicit conversion functions of a class -/// type. -void -BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, - SourceLocation Loc, - bool AllowUserConversions, - bool AllowExplicitConversions, - const Qualifiers &VisibleQuals) { +/// type, and DisallowNonRelationalComparableTypes if we should exclude types +/// which cannot be compared with relational operators. +void BuiltinCandidateTypeSet::AddTypesConvertedFrom( + QualType Ty, SourceLocation Loc, bool AllowUserConversions, + bool AllowExplicitConversions, bool DisallowNonRelationalComparableTypes, + const Qualifiers &VisibleQuals) { // Only deal with canonical types. Ty = Context.getCanonicalType(Ty); @@ -8009,6 +8008,10 @@ if (Ty->isObjCIdType() || Ty->isObjCClassType()) PointerTypes.insert(Ty); else if (Ty->getAs() || Ty->getAs()) { + // The builtin operator for relational comparisons on function pointers + // is the only known case which cannot be used for three-way comparisons. + if (DisallowNonRelationalComparableTypes && Ty->isFunctionPointerType()) + return; // Insert our type, and its more-qualified variants, into the set // of types. if (!AddPointerWithMoreQualifiedTypeVariants(Ty, VisibleQuals)) @@ -8050,6 +8053,7 @@ CXXConversionDecl *Conv = cast(D); if (AllowExplicitConversions || !Conv->isExplicit()) { AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, + DisallowNonRelationalComparableTypes, VisibleQuals); } } @@ -9132,13 +9136,10 @@ SmallVector CandidateTypes; for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { CandidateTypes.emplace_back(*this); - CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(), - OpLoc, - true, - (Op == OO_Exclaim || - Op == OO_AmpAmp || - Op == OO_PipePipe), - VisibleTypeConversionsQuals); + CandidateTypes[ArgIdx].AddTypesConvertedFrom( + Args[ArgIdx]->getType(), OpLoc, true, + (Op == OO_Exclaim || Op == OO_AmpAmp || Op == OO_PipePipe), + (Op == OO_Less || Op == OO_Spaceship), VisibleTypeConversionsQuals); HasNonRecordCandidateType = HasNonRecordCandidateType || CandidateTypes[ArgIdx].hasNonRecordTypes(); HasArithmeticOrEnumeralCandidateType = diff --git a/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp b/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp --- a/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp +++ b/clang/test/CXX/class/class.compare/class.spaceship/p2.cpp @@ -197,8 +197,7 @@ operator fp() const; }; struct b3 { - auto operator<=>(b3 const &) const = default; // expected-error {{cannot be deduced because three-way comparison for member 'f' would compare as builtin type 'void (*)()' which is not currently supported}} - // expected-warning@-1 {{implicitly deleted}} - a3 f; + auto operator<=>(b3 const &) const = default; // expected-warning {{implicitly deleted}} + a3 f; // expected-note {{because there is no viable three-way comparison function for member 'f'}} }; }