https://github.com/mizvekov updated 
https://github.com/llvm/llvm-project/pull/133113

>From d1831e84e62f5a100de193619cbfdf9a1d403674 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizve...@gmail.com>
Date: Wed, 26 Mar 2025 12:26:40 -0300
Subject: [PATCH] [clang] fix deduction of member pointers with dependent named
 classes

This fixes a regression when interpreting a nested name specifier
for deduction purposes in member pointers.

This introduces a helper for fully translating a nested name specifier into a
type.

This regression was introduced here: 
https://github.com/llvm/llvm-project/pull/130537
and was reported here: 
https://github.com/llvm/llvm-project/pull/132401#issuecomment-2751489581

No release notes, since the regression was never released.
---
 clang/include/clang/AST/NestedNameSpecifier.h |  5 ++
 clang/lib/AST/NestedNameSpecifier.cpp         | 46 +++++++++++++++++++
 clang/lib/Sema/SemaExprCXX.cpp                | 26 ++---------
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 34 +++++++++-----
 clang/test/SemaCXX/member-pointer.cpp         | 43 +++++++++++++++++
 .../SemaTemplate/instantiation-backtrace.cpp  |  6 +--
 6 files changed, 122 insertions(+), 38 deletions(-)

diff --git a/clang/include/clang/AST/NestedNameSpecifier.h 
b/clang/include/clang/AST/NestedNameSpecifier.h
index 051d632f1cdf9..273e73e7c1e95 100644
--- a/clang/include/clang/AST/NestedNameSpecifier.h
+++ b/clang/include/clang/AST/NestedNameSpecifier.h
@@ -201,6 +201,11 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
     return nullptr;
   }
 
+  /// Fully translate this nested name specifier to a type.
+  /// Unlike getAsType, this will convert this entire nested
+  /// name specifier chain into its equivalent type.
+  const Type *translateToType(const ASTContext &Context) const;
+
   NestedNameSpecifierDependence getDependence() const;
 
   /// Whether this nested name specifier refers to a dependent
diff --git a/clang/lib/AST/NestedNameSpecifier.cpp 
b/clang/lib/AST/NestedNameSpecifier.cpp
index a256a87695afc..206e462a58a79 100644
--- a/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/clang/lib/AST/NestedNameSpecifier.cpp
@@ -245,6 +245,52 @@ bool NestedNameSpecifier::containsErrors() const {
   return getDependence() & NestedNameSpecifierDependence::Error;
 }
 
