diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -255,6 +255,8 @@ - Reject non-type template arguments formed by casting a non-zero integer to a pointer in pre-C++17 modes, instead of treating them as null pointers. +- Fix an issue when performing constraints partial ordering on non-template + functions. `Issue 56154 `_ Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 @@ -10033,13 +10033,20 @@ // parameter-type-lists, and F1 is more constrained than F2 [...], if (!Cand1IsSpecialization && !Cand2IsSpecialization && sameFunctionParameterTypeLists(S, Cand1, Cand2)) { - Expr *RC1 = Cand1.Function->getTrailingRequiresClause(); - Expr *RC2 = Cand2.Function->getTrailingRequiresClause(); + FunctionDecl *Function1 = Cand1.Function; + FunctionDecl *Function2 = Cand2.Function; + if (FunctionDecl *MF = Function1->getInstantiatedFromMemberFunction()) + Function1 = MF; + if (FunctionDecl *MF = Function2->getInstantiatedFromMemberFunction()) + Function2 = MF; + + Expr *RC1 = Function1->getTrailingRequiresClause(); + Expr *RC2 = Function2->getTrailingRequiresClause(); if (RC1 && RC2) { bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, {RC2}, + if (S.IsAtLeastAsConstrained(Function1, {RC1}, Function2, {RC2}, AtLeastAsConstrained1) || - S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, {RC1}, + S.IsAtLeastAsConstrained(Function2, {RC2}, Function1, {RC1}, AtLeastAsConstrained2)) return false; if (AtLeastAsConstrained1 != AtLeastAsConstrained2) diff --git a/clang/test/CXX/over/over.match/over.match.best/p2.cpp b/clang/test/CXX/over/over.match/over.match.best/p2.cpp --- a/clang/test/CXX/over/over.match/over.match.best/p2.cpp +++ b/clang/test/CXX/over/over.match/over.match.best/p2.cpp @@ -7,8 +7,7 @@ bool operator<(const A&) const & requires X; // #1 int operator<=>(const A&) const & requires X && X = delete; // #2 }; - bool k1 = A() < A(); // not ordered by constraints: prefer non-rewritten form - bool k2 = A() < A(); // prefer more-constrained 'operator<=>' + bool k = A() < A(); // prefer more-constrained 'operator<=>' // expected-error@-1 {{deleted}} // expected-note@#1 {{candidate}} // expected-note@#2 {{candidate function has been explicitly deleted}} diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/non-template-functions.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/non-template-functions.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/non-template-functions.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s +// expected-no-diagnostics + +namespace PR56154 { + template concept C0 = (N == 0); + template concept C0x = C0; + template concept C00 = C0x && C0; + + template + struct A { + void f() requires C00; + void f() requires C0x; + }; + void h(A<0, 0> a) { + a.f(); + } +}