[clang] e18c2c5 - [Clang] use non-instantiated function declaration for constraints partial ordering
Yuanfang Chen via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 30 22:40:26 PDT 2022
Author: Yuanfang Chen
Date: 2022-10-30T22:39:47-07:00
New Revision: e18c2c5548f6864def4a110239395a18afc195d6
URL: https://github.com/llvm/llvm-project/commit/e18c2c5548f6864def4a110239395a18afc195d6
DIFF: https://github.com/llvm/llvm-project/commit/e18c2c5548f6864def4a110239395a18afc195d6.diff
LOG: [Clang] use non-instantiated function declaration for constraints partial ordering
Per wordings in
- https://eel.is/c++draft/over.match#best.general-2.6
- https://eel.is/c++draft/temp.constr.order
- https://eel.is/c++draft/temp.constr#atomic-1
constraints partial ordering should use the unsubstituted template
parameters of the constrained entity, not the instantiated entity.
Fix #56154
Reviewed By: erichkeane, royjacobson, mizvekov
Differential Revision: https://reviews.llvm.org/D136545
Added:
clang/test/CXX/temp/temp.constr/temp.constr.order/non-template-functions.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaOverload.cpp
clang/test/CXX/over/over.match/over.match.best/p2.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bd4c0bf7fa0c0..641f75eeeb64c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -264,6 +264,8 @@ Bug Fixes
constraint, which re-evaluated the same constraint.
`Issue 53213 <https://github.com/llvm/llvm-project/issues/53213>`_
`Issue 45736 <https://github.com/llvm/llvm-project/issues/45736>`_
+- Fix an issue when performing constraints partial ordering on non-template
+ functions. `Issue 56154 <https://github.com/llvm/llvm-project/issues/56154>`_
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d3d87c8354aea..54d8a746fa247 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1300,6 +1300,18 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
NamedDecl *D2,
MutableArrayRef<const Expr *> AC2,
bool &Result) {
+ if (const auto *FD1 = dyn_cast<FunctionDecl>(D1)) {
+ auto IsExpectedEntity = [](const FunctionDecl *FD) {
+ FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
+ return Kind == FunctionDecl::TK_NonTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplate;
+ };
+ const auto *FD2 = dyn_cast<FunctionDecl>(D2);
+ assert(IsExpectedEntity(FD1) && FD2 && IsExpectedEntity(FD2) &&
+ "use non-instantiated function declaration for constraints partial "
+ "ordering");
+ }
+
if (AC1.empty()) {
Result = AC2.empty();
return false;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 686a126968e8a..a164d9af8f34a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -18218,13 +18218,20 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record,
if (!SatisfactionStatus[i])
continue;
CXXMethodDecl *Method = Methods[i];
- const Expr *Constraints = Method->getTrailingRequiresClause();
+ CXXMethodDecl *OrigMethod = Method;
+ if (FunctionDecl *MF = OrigMethod->getInstantiatedFromMemberFunction())
+ OrigMethod = cast<CXXMethodDecl>(MF);
+
+ const Expr *Constraints = OrigMethod->getTrailingRequiresClause();
bool AnotherMethodIsMoreConstrained = false;
for (size_t j = 0; j < Methods.size(); j++) {
if (i == j || !SatisfactionStatus[j])
continue;
CXXMethodDecl *OtherMethod = Methods[j];
- if (!AreSpecialMemberFunctionsSameKind(S.Context, Method, OtherMethod,
+ if (FunctionDecl *MF = OtherMethod->getInstantiatedFromMemberFunction())
+ OtherMethod = cast<CXXMethodDecl>(MF);
+
+ if (!AreSpecialMemberFunctionsSameKind(S.Context, OrigMethod, OtherMethod,
CSM))
continue;
@@ -18235,7 +18242,7 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record,
AnotherMethodIsMoreConstrained = true;
break;
}
- if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, Method,
+ if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, OrigMethod,
{Constraints},
AnotherMethodIsMoreConstrained)) {
// There was an error with the constraints comparison. Exit the loop
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d21de7db3f53b..45bca3a31d3a7 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10039,13 +10039,20 @@ bool clang::isBetterOverloadCandidate(
// parameter-type-lists, and F1 is more constrained than F2 [...],
if (!Cand1IsSpecialization && !Cand2IsSpecialization &&
sameFunctionParameterTypeLists(S, Cand1, Cand2)) {
- const Expr *RC1 = Cand1.Function->getTrailingRequiresClause();
- const 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;
+
+ const Expr *RC1 = Function1->getTrailingRequiresClause();
+ const 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)
@@ -12630,20 +12637,24 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
DeclAccessPair DAP;
SmallVector<FunctionDecl *, 2> AmbiguousDecls;
- auto CheckMoreConstrained =
- [&] (FunctionDecl *FD1, FunctionDecl *FD2) -> Optional<bool> {
- SmallVector<const Expr *, 1> AC1, AC2;
- FD1->getAssociatedConstraints(AC1);
- FD2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1))
- return None;
- if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2))
- return None;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return None;
- return AtLeastAsConstrained1;
- };
+ auto CheckMoreConstrained = [&](FunctionDecl *FD1,
+ FunctionDecl *FD2) -> Optional<bool> {
+ if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
+ FD1 = MF;
+ if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
+ FD2 = MF;
+ SmallVector<const Expr *, 1> AC1, AC2;
+ FD1->getAssociatedConstraints(AC1);
+ FD2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1))
+ return None;
+ if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2))
+ return None;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return None;
+ return AtLeastAsConstrained1;
+ };
// Don't use the AddressOfResolver because we're specifically looking for
// cases where we have one overload candidate that lacks
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
index 3a44436655767..e0f7dfb6a4065 100644
--- 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,7 +7,11 @@ namespace PR44761 {
bool operator<(const A&) const & requires X<T>; // #1
int operator<=>(const A&) const & requires X<T> && X<int> = delete; // #2
};
- bool k1 = A<int>() < A<int>(); // not ordered by constraints: prefer non-rewritten form
+ bool k1 = A<int>() < A<int>(); // prefer more-constrained 'operator<=>'
+ // expected-error at -1 {{deleted}}
+ // expected-note@#1 {{candidate}}
+ // expected-note@#2 {{candidate function has been explicitly deleted}}
+ // expected-note@#2 {{candidate function (with reversed parameter order) has been explicitly deleted}}
bool k2 = A<float>() < A<float>(); // prefer more-constrained 'operator<=>'
// expected-error at -1 {{deleted}}
// expected-note@#1 {{candidate}}
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
index 0000000000000..4ef8403774428
--- /dev/null
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/non-template-functions.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s
+// expected-no-diagnostics
+
+template<typename T, typename U>
+constexpr static bool is_same_v = false;
+
+template<typename T>
+constexpr static bool is_same_v<T, T> = true;
+
+namespace PR56154 {
+ template <int N> concept C0 = (N == 0);
+ template <int N, int N2> concept C0x = C0<N>;
+ template <int N1, int N2> concept C00 = C0x<N1, N2> && C0<N2>;
+
+ template<int N1, int N2>
+ struct A {
+ void f() requires C00<N1, N2>;
+ void f() requires C0x<N1, N2> = delete;
+
+ static short g() requires C00<N1, N2>;
+ static int g() requires C0x<N1, N2>;
+ };
+ void h(A<0, 0> a) {
+ a.f();
+ static_assert(is_same_v<decltype(&A<0, 0>::g), short(*)()>);
+ }
+}
More information about the cfe-commits
mailing list