+const Type *
+NestedNameSpecifier::translateToType(const ASTContext &Context) const {
+  NestedNameSpecifier *Prefix = getPrefix();
+  switch (getKind()) {
+  case SpecifierKind::Identifier:
+    return Context
+        .getDependentNameType(ElaboratedTypeKeyword::None, Prefix,
+                              getAsIdentifier())
+        .getTypePtr();
+  case SpecifierKind::TypeSpec:
+  case SpecifierKind::TypeSpecWithTemplate: {
+    const Type *T = getAsType();
+    switch (T->getTypeClass()) {
+    case Type::DependentTemplateSpecialization: {
+      const auto *DT = cast<DependentTemplateSpecializationType>(T);
+      // FIXME: The type node can't represent the template keyword.
+      return Context
+          .getDependentTemplateSpecializationType(ElaboratedTypeKeyword::None,
+                                                  Prefix, DT->getIdentifier(),
+                                                  DT->template_arguments())
+          .getTypePtr();
+    }
+    case Type::Record:
+    case Type::TemplateSpecialization:
+    case Type::Using:
+    case Type::Enum:
+    case Type::Typedef:
+    case Type::UnresolvedUsing:
+      return Context
+          .getElaboratedType(ElaboratedTypeKeyword::None, Prefix,
+                             QualType(T, 0))
+          .getTypePtr();
+    default:
+      assert(Prefix == nullptr && "unexpected type with elaboration");
+      return T;
+    }
+  }
+  case SpecifierKind::Global:
+  case SpecifierKind::Namespace:
+  case SpecifierKind::NamespaceAlias:
+  case SpecifierKind::Super:
+    // These are not representable as types.
+    return nullptr;
+  }
+}
+
 /// Print this nested name specifier to the given output
 /// stream.
 void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 856b505e92214..b2310628adc64 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -60,30 +60,10 @@ ParsedType Sema::getInheritingConstructorName(CXXScopeSpec 
&SS,
                                               SourceLocation NameLoc,
                                               const IdentifierInfo &Name) {
   NestedNameSpecifier *NNS = SS.getScopeRep();
+  if (const IdentifierInfo *II = NNS->getAsIdentifier())
+    assert(II == &Name && "not a constructor name");
 
-  // Convert the nested-name-specifier into a type.
-  QualType Type;
-  switch (NNS->getKind()) {
-  case NestedNameSpecifier::TypeSpec:
-  case NestedNameSpecifier::TypeSpecWithTemplate:
-    Type = QualType(NNS->getAsType(), 0);
-    break;
-
-  case NestedNameSpecifier::Identifier:
-    // Strip off the last layer of the nested-name-specifier and build a
-    // typename type for it.
-    assert(NNS->getAsIdentifier() == &Name && "not a constructor name");
-    Type = Context.getDependentNameType(
-        ElaboratedTypeKeyword::None, NNS->getPrefix(), NNS->getAsIdentifier());
-    break;
-
-  case NestedNameSpecifier::Global:
-  case NestedNameSpecifier::Super:
-  case NestedNameSpecifier::Namespace:
-  case NestedNameSpecifier::NamespaceAlias:
-    llvm_unreachable("Nested name specifier is not a type for inheriting 
ctor");
-  }
-
+  QualType Type(NNS->translateToType(Context), 0);
   // This reference to the type is located entirely at the location of the
   // final identifier in the qualified-id.
   return CreateParsedType(Type,
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 410b5a2c83e8d..4f6383a40f457 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2127,19 +2127,29 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
               /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
           Result != TemplateDeductionResult::Success)
         return Result;
-      const Type *QP = MPP->getQualifier()->getAsType(),
-                 *QA = MPA->getQualifier()->getAsType();
-      CXXRecordDecl *ClsP = MPP->getMostRecentCXXRecordDecl(),
-                    *ClsA = MPA->getMostRecentCXXRecordDecl();
-      // FIXME: Don't drop the rest of the prefixes here.
-      QualType P = !ClsP || declaresSameEntity(QP->getAsCXXRecordDecl(), ClsP)
-                       ? QualType(QP, 0)
-                       : S.Context.getTypeDeclType(ClsP);
-      QualType A = !ClsA || declaresSameEntity(QA->getAsCXXRecordDecl(), ClsA)
-                       ? QualType(QA, 0)
-                       : S.Context.getTypeDeclType(ClsA);
+
+      QualType TP;
+      if (MPP->isSugared()) {
+        TP = S.Context.getTypeDeclType(MPP->getMostRecentCXXRecordDecl());
+      } else {
+        NestedNameSpecifier *QP = MPP->getQualifier();
+        if (QP->getKind() == clang::NestedNameSpecifier::Identifier)
+          // Skip translation if it's a non-deduced context anyway.
+          return TemplateDeductionResult::Success;
+        TP = QualType(QP->translateToType(S.Context), 0);
+      }
+      assert(!TP.isNull() && "member pointer with non-type class");
+
+      QualType TA;
+      if (MPA->isSugared()) {
+        TA = S.Context.getTypeDeclType(MPA->getMostRecentCXXRecordDecl());
+      } else {
+        NestedNameSpecifier *QA = MPA->getQualifier();
+        TA = QualType(QA->translateToType(S.Context), 0);
+      }
+      assert(!TA.isNull() && "member pointer with non-type class");
       return DeduceTemplateArgumentsByTypeMatch(
-          S, TemplateParams, P, A, Info, Deduced, SubTDF,
+          S, TemplateParams, TP, TA, Info, Deduced, SubTDF,
           degradeCallPartialOrderingKind(POK),
           /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
     }
diff --git a/clang/test/SemaCXX/member-pointer.cpp 
b/clang/test/SemaCXX/member-pointer.cpp
index fa3e6a5a4bcf7..c94c26fbcbb28 100644
--- a/clang/test/SemaCXX/member-pointer.cpp
+++ b/clang/test/SemaCXX/member-pointer.cpp
@@ -365,3 +365,46 @@ namespace adl_dependent_class {
   void f(A);
   void g() { f(d<C>); }
 } // namespace adl_dependent_class
+
+namespace deduction1 {
+  template <typename> struct RunCallImpl;
+
+  template <typename Derived>
+  struct RunCallImpl<int (Derived::Info::*)(Derived *)> {};
+
+  template <typename d>
+  void RunCall(d) {
+    RunCallImpl<d>();
+  }
+
+  struct Filter {
+    virtual void MakeCall();
+    virtual ~Filter() = default;
+  };
+
+  template <typename Derived>
+  struct ImplementFilter : Filter {
+    void MakeCall() { RunCall(&Derived::Info::OnStuffHandler); }
+  };
+
+  struct FoobarFilter : ImplementFilter<FoobarFilter> {
+    struct Info {
+      int OnStuffHandler(FoobarFilter *);
+    };
+  };
+} // namespace deduction1
+
+namespace deduction2 {
+  template <typename> struct A;
+  template <typename T>
+  struct A<void (T::C::*)(int &, T *)> {};
+  template <typename T> void e(T) {
+    A<T> f;
+  }
+  struct S {
+    struct C {
+      void h(int &, S *);
+    };
+    void i() { e(&C::h); }
+  };
+} // namespace deduction2
diff --git a/clang/test/SemaTemplate/instantiation-backtrace.cpp 
b/clang/test/SemaTemplate/instantiation-backtrace.cpp
index 39dfb0b32a2fb..6b51d0eba7979 100644
--- a/clang/test/SemaTemplate/instantiation-backtrace.cpp
+++ b/clang/test/SemaTemplate/instantiation-backtrace.cpp
@@ -22,7 +22,7 @@ void g() {
   (void)sizeof(B<X>); // expected-note{{in instantiation of template class 
'B<X>' requested here}}
 }
 
-template<typename T> 
+template<typename T>
 struct G : A<T>, // expected-error{{implicit instantiation of undefined 
template 'A<int>'}}
   A<T*> // expected-error{{implicit instantiation of undefined template 'A<int 
*>'}}
   { };
@@ -39,13 +39,13 @@ namespace PR13365 {
   template <class T1, class T2>
     typename ResultTy<T2>::error Deduce( void (T1::*member)(T2) ) {} // \
     // expected-note {{instantiation of template class 'PR13365::ResultTy<int 
&>'}} \
-    // expected-note {{substitution failure [with T1 = PR13365::Cls, T2 = int 
&]}}
+    // expected-note {{substitution failure [with T1 = Cls, T2 = int &]}}
 
   struct Cls {
     void method(int&);
   };
   void test() {
     Deduce(&Cls::method); // expected-error {{no matching function}} \
-                          // expected-note {{substituting deduced template 
arguments into function template 'Deduce' [with T1 = PR13365::Cls, T2 = int &]}}
+                          // expected-note {{substituting deduced template 
arguments into function template 'Deduce' [with T1 = Cls, T2 = int &]}}
   }
 }

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

Reply via email to