Skip to content

Commit

Permalink
[Clang] CWG2789 Overload resolution with implicit and explicit object… (
Browse files Browse the repository at this point in the history
#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.
  • Loading branch information
cor3ntin committed Nov 28, 2023
1 parent 95a47bc commit 205f530
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 14 deletions.
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
69 changes: 55 additions & 14 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
31 changes: 31 additions & 0 deletions clang/test/CXX/drs/dr27xx.cpp
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -22,3 +52,4 @@ consteval X f() { return {}; }
static_assert(false, f().s); // expected-error {{static assertion failed: Hello}}
#endif
} // namespace dr2798

0 comments on commit 205f530

Please sign in to comment.