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 @@ -7685,10 +7685,14 @@ if (Args[0]->getType()->isOverloadableType()) S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args); - else { + else if (OO == OO_EqualEqual || + !Args[0]->getType()->isFunctionPointerType()) { // 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); } diff --git a/clang/test/CXX/class/class.compare/class.compare.default/p2.cpp b/clang/test/CXX/class/class.compare/class.compare.default/p2.cpp --- a/clang/test/CXX/class/class.compare/class.compare.default/p2.cpp +++ b/clang/test/CXX/class/class.compare/class.compare.default/p2.cpp @@ -39,6 +39,14 @@ void(a >= a); } +struct A3 { + int &x; // expected-note {{because class 'A3' has a reference member}} + + bool operator==(const A3 &) const = default; // expected-warning {{implicitly deleted}} + bool operator<(const A3 &) const = default; // expected-warning {{implicitly deleted}} + // expected-note@-1 {{because there is no viable comparison function}} +}; + struct B1 { struct { int x; diff --git a/clang/test/CXX/class/class.compare/class.eq/p2.cpp b/clang/test/CXX/class/class.compare/class.eq/p2.cpp --- a/clang/test/CXX/class/class.compare/class.eq/p2.cpp +++ b/clang/test/CXX/class/class.compare/class.eq/p2.cpp @@ -15,6 +15,25 @@ struct F { void operator==(F) const; }; struct G { bool operator==(G) const = delete; }; // expected-note {{deleted here}} +struct H1 { + bool operator==(const H1 &) const = default; + bool operator<(const H1 &) const = default; // expected-warning {{implicitly deleted}} + // expected-note@-1 {{because there is no viable comparison function}} + void (*x)(); +}; +struct H2 { + bool operator==(const H2 &) const = default; + bool operator<(const H2 &) const = default; // expected-warning {{implicitly deleted}} + // expected-note@-1 {{because there is no viable comparison function}} + void (H2::*x)(); +}; +struct H3 { + bool operator==(const H3 &) const = default; + bool operator<(const H3 &) const = default; // expected-warning {{implicitly deleted}} + // expected-note@-1 {{because there is no viable comparison function}} + int H3::*x; +}; + template struct X { X(); bool operator==(const X&) const = default; // #x expected-note 4{{deleted here}} 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 @@ -155,3 +155,20 @@ friend CmpCat auto operator<=>(const D&, const D&) = default; }; } + +namespace PR48856 { + struct A { + auto operator<=>(const A &) const = default; // expected-warning {{implicitly deleted}} + void (*x)(); // expected-note {{because there is no viable comparison function for member 'x'}} + }; + + struct B { + auto operator<=>(const B &) const = default; // expected-warning {{implicitly deleted}} + void (B::*x)(); // expected-note {{because there is no viable comparison function for member 'x'}} + }; + + struct C { + auto operator<=>(const C &) const = default; // expected-warning {{implicitly deleted}} + int C::*x; // expected-note {{because there is no viable comparison function for member 'x'}} + }; +}