Skip to content

Commit a6a16e1

Browse files
committed
[Clang] Correctly handle taking the address of an explicit object member function template
When implementing #93430, I failed to consider some cases involving function templates. ``` struct A { template <typename T> void a(this T self); }; (&A::a<A>)(A{}); ``` This fixes that
1 parent a75587d commit a6a16e1

File tree

6 files changed

+216
-33
lines changed

6 files changed

+216
-33
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,8 @@ Bug Fixes to C++ Support
896896
- Fixed a crash when constant evaluating some explicit object member assignment operators. (#GH142835)
897897
- Fixed an access checking bug when substituting into concepts (#GH115838)
898898
- Fix a bug where private access specifier of overloaded function not respected. (#GH107629)
899+
- Correctly handles calling an explicit object member function template overload set
900+
through its address (``(&Foo::bar<baz>)()``).
899901

900902
Bug Fixes to AST Handling
901903
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12500,6 +12500,7 @@ class Sema final : public SemaBase {
1250012500
sema::TemplateDeductionInfo &Info,
1250112501
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
1250212502
bool PartialOverloading, bool PartialOrdering,
12503+
bool ForOverloadSetAddressResolution,
1250312504
llvm::function_ref<bool(bool)> CheckNonDependent =
1250412505
[](bool /*OnlyInitializeNonUserDefinedConversions*/) {
1250512506
return false;

clang/lib/Sema/SemaOverload.cpp

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7700,18 +7700,6 @@ void Sema::AddMethodCandidate(
77007700
EnterExpressionEvaluationContext Unevaluated(
77017701
*this, Sema::ExpressionEvaluationContext::Unevaluated);
77027702

7703-
// Add this candidate
7704-
OverloadCandidate &Candidate =
7705-
CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);
7706-
Candidate.FoundDecl = FoundDecl;
7707-
Candidate.Function = Method;
7708-
Candidate.RewriteKind =
7709-
CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);
7710-
Candidate.TookAddressOfOverload =
7711-
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
7712-
Candidate.ExplicitCallArguments = Args.size();
7713-
Candidate.StrictPackMatch = StrictPackMatch;
7714-
77157703
bool IgnoreExplicitObject =
77167704
(Method->isExplicitObjectMemberFunction() &&
77177705
CandidateSet.getKind() ==
@@ -7727,6 +7715,23 @@ void Sema::AddMethodCandidate(
77277715
unsigned NumParams = Method->getNumParams() - ExplicitOffset +
77287716
int(ImplicitObjectMethodTreatedAsStatic);
77297717

7718+
unsigned ExtraArgs =
7719+
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet
7720+
? 0
7721+
: 1;
7722+
7723+
// Add this candidate
7724+
OverloadCandidate &Candidate =
7725+
CandidateSet.addCandidate(Args.size() + ExtraArgs, EarlyConversions);
7726+
Candidate.FoundDecl = FoundDecl;
7727+
Candidate.Function = Method;
7728+
Candidate.RewriteKind =
7729+
CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);
7730+
Candidate.TookAddressOfOverload =
7731+
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
7732+
Candidate.ExplicitCallArguments = Args.size();
7733+
Candidate.StrictPackMatch = StrictPackMatch;
7734+
77307735
// (C++ 13.3.2p2): A candidate function having fewer than m
77317736
// parameters is viable only if it has an ellipsis in its parameter
77327737
// list (8.3.5).
@@ -7757,7 +7762,9 @@ void Sema::AddMethodCandidate(
77577762
Candidate.Viable = true;
77587763

77597764
unsigned FirstConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
7760-
if (ObjectType.isNull())
7765+
if (IgnoreExplicitObject)
7766+
;
7767+
else if (ObjectType.isNull())
77617768
Candidate.IgnoreObjectArgument = true;
77627769
else if (Method->isStatic()) {
77637770
// [over.best.ics.general]p8
@@ -7807,7 +7814,7 @@ void Sema::AddMethodCandidate(
78077814
// arguments.
78087815
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
78097816
unsigned ConvIdx =
7810-
PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + 1);
7817+
PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + ExtraArgs);
78117818
if (Candidate.Conversions[ConvIdx].isInitialized()) {
78127819
// We already formed a conversion sequence for this parameter during
78137820
// template argument deduction.
@@ -7876,6 +7883,7 @@ static void AddMethodTemplateCandidateImmediately(
78767883
// function template are combined with the set of non-template candidate
78777884
// functions.
78787885
TemplateDeductionInfo Info(CandidateSet.getLocation());
7886+
auto Method = cast<CXXMethodDecl>(MethodTmpl->getTemplatedDecl());
78797887
FunctionDecl *Specialization = nullptr;
78807888
ConversionSequenceList Conversions;
78817889
if (TemplateDeductionResult Result = S.DeduceTemplateArguments(
@@ -7897,14 +7905,18 @@ static void AddMethodTemplateCandidateImmediately(
78977905
OverloadCandidate &Candidate =
78987906
CandidateSet.addCandidate(Conversions.size(), Conversions);
78997907
Candidate.FoundDecl = FoundDecl;
7900-
Candidate.Function = MethodTmpl->getTemplatedDecl();
7908+
Candidate.Function = Method;
79017909
Candidate.Viable = false;
79027910
Candidate.RewriteKind =
79037911
CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
79047912
Candidate.IsSurrogate = false;
7913+
Candidate.TookAddressOfOverload =
7914+
CandidateSet.getKind() ==
7915+
OverloadCandidateSet::CSK_AddressOfOverloadSet;
7916+
79057917
Candidate.IgnoreObjectArgument =
7906-
cast<CXXMethodDecl>(Candidate.Function)->isStatic() ||
7907-
ObjectType.isNull();
7918+
Method->isStatic() ||
7919+
(!Method->isExplicitObjectMemberFunction() && ObjectType.isNull());
79087920
Candidate.ExplicitCallArguments = Args.size();
79097921
if (Result == TemplateDeductionResult::NonDependentConversionFailure)
79107922
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -8024,9 +8036,16 @@ static void AddTemplateOverloadCandidateImmediately(
80248036
Candidate.IsADLCandidate = llvm::to_underlying(IsADLCandidate);
80258037
// Ignore the object argument if there is one, since we don't have an object
80268038
// type.
8039+
Candidate.TookAddressOfOverload =
8040+
CandidateSet.getKind() ==
8041+
OverloadCandidateSet::CSK_AddressOfOverloadSet;
8042+
80278043
Candidate.IgnoreObjectArgument =
80288044
isa<CXXMethodDecl>(Candidate.Function) &&
8045+
cast<CXXMethodDecl>(Candidate.Function)
8046+
->isImplicitObjectMemberFunction() &&
80298047
!isa<CXXConstructorDecl>(Candidate.Function);
8048+
80308049
Candidate.ExplicitCallArguments = Args.size();
80318050
if (Result == TemplateDeductionResult::NonDependentConversionFailure)
80328051
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -8093,9 +8112,12 @@ bool Sema::CheckNonDependentConversions(
80938112
// that is correct.
80948113
const bool AllowExplicit = false;
80958114

8115+
bool ForOverloadSetAddressResolution =
8116+
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
80968117
auto *FD = FunctionTemplate->getTemplatedDecl();
80978118
auto *Method = dyn_cast<CXXMethodDecl>(FD);
8098-
bool HasThisConversion = Method && !isa<CXXConstructorDecl>(Method);
8119+
bool HasThisConversion = !ForOverloadSetAddressResolution && Method &&
8120+
!isa<CXXConstructorDecl>(Method);
80998121
unsigned ThisConversions = HasThisConversion ? 1 : 0;
81008122

81018123
if (Conversions.empty())
@@ -8165,7 +8187,8 @@ bool Sema::CheckNonDependentConversions(
81658187
};
81668188

81678189
unsigned Offset =
8168-
Method && Method->hasCXXExplicitFunctionObjectParameter() ? 1 : 0;
8190+
HasThisConversion && Method->hasCXXExplicitFunctionObjectParameter() ? 1
8191+
: 0;
81698192

81708193
for (unsigned I = 0, N = std::min(ParamTypes.size() - Offset, Args.size());
81718194
I != N; ++I) {
@@ -10780,7 +10803,8 @@ bool clang::isBetterOverloadCandidate(
1078010803
// any function G, and, symmetrically, ICS1(G) is neither
1078110804
// better nor worse than ICS1(F).
1078210805
unsigned StartArg = 0;
10783-
if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument)
10806+
if (!Cand1.TookAddressOfOverload &&
10807+
(Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument))
1078410808
StartArg = 1;
1078510809

1078610810
auto IsIllFormedConversion = [&](const ImplicitConversionSequence &ICS) {
@@ -11797,7 +11821,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1179711821
// non-constructor method. Note that 'I' corresponds the
1179811822
// conversion-slot index.
1179911823
bool isObjectArgument = false;
11800-
if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) {
11824+
if (!TakingCandidateAddress && isa<CXXMethodDecl>(Fn) &&
11825+
!isa<CXXConstructorDecl>(Fn)) {
1180111826
if (I == 0)
1180211827
isObjectArgument = true;
1180311828
else if (!Fn->hasCXXExplicitFunctionObjectParameter())
@@ -12296,7 +12321,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
1229612321
}
1229712322
case TemplateDeductionResult::TooManyArguments:
1229812323
case TemplateDeductionResult::TooFewArguments:
12299-
DiagnoseArityMismatch(S, Found, Templated, NumArgs);
12324+
DiagnoseArityMismatch(S, Found, Templated, NumArgs, TakingCandidateAddress);
1230012325
return;
1230112326

1230212327
case TemplateDeductionResult::InstantiationDepth:
@@ -13073,8 +13098,10 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
1307313098

1307413099
// Attempt to fix the bad conversion.
1307513100
unsigned ConvCount = Cand->Conversions.size();
13076-
for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); /**/;
13077-
++ConvIdx) {
13101+
for (unsigned ConvIdx =
13102+
((!Cand->TookAddressOfOverload && Cand->IgnoreObjectArgument) ? 1
13103+
: 0);
13104+
/**/; ++ConvIdx) {
1307813105
assert(ConvIdx != ConvCount && "no bad conversion in candidate");
1307913106
if (Cand->Conversions[ConvIdx].isInitialized() &&
1308013107
Cand->Conversions[ConvIdx].isBad()) {
@@ -13259,7 +13286,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
1325913286

1326013287
if (Cand->Function)
1326113288
NoteFunctionCandidate(S, Cand, Args.size(),
13262-
/*TakingCandidateAddress=*/false, DestAS);
13289+
Kind == CSK_AddressOfOverloadSet, DestAS);
1326313290
else if (Cand->IsSurrogate)
1326413291
NoteSurrogateCandidate(S, Cand);
1326513292
else {

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3885,6 +3885,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
38853885
TemplateDeductionInfo &Info,
38863886
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
38873887
bool PartialOverloading, bool PartialOrdering,
3888+
bool ForOverloadSetAddressResolution,
38883889
llvm::function_ref<bool(bool)> CheckNonDependent) {
38893890
// Unevaluated SFINAE context.
38903891
EnterExpressionEvaluationContext Unevaluated(
@@ -4034,7 +4035,10 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
40344035

40354036
auto ParamIdx = OriginalArg.ArgIdx;
40364037
unsigned ExplicitOffset =
4037-
Specialization->hasCXXExplicitFunctionObjectParameter() ? 1 : 0;
4038+
(Specialization->hasCXXExplicitFunctionObjectParameter() &&
4039+
!ForOverloadSetAddressResolution)
4040+
? 1
4041+
: 0;
40384042
if (ParamIdx >= Specialization->getNumParams() - ExplicitOffset)
40394043
// FIXME: This presumably means a pack ended up smaller than we
40404044
// expected while deducing. Should this not result in deduction
@@ -4681,6 +4685,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
46814685
Result = FinishTemplateArgumentDeduction(
46824686
FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
46834687
&OriginalCallArgs, PartialOverloading, PartialOrdering,
4688+
ForOverloadSetAddressResolution,
46844689
[&, CallingCtx](bool OnlyInitializeNonUserDefinedConversions) {
46854690
ContextRAII SavedContext(*this, CallingCtx);
46864691
return CheckNonDependent(ParamTypesForArgChecking,
@@ -4797,7 +4802,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
47974802
Result = FinishTemplateArgumentDeduction(
47984803
FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
47994804
/*OriginalCallArgs=*/nullptr, /*PartialOverloading=*/false,
4800-
/*PartialOrdering=*/true);
4805+
/*PartialOrdering=*/true, IsAddressOfFunction);
48014806
});
48024807
if (Result != TemplateDeductionResult::Success)
48034808
return Result;
@@ -4981,7 +4986,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
49814986
Result = FinishTemplateArgumentDeduction(
49824987
ConversionTemplate, Deduced, 0, ConversionSpecialized, Info,
49834988
&OriginalCallArgs, /*PartialOverloading=*/false,
4984-
/*PartialOrdering=*/false);
4989+
/*PartialOrdering=*/false, /*ForOverloadSetAddressResolution*/ false);
49854990
});
49864991
Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
49874992
return Result;

clang/test/CXX/drs/cwg26xx.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -345,14 +345,19 @@ void test() {
345345
namespace cwg2692 { // cwg2692: 19
346346
#if __cplusplus >= 202302L
347347

348-
struct A {
348+
struct A {
349349
static void f(A); // #cwg2692-1
350350
void f(this A); // #cwg2692-2
351351

352-
void g();
353-
};
352+
template <typename T>
353+
static void g(T); // #cwg2692-3
354+
template <typename T>
355+
void g(this T); // #cwg2692-4
356+
357+
void test();
358+
};
354359

355-
void A::g() {
360+
void A::test() {
356361
(&A::f)(A());
357362
// since-cxx23-error@-1 {{call to 'f' is ambiguous}}
358363
// since-cxx23-note@#cwg2692-1 {{candidate function}}
@@ -361,6 +366,16 @@ namespace cwg2692 { // cwg2692: 19
361366
// since-cxx23-error@-1 {{no matching function for call to 'f'}}
362367
// since-cxx23-note@#cwg2692-1 {{candidate function not viable: requires 1 argument, but 0 were provided}}
363368
// since-cxx23-note@#cwg2692-2 {{candidate function not viable: requires 1 argument, but 0 were provided}}
364-
}
369+
370+
371+
(&A::g)(A());
372+
// since-cxx23-error@-1 {{call to 'g' is ambiguous}}
373+
// since-cxx23-note@#cwg2692-3 {{candidate function}}
374+
// since-cxx23-note@#cwg2692-4 {{candidate function}}
375+
(&A::g<A>)();
376+
// since-cxx23-error@-1 {{no matching function for call to 'g'}}
377+
// since-cxx23-note@#cwg2692-3 {{candidate function template not viable: requires 1 argument, but 0 were provided}}
378+
// since-cxx23-note@#cwg2692-4 {{candidate function [with T = cwg2692::A] not viable: requires 1 argument, but 0 were provided}}
379+
}
365380
#endif
366381
} // namespace cwg2692

0 commit comments

Comments
 (0)