https://github.com/jcsxky updated 
https://github.com/llvm/llvm-project/pull/94725

>From 4e9e322a82e636783d2ba0ccda92f3547d557a64 Mon Sep 17 00:00:00 2001
From: huqizhi <huqi...@feysh.com>
Date: Fri, 7 Jun 2024 14:04:52 +0800
Subject: [PATCH] [Clang][Sema] qualifier should be transformed

---
 clang/docs/ReleaseNotes.rst                   |  1 +
 clang/lib/Sema/TreeTransform.h                | 19 ++++++++++++++++++
 .../SemaCXX/many-template-parameter-lists.cpp |  6 +++---
 .../PR12884_original_no_crash.cpp             | 20 +++++++++++++++++++
 clang/test/SemaTemplate/PR91677.cpp           | 14 +++++++++++++
 .../SemaTemplate/typename-specifier-3.cpp     |  7 ++++---
 6 files changed, 61 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/SemaTemplate/PR12884_original_no_crash.cpp
 create mode 100644 clang/test/SemaTemplate/PR91677.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7ac0fa0141b47..8f217990a494c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -914,6 +914,7 @@ Bug Fixes to C++ Support
 - Clang now diagnoses explicit specializations with storage class specifiers 
in all contexts.
 - Fix an assertion failure caused by parsing a lambda used as a default 
argument for the value of a
   forward-declared class. (#GH93512).
+- Clang now transforms qualifier of template name. (#91677).
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index cf4e80399632b..6fd9f20647b0b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4568,6 +4568,25 @@ 
TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
   if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
     TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl();
     assert(Template && "qualified template name must refer to a template");
+    if (QTN->getQualifier()) {
+      CXXScopeSpec QualifierSS;
+      QualifierSS.MakeTrivial(getSema().getASTContext(), QTN->getQualifier(),
+                              NameLoc);
+      NestedNameSpecifierLoc QualifierLoc =
+          QualifierSS.getWithLocInContext(getSema().getASTContext());
+      NestedNameSpecifierLoc TransformedQualifierLoc =
+          getDerived().TransformNestedNameSpecifierLoc(QualifierLoc);
+      if (!TransformedQualifierLoc)
+        return Name;
+      if (getDerived().AlwaysRebuild() ||
+          QualifierLoc != TransformedQualifierLoc) {
+        QualifierSS.Adopt(TransformedQualifierLoc);
+        return getDerived().RebuildTemplateName(
+            QualifierSS, QTN->hasTemplateKeyword() ? SourceLocation() : 
NameLoc,
+            *Template->getIdentifier(), NameLoc, ObjectType,
+            FirstQualifierInScope, /*AllowInjectedClassName=*/true);
+      }
+    }
 
     TemplateDecl *TransTemplate
       = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc,
diff --git a/clang/test/SemaCXX/many-template-parameter-lists.cpp 
b/clang/test/SemaCXX/many-template-parameter-lists.cpp
index f98005c7e6fb5..4f447be06b926 100644
--- a/clang/test/SemaCXX/many-template-parameter-lists.cpp
+++ b/clang/test/SemaCXX/many-template-parameter-lists.cpp
@@ -5,7 +5,7 @@
 template <class T>
 struct X {
   template <class U>
-  struct A { // expected-note {{not-yet-instantiated member is declared here}}
+  struct A {
     template <class V>
     struct B {
       template <class W>
@@ -28,9 +28,9 @@ struct X {
   template <class X>
   template <class Y>
   template <class Z>
-  friend void A<U>::template B<V>::template C<W>::template D<X>::template 
E<Y>::operator+=(Z); // expected-warning {{not supported}} expected-error {{no 
member 'A' in 'X<int>'; it has not yet been instantiated}}
+  friend void A<U>::template B<V>::template C<W>::template D<X>::template 
E<Y>::operator+=(Z); // expected-warning {{dependent nested name specifier 
'A<U>::template B<V>::template C<W>::template D<X>::template E<Y>::' for friend 
class declaration is not supported; turning off access control for 'X'}}
 };
 
 void test() {
-  X<int>::A<int>::B<int>::C<int>::D<int>::E<int>() += 1.0; // expected-note 
{{in instantiation of template class 'X<int>' requested here}}
+  X<int>::A<int>::B<int>::C<int>::D<int>::E<int>() += 1.0;
 }
diff --git a/clang/test/SemaTemplate/PR12884_original_no_crash.cpp 
b/clang/test/SemaTemplate/PR12884_original_no_crash.cpp
new file mode 100644
index 0000000000000..f2b6f6e28c2f9
--- /dev/null
+++ b/clang/test/SemaTemplate/PR12884_original_no_crash.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+
+namespace PR12884_original {
+  template <typename T> struct A {
+    struct B {
+      template <typename U> struct X {};
+      typedef int arg;
+    };
+    struct C {
+      typedef B::X<typename B::arg> x; // expected-error{{typename specifier 
refers to non-type member 'arg' in 'PR12884_original::A<int>::B'}}
+    };
+  };
+
+  template <> struct A<int>::B {
+    template <int N> struct X {};
+    static const int arg = 0; // expected-note{{referenced member 'arg' is 
declared here}}
+  };
+
+  A<int>::C::x a; // expected-note{{in instantiation of member class 
'PR12884_original::A<int>::C' requested here}}
+}
diff --git a/clang/test/SemaTemplate/PR91677.cpp 
b/clang/test/SemaTemplate/PR91677.cpp
new file mode 100644
index 0000000000000..cc8db60a438ea
--- /dev/null
+++ b/clang/test/SemaTemplate/PR91677.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+// expected-no-diagnostics
+
+template <typename> struct t1 {
+  template <typename>
+  struct t2 {};
+};
+
+template <typename T>
+t1<T>::template t2<T> f1();
+
+void f2() {
+  f1<bool>();
+}
diff --git a/clang/test/SemaTemplate/typename-specifier-3.cpp 
b/clang/test/SemaTemplate/typename-specifier-3.cpp
index 714830f0032d2..40f9430386773 100644
--- a/clang/test/SemaTemplate/typename-specifier-3.cpp
+++ b/clang/test/SemaTemplate/typename-specifier-3.cpp
@@ -28,16 +28,17 @@ namespace PR12884_original {
       typedef int arg;
     };
     struct C {
-      typedef B::X<typename B::arg> x; // precxx17-warning{{missing 'typename' 
prior to dependent type name B::X; implicit 'typename' is a C++20 extension}}
+      typedef B::X<typename B::arg> x; // precxx17-warning{{missing 'typename' 
prior to dependent type name B::X; implicit 'typename' is a C++20 extension}} \
+                                       expected-error{{typename specifier 
refers to non-type member 'arg' in 'PR12884_original::A<int>::B'}}
     };
   };
 
   template <> struct A<int>::B {
     template <int N> struct X {};
-    static const int arg = 0;
+    static const int arg = 0; // expected-note{{referenced member 'arg' is 
declared here}}
   };
 
-  A<int>::C::x a;
+  A<int>::C::x a; // expected-note{{in instantiation of member class 
'PR12884_original::A<int>::C' requested here}}
 }
 namespace PR12884_half_fixed {
   template <typename T> struct A {

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

Reply via email to