[clang] 205f530 - [Clang] CWG2789 Overload resolution with implicit and explicit object… (#73493)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 28 04:30:22 PST 2023
Author: cor3ntin
Date: 2023-11-28T13:30:18+01:00
New Revision: 205f53010d0da11a9c4ab7a4655edb4a2ded1b02
URL: https://github.com/llvm/llvm-project/commit/205f53010d0da11a9c4ab7a4655edb4a2ded1b02
DIFF: https://github.com/llvm/llvm-project/commit/205f53010d0da11a9c4ab7a4655edb4a2ded1b02.diff
LOG: [Clang] CWG2789 Overload resolution with implicit and explicit object… (#73493)
… member functions
Implement the resolution to CWG2789 from
https://wiki.edg.com/pub/Wg21kona2023/StrawPolls/p3046r0.html
The DR page is not updated because the issue has not made it to a
published list yet.
Added:
Modified:
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaOverload.cpp
clang/test/CXX/drs/dr27xx.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f7c9d0e2e6412b7..7579a3256bc37aa 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3849,6 +3849,12 @@ class Sema final {
const FunctionProtoType *NewType,
unsigned *ArgPos = nullptr,
bool Reversed = false);
+
+ bool FunctionNonObjectParamTypesAreEqual(const FunctionDecl *OldFunction,
+ const FunctionDecl *NewFunction,
+ unsigned *ArgPos = nullptr,
+ bool Reversed = false);
+
void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
QualType FromType, QualType ToType);
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 9800d7f1c9cfee9..3a3e9234469d393 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -3239,6 +3239,28 @@ bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
NewType->param_types(), ArgPos, Reversed);
}
+bool Sema::FunctionNonObjectParamTypesAreEqual(const FunctionDecl *OldFunction,
+ const FunctionDecl *NewFunction,
+ unsigned *ArgPos,
+ bool Reversed) {
+
+ if (OldFunction->getNumNonObjectParams() !=
+ NewFunction->getNumNonObjectParams())
+ return false;
+
+ unsigned OldIgnore =
+ unsigned(OldFunction->hasCXXExplicitFunctionObjectParameter());
+ unsigned NewIgnore =
+ unsigned(NewFunction->hasCXXExplicitFunctionObjectParameter());
+
+ auto *OldPT = cast<FunctionProtoType>(OldFunction->getFunctionType());
+ auto *NewPT = cast<FunctionProtoType>(NewFunction->getFunctionType());
+
+ return FunctionParamTypesAreEqual(OldPT->param_types().slice(OldIgnore),
+ NewPT->param_types().slice(NewIgnore),
+ ArgPos, Reversed);
+}
+
/// CheckPointerConversion - Check the pointer conversion from the
/// expression From to the type ToType. This routine checks for
/// ambiguous or inaccessible derived-to-base pointer
@@ -10121,22 +10143,41 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
/// We're allowed to use constraints partial ordering only if the candidates
/// have the same parameter types:
-/// [over.match.best]p2.6
-/// F1 and F2 are non-template functions with the same parameter-type-lists,
-/// and F1 is more constrained than F2 [...]
+/// [over.match.best.general]p2.6
+/// F1 and F2 are non-template functions with the same
+/// non-object-parameter-type-lists, and F1 is more constrained than F2 [...]
static bool sameFunctionParameterTypeLists(Sema &S,
- const OverloadCandidate &Cand1,
- const OverloadCandidate &Cand2) {
- if (Cand1.Function && Cand2.Function) {
- auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType());
- auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType());
- if (PT1->getNumParams() == PT2->getNumParams() &&
- PT1->isVariadic() == PT2->isVariadic() &&
- S.FunctionParamTypesAreEqual(PT1, PT2, nullptr,
- Cand1.isReversed() ^ Cand2.isReversed()))
- return true;
+ const OverloadCandidate &Cand1,
+ const OverloadCandidate &Cand2) {
+ if (!Cand1.Function || !Cand2.Function)
+ return false;
+
+ FunctionDecl *Fn1 = Cand1.Function;
+ FunctionDecl *Fn2 = Cand2.Function;
+
+ if (Fn1->isVariadic() != Fn1->isVariadic())
+ return false;
+
+ if (!S.FunctionNonObjectParamTypesAreEqual(
+ Fn1, Fn2, nullptr, Cand1.isReversed() ^ Cand2.isReversed()))
+ return false;
+
+ auto *Mem1 = dyn_cast<CXXMethodDecl>(Fn1);
+ auto *Mem2 = dyn_cast<CXXMethodDecl>(Fn2);
+ if (Mem1 && Mem2) {
+ // if they are member functions, both are direct members of the same class,
+ // and
+ if (Mem1->getParent() != Mem2->getParent())
+ return false;
+ // if both are non-static member functions, they have the same types for
+ // their object parameters
+ if (Mem1->isInstance() && Mem2->isInstance() &&
+ !S.getASTContext().hasSameType(
+ Mem1->getFunctionObjectParameterReferenceType(),
+ Mem1->getFunctionObjectParameterReferenceType()))
+ return false;
}
- return false;
+ return true;
}
/// isBetterOverloadCandidate - Determines whether the first overload
diff --git a/clang/test/CXX/drs/dr27xx.cpp b/clang/test/CXX/drs/dr27xx.cpp
index a5998163da52493..5c7ce98f878da6b 100644
--- a/clang/test/CXX/drs/dr27xx.cpp
+++ b/clang/test/CXX/drs/dr27xx.cpp
@@ -1,5 +1,35 @@
// RUN: %clang_cc1 -std=c++2c -verify %s
+namespace dr2789 { // dr2789: 18 open
+template <typename T = int>
+struct Base {
+ constexpr void g(); // #dr2789-g1
+};
+
+template <typename T = int>
+struct Base2 {
+ constexpr void g() requires true; // #dr2789-g2
+};
+
+template <typename T = int>
+struct S : Base<T>, Base2<T> {
+ constexpr void f();
+ constexpr void f(this S&) requires true{};
+
+ using Base<T>::g;
+ using Base2<T>::g;
+};
+
+void test() {
+ S<> s;
+ s.f();
+ s.g(); // expected-error {{call to member function 'g' is ambiguous}}
+ // expected-note@#dr2789-g1 {{candidate function}}
+ // expected-note@#dr2789-g2 {{candidate function}}
+}
+
+}
+
namespace dr2798 { // dr2798: 17 drafting
#if __cpp_static_assert >= 202306
struct string {
@@ -22,3 +52,4 @@ consteval X f() { return {}; }
static_assert(false, f().s); // expected-error {{static assertion failed: Hello}}
#endif
} // namespace dr2798
+
More information about the cfe-commits
mailing list