Author: Corentin Jabot
Date: 2025-07-10T14:05:23+02:00
New Revision: 39ea9b71d90f95a5d91d72004b37779d1ed6d72e

URL: 
https://github.com/llvm/llvm-project/commit/39ea9b71d90f95a5d91d72004b37779d1ed6d72e
DIFF: 
https://github.com/llvm/llvm-project/commit/39ea9b71d90f95a5d91d72004b37779d1ed6d72e.diff

LOG: [Clang] Correctly handle taking the address of an explicit object member 
function template (#147046)

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

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Sema/Sema.h
    clang/lib/Sema/SemaOverload.cpp
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/test/CXX/drs/cwg26xx.cpp
    clang/test/SemaCXX/cxx2b-deducing-this.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ec795a9d8214f..9048d7701e255 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -928,6 +928,8 @@ Bug Fixes to C++ Support
 - Fixed a crash when constant evaluating some explicit object member 
assignment operators. (#GH142835)
 - Fixed an access checking bug when substituting into concepts (#GH115838)
 - Fix a bug where private access specifier of overloaded function not 
respected. (#GH107629)
+- Correctly handles calling an explicit object member function template 
overload set
+  through its address (``(&Foo::bar<baz>)()``).
 - Correctly handle allocations in the condition of a ``if 
constexpr``.(#GH120197) (#GH134820)
 - Fixed a crash when handling invalid member using-declaration in C++20+ mode. 
(#GH63254)
 - Fix name lookup in lambda appearing in the body of a requires expression. 
(#GH147650)

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index dbba13df3dbe8..443a389ab6a18 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12501,6 +12501,7 @@ class Sema final : public SemaBase {
       sema::TemplateDeductionInfo &Info,
       SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
       bool PartialOverloading, bool PartialOrdering,
+      bool ForOverloadSetAddressResolution,
       llvm::function_ref<bool(bool)> CheckNonDependent =
           [](bool /*OnlyInitializeNonUserDefinedConversions*/) {
             return false;

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 34f512b13d6a8..7af3acacb5ba6 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -7700,18 +7700,6 @@ void Sema::AddMethodCandidate(
   EnterExpressionEvaluationContext Unevaluated(
       *this, Sema::ExpressionEvaluationContext::Unevaluated);
 
-  // Add this candidate
-  OverloadCandidate &Candidate =
-      CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);
-  Candidate.FoundDecl = FoundDecl;
-  Candidate.Function = Method;
-  Candidate.RewriteKind =
-      CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);
-  Candidate.TookAddressOfOverload =
-      CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
-  Candidate.ExplicitCallArguments = Args.size();
-  Candidate.StrictPackMatch = StrictPackMatch;
-
   bool IgnoreExplicitObject =
       (Method->isExplicitObjectMemberFunction() &&
        CandidateSet.getKind() ==
@@ -7727,6 +7715,23 @@ void Sema::AddMethodCandidate(
   unsigned NumParams = Method->getNumParams() - ExplicitOffset +
                        int(ImplicitObjectMethodTreatedAsStatic);
 
+  unsigned ExtraArgs =
+      CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet
+          ? 0
+          : 1;
+
+  // Add this candidate
+  OverloadCandidate &Candidate =
+      CandidateSet.addCandidate(Args.size() + ExtraArgs, EarlyConversions);
+  Candidate.FoundDecl = FoundDecl;
+  Candidate.Function = Method;
+  Candidate.RewriteKind =
+      CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);
+  Candidate.TookAddressOfOverload =
+      CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
+  Candidate.ExplicitCallArguments = Args.size();
+  Candidate.StrictPackMatch = StrictPackMatch;
+
   // (C++ 13.3.2p2): A candidate function having fewer than m
   // parameters is viable only if it has an ellipsis in its parameter
   // list (8.3.5).
@@ -7757,29 +7762,31 @@ void Sema::AddMethodCandidate(
   Candidate.Viable = true;
 
   unsigned FirstConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
-  if (ObjectType.isNull())
-    Candidate.IgnoreObjectArgument = true;
-  else if (Method->isStatic()) {
-    // [over.best.ics.general]p8
-    // When the parameter is the implicit object parameter of a static member
-    // function, the implicit conversion sequence is a standard conversion
-    // sequence that is neither better nor worse than any other standard
-    // conversion sequence.
-    //
-    // This is a rule that was introduced in C++23 to support static lambdas. 
We
-    // apply it retroactively because we want to support static lambdas as an
-    // extension and it doesn't hurt previous code.
-    Candidate.Conversions[FirstConvIdx].setStaticObjectArgument();
-  } else {
-    // Determine the implicit conversion sequence for the object
-    // parameter.
-    Candidate.Conversions[FirstConvIdx] = TryObjectArgumentInitialization(
-        *this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
-        Method, ActingContext, /*InOverloadResolution=*/true);
-    if (Candidate.Conversions[FirstConvIdx].isBad()) {
-      Candidate.Viable = false;
-      Candidate.FailureKind = ovl_fail_bad_conversion;
-      return;
+  if (!IgnoreExplicitObject) {
+    if (ObjectType.isNull())
+      Candidate.IgnoreObjectArgument = true;
+    else if (Method->isStatic()) {
+      // [over.best.ics.general]p8
+      // When the parameter is the implicit object parameter of a static member
+      // function, the implicit conversion sequence is a standard conversion
+      // sequence that is neither better nor worse than any other standard
+      // conversion sequence.
+      //
+      // This is a rule that was introduced in C++23 to support static lambdas.
+      // We apply it retroactively because we want to support static lambdas as
+      // an extension and it doesn't hurt previous code.
+      Candidate.Conversions[FirstConvIdx].setStaticObjectArgument();
+    } else {
+      // Determine the implicit conversion sequence for the object
+      // parameter.
+      Candidate.Conversions[FirstConvIdx] = TryObjectArgumentInitialization(
+          *this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
+          Method, ActingContext, /*InOverloadResolution=*/true);
+      if (Candidate.Conversions[FirstConvIdx].isBad()) {
+        Candidate.Viable = false;
+        Candidate.FailureKind = ovl_fail_bad_conversion;
+        return;
+      }
     }
   }
 
@@ -7807,7 +7814,7 @@ void Sema::AddMethodCandidate(
   // arguments.
   for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
     unsigned ConvIdx =
-        PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + 1);
+        PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + ExtraArgs);
     if (Candidate.Conversions[ConvIdx].isInitialized()) {
       // We already formed a conversion sequence for this parameter during
       // template argument deduction.
@@ -7876,6 +7883,7 @@ static void AddMethodTemplateCandidateImmediately(
   //   function template are combined with the set of non-template candidate
   //   functions.
   TemplateDeductionInfo Info(CandidateSet.getLocation());
+  auto *Method = cast<CXXMethodDecl>(MethodTmpl->getTemplatedDecl());
   FunctionDecl *Specialization = nullptr;
   ConversionSequenceList Conversions;
   if (TemplateDeductionResult Result = S.DeduceTemplateArguments(
@@ -7897,14 +7905,18 @@ static void AddMethodTemplateCandidateImmediately(
     OverloadCandidate &Candidate =
         CandidateSet.addCandidate(Conversions.size(), Conversions);
     Candidate.FoundDecl = FoundDecl;
-    Candidate.Function = MethodTmpl->getTemplatedDecl();
+    Candidate.Function = Method;
     Candidate.Viable = false;
     Candidate.RewriteKind =
       CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
     Candidate.IsSurrogate = false;
+    Candidate.TookAddressOfOverload =
+        CandidateSet.getKind() ==
+        OverloadCandidateSet::CSK_AddressOfOverloadSet;
+
     Candidate.IgnoreObjectArgument =
-        cast<CXXMethodDecl>(Candidate.Function)->isStatic() ||
-        ObjectType.isNull();
+        Method->isStatic() ||
+        (!Method->isExplicitObjectMemberFunction() && ObjectType.isNull());
     Candidate.ExplicitCallArguments = Args.size();
     if (Result == TemplateDeductionResult::NonDependentConversionFailure)
       Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -8024,9 +8036,16 @@ static void AddTemplateOverloadCandidateImmediately(
     Candidate.IsADLCandidate = llvm::to_underlying(IsADLCandidate);
     // Ignore the object argument if there is one, since we don't have an 
object
     // type.
+    Candidate.TookAddressOfOverload =
+        CandidateSet.getKind() ==
+        OverloadCandidateSet::CSK_AddressOfOverloadSet;
+
     Candidate.IgnoreObjectArgument =
         isa<CXXMethodDecl>(Candidate.Function) &&
+        cast<CXXMethodDecl>(Candidate.Function)
+            ->isImplicitObjectMemberFunction() &&
         !isa<CXXConstructorDecl>(Candidate.Function);
+
     Candidate.ExplicitCallArguments = Args.size();
     if (Result == TemplateDeductionResult::NonDependentConversionFailure)
       Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -8093,9 +8112,12 @@ bool Sema::CheckNonDependentConversions(
   // that is correct.
   const bool AllowExplicit = false;
 
+  bool ForOverloadSetAddressResolution =
+      CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
   auto *FD = FunctionTemplate->getTemplatedDecl();
   auto *Method = dyn_cast<CXXMethodDecl>(FD);
-  bool HasThisConversion = Method && !isa<CXXConstructorDecl>(Method);
+  bool HasThisConversion = !ForOverloadSetAddressResolution && Method &&
+                           !isa<CXXConstructorDecl>(Method);
   unsigned ThisConversions = HasThisConversion ? 1 : 0;
 
   if (Conversions.empty())
@@ -8165,7 +8187,8 @@ bool Sema::CheckNonDependentConversions(
   };
 
   unsigned Offset =
-      Method && Method->hasCXXExplicitFunctionObjectParameter() ? 1 : 0;
+      HasThisConversion && Method->hasCXXExplicitFunctionObjectParameter() ? 1
+                                                                           : 0;
 
   for (unsigned I = 0, N = std::min(ParamTypes.size() - Offset, Args.size());
        I != N; ++I) {
@@ -10780,7 +10803,8 @@ bool clang::isBetterOverloadCandidate(
   //      any function G, and, symmetrically, ICS1(G) is neither
   //      better nor worse than ICS1(F).
   unsigned StartArg = 0;
-  if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument)
+  if (!Cand1.TookAddressOfOverload &&
+      (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument))
     StartArg = 1;
 
   auto IsIllFormedConversion = [&](const ImplicitConversionSequence &ICS) {
@@ -11797,7 +11821,8 @@ static void DiagnoseBadConversion(Sema &S, 
OverloadCandidate *Cand,
   // non-constructor method.  Note that 'I' corresponds the
   // conversion-slot index.
   bool isObjectArgument = false;
-  if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) {
+  if (!TakingCandidateAddress && isa<CXXMethodDecl>(Fn) &&
+      !isa<CXXConstructorDecl>(Fn)) {
     if (I == 0)
       isObjectArgument = true;
     else if (!Fn->hasCXXExplicitFunctionObjectParameter())
@@ -12296,7 +12321,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl 
*Found, Decl *Templated,
   }
   case TemplateDeductionResult::TooManyArguments:
   case TemplateDeductionResult::TooFewArguments:
-    DiagnoseArityMismatch(S, Found, Templated, NumArgs);
+    DiagnoseArityMismatch(S, Found, Templated, NumArgs, 
TakingCandidateAddress);
     return;
 
   case TemplateDeductionResult::InstantiationDepth:
@@ -13073,8 +13098,10 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate 
*Cand,
 
   // Attempt to fix the bad conversion.
   unsigned ConvCount = Cand->Conversions.size();
-  for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); /**/;
-       ++ConvIdx) {
+  for (unsigned ConvIdx =
+           ((!Cand->TookAddressOfOverload && Cand->IgnoreObjectArgument) ? 1
+                                                                         : 0);
+       /**/; ++ConvIdx) {
     assert(ConvIdx != ConvCount && "no bad conversion in candidate");
     if (Cand->Conversions[ConvIdx].isInitialized() &&
         Cand->Conversions[ConvIdx].isBad()) {
@@ -13259,7 +13286,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, 
ArrayRef<Expr *> Args,
 
     if (Cand->Function)
       NoteFunctionCandidate(S, Cand, Args.size(),
-                            /*TakingCandidateAddress=*/false, DestAS);
+                            Kind == CSK_AddressOfOverloadSet, DestAS);
     else if (Cand->IsSurrogate)
       NoteSurrogateCandidate(S, Cand);
     else {

diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 94edd553aacd7..d09a72b71b805 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3885,6 +3885,7 @@ TemplateDeductionResult 
Sema::FinishTemplateArgumentDeduction(
     TemplateDeductionInfo &Info,
     SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
     bool PartialOverloading, bool PartialOrdering,
+    bool ForOverloadSetAddressResolution,
     llvm::function_ref<bool(bool)> CheckNonDependent) {
   // Unevaluated SFINAE context.
   EnterExpressionEvaluationContext Unevaluated(
@@ -4034,7 +4035,10 @@ TemplateDeductionResult 
Sema::FinishTemplateArgumentDeduction(
 
       auto ParamIdx = OriginalArg.ArgIdx;
       unsigned ExplicitOffset =
-          Specialization->hasCXXExplicitFunctionObjectParameter() ? 1 : 0;
+          (Specialization->hasCXXExplicitFunctionObjectParameter() &&
+           !ForOverloadSetAddressResolution)
+              ? 1
+              : 0;
       if (ParamIdx >= Specialization->getNumParams() - ExplicitOffset)
         // FIXME: This presumably means a pack ended up smaller than we
         // expected while deducing. Should this not result in deduction
@@ -4681,6 +4685,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
     Result = FinishTemplateArgumentDeduction(
         FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, 
Info,
         &OriginalCallArgs, PartialOverloading, PartialOrdering,
+        ForOverloadSetAddressResolution,
         [&, CallingCtx](bool OnlyInitializeNonUserDefinedConversions) {
           ContextRAII SavedContext(*this, CallingCtx);
           return CheckNonDependent(ParamTypesForArgChecking,
@@ -4797,7 +4802,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
     Result = FinishTemplateArgumentDeduction(
         FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, 
Info,
         /*OriginalCallArgs=*/nullptr, /*PartialOverloading=*/false,
-        /*PartialOrdering=*/true);
+        /*PartialOrdering=*/true, IsAddressOfFunction);
   });
   if (Result != TemplateDeductionResult::Success)
     return Result;
@@ -4981,7 +4986,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
     Result = FinishTemplateArgumentDeduction(
         ConversionTemplate, Deduced, 0, ConversionSpecialized, Info,
         &OriginalCallArgs, /*PartialOverloading=*/false,
-        /*PartialOrdering=*/false);
+        /*PartialOrdering=*/false, /*ForOverloadSetAddressResolution*/ false);
   });
   Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
   return Result;

diff  --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 60d896443ecd1..426fc6cab66a8 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -345,14 +345,19 @@ void test() {
 namespace cwg2692 { // cwg2692: 19
 #if __cplusplus >= 202302L
 
- struct A {
+struct A {
     static void f(A); // #cwg2692-1
     void f(this A); // #cwg2692-2
 
-    void g();
-  };
+    template <typename T>
+    static void g(T); // #cwg2692-3
+    template <typename T>
+    void g(this T); // #cwg2692-4
+
+    void test();
+};
 
-  void A::g() {
+void A::test() {
     (&A::f)(A());
     // since-cxx23-error@-1 {{call to 'f' is ambiguous}}
     //   since-cxx23-note@#cwg2692-1 {{candidate function}}
@@ -361,6 +366,16 @@ namespace cwg2692 { // cwg2692: 19
     // since-cxx23-error@-1 {{no matching function for call to 'f'}}
     //   since-cxx23-note@#cwg2692-1 {{candidate function not viable: requires 
1 argument, but 0 were provided}}
     //   since-cxx23-note@#cwg2692-2 {{candidate function not viable: requires 
1 argument, but 0 were provided}}
-  }
+
+
+    (&A::g)(A());
+    // since-cxx23-error@-1 {{call to 'g' is ambiguous}}
+    //   since-cxx23-note@#cwg2692-3 {{candidate function}}
+    //   since-cxx23-note@#cwg2692-4 {{candidate function}}
+    (&A::g<A>)();
+    // since-cxx23-error@-1 {{no matching function for call to 'g'}}
+    //   since-cxx23-note@#cwg2692-3 {{candidate function template not viable: 
requires 1 argument, but 0 were provided}}
+    //   since-cxx23-note@#cwg2692-4 {{candidate function [with T = 
cwg2692::A] not viable: requires 1 argument, but 0 were provided}}
+}
 #endif
 } // namespace cwg2692

diff  --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 2286da8d1c0e5..3a3dc8855d827 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1168,3 +1168,125 @@ struct S {
   bool g() { return f(); } // expected-error {{no viable conversion from 
returned value of type 'S' to function return type 'bool'}}
 };
 }
+
+namespace tpl_address {
+
+struct A {
+    template <typename T>
+    void a(this T self); // #tpl-address-a
+
+    template <typename T>
+    void b(this T&& self); // #tpl-address-b
+
+    template <typename T>
+    void c(this T self, int); // #tpl-address-c
+
+    template <typename T, typename U>
+    void d(this T self, U); // #tpl-address-d
+
+    template <typename T, typename U>
+    requires __is_same_as(U, int)  void e(this T self, U); // #tpl-address-e
+
+    template <typename T>
+    requires __is_same_as(T, int)  void f(this T self); // #tpl-address-f
+
+    template <typename T>
+    void g(this T self); // #tpl-address-g1
+
+    template <typename T>
+    void g(this T self, int); // #tpl-address-g2
+
+};
+
+void f() {
+    A a{};
+
+    (&A::a<A>)(a);
+
+    (&A::a)(a);
+
+    (&A::a<A>)();
+    // expected-error@-1 {{no matching function for call to 'a'}} \
+    // expected-note@#tpl-address-a {{candidate function [with T = 
tpl_address::A] not viable: requires 1 argument, but 0 were provided}}
+
+    (&A::a)();
+    // expected-error@-1 {{no matching function for call to 'a'}} \
+    // expected-note@#tpl-address-a {{candidate template ignored: couldn't 
infer template argument 'T'}}
+
+    (&A::a<A>)(0);
+    // expected-error@-1 {{no matching function for call to 'a'}} \
+    // expected-note@#tpl-address-a {{candidate function template not viable: 
no known conversion from 'int' to 'A' for 1st argument}}
+
+    (&A::a<A>)(a, 1);
+    // expected-error@-1 {{no matching function for call to 'a'}} \
+    // expected-note@#tpl-address-a {{candidate function template not viable: 
requires 1 argument, but 2 were provided}}
+
+
+    (&A::b<A>)(a);
+    // expected-error@-1 {{no matching function for call to 'b'}} \
+    // expected-note@#tpl-address-b{{candidate function template not viable: 
expects an rvalue for 1st argument}}
+
+    (&A::b)(a);
+
+    (&A::c<A>)(a, 0);
+
+    (&A::c<A>)(a);
+    // expected-error@-1 {{no matching function for call to 'c'}} \
+    // expected-note@#tpl-address-c{{candidate function [with T = 
tpl_address::A] not viable: requires 2 arguments, but 1 was provided}}
+
+    (&A::c<A>)(a, 0, 0);
+    // expected-error@-1 {{no matching function for call to 'c'}} \
+    // expected-note@#tpl-address-c{{candidate function template not viable: 
requires 2 arguments, but 3 were provided}}
+
+    (&A::c<A>)(a, a);
+    // expected-error@-1 {{no matching function for call to 'c'}} \
+    // expected-note@#tpl-address-c{{candidate function template not viable: 
no known conversion from 'A' to 'int' for 2nd argument}}
+
+    (&A::d)(a, 0);
+    (&A::d)(a, a);
+    (&A::d<A>)(a, 0);
+    (&A::d<A>)(a, a);
+    (&A::d<A, int>)(a, 0);
+
+    (&A::d<A, int>)(a, a);
+    // expected-error@-1 {{no matching function for call to 'd'}} \
+    // expected-note@#tpl-address-d{{no known conversion from 'A' to 'int' for 
2nd argument}}
+
+
+    (&A::e)(a, 0);
+    (&A::e)(a, a);
+    // expected-error@-1 {{no matching function for call to 'e'}} \
+    // expected-note@#tpl-address-e{{candidate template ignored: constraints 
not satisfied [with T = A, U = A]}} \
+    // expected-note@#tpl-address-e{{because '__is_same(tpl_address::A, int)' 
evaluated to false}}
+
+    (&A::e<A>)(a, 0);
+    (&A::e<A>)(a, a);
+    // expected-error@-1 {{no matching function for call to 'e'}} \
+    // expected-note@#tpl-address-e{{candidate template ignored: constraints 
not satisfied [with T = A, U = A]}} \
+    // expected-note@#tpl-address-e{{because '__is_same(tpl_address::A, int)' 
evaluated to false}}
+
+    (&A::e<A, int>)(a, 0);
+
+    (&A::f<int>)(0);
+    (&A::f)(0);
+
+    (&A::f<A>)(a);
+    // expected-error@-1 {{no matching function for call to 'f'}} \
+    // expected-note@#tpl-address-f{{candidate template ignored: constraints 
not satisfied [with T = A]}} \
+    // expected-note@#tpl-address-f{{because '__is_same(tpl_address::A, int)' 
evaluated to false}}
+
+    (&A::f)(a);
+    // expected-error@-1 {{no matching function for call to 'f'}} \
+    // expected-note@#tpl-address-f{{candidate template ignored: constraints 
not satisfied [with T = A]}} \
+    // expected-note@#tpl-address-f{{because '__is_same(tpl_address::A, int)' 
evaluated to false}}
+
+    (&A::g)(a);
+    (&A::g)(a, 0);
+    (&A::g)(a, 0, 0);
+    // expected-error@-1 {{no matching function for call to 'g'}} \
+    // expected-note@#tpl-address-g2 {{candidate function template not viable: 
requires 2 arguments, but 3 were provided}}\
+    // expected-note@#tpl-address-g1 {{candidate function template not viable: 
requires 1 argument, but 3 were provided}}
+}
+
+
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to