[clang] [Clang][Sema] qualifier should be transformed (PR #94725)
Qizhi Hu via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 7 07:15:52 PDT 2024
https://github.com/jcsxky updated https://github.com/llvm/llvm-project/pull/94725
>From 2977f65d503c2a96247705ce50157870aaefa003 Mon Sep 17 00:00:00 2001
From: huqizhi <huqizhi at 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 | 18 +++++++++++++++++
.../SemaCXX/many-template-parameter-lists.cpp | 6 +++---
.../PR12884_original_no_crash.cpp | 20 +++++++++++++++++++
clang/test/SemaTemplate/PR91677.cpp | 14 +++++++++++++
clang/test/SemaTemplate/instantiate-scope.cpp | 8 ++++----
.../SemaTemplate/typename-specifier-3.cpp | 7 ++++---
7 files changed, 64 insertions(+), 10 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 b9c9070fcb22f..e775bd6494fc0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -846,6 +846,7 @@ Bug Fixes to C++ Support
- Fix a crash caused by improper use of ``__array_extent``. (#GH80474)
- Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307),
(#GH88081), (#GH89496), (#GH90669) and (#GH91633).
+- 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 3bfda09d5f80f..2fea4d9947870 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4568,6 +4568,24 @@ 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) {
+ SS.Adopt(TransformedQualifierLoc);
+ return getDerived().RebuildTemplateName(
+ SS, SourceLocation(), *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..b5d954986dd4f 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>::B<V>::C<W>::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..cfc3fc06bd4cf
--- /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}}
+}
\ No newline at end of file
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/instantiate-scope.cpp b/clang/test/SemaTemplate/instantiate-scope.cpp
index 733105674b7a4..3a1708a695ceb 100644
--- a/clang/test/SemaTemplate/instantiate-scope.cpp
+++ b/clang/test/SemaTemplate/instantiate-scope.cpp
@@ -11,10 +11,10 @@ template<typename T, typename U> using A = T;
// These definitions are OK, X<A<T, decltype(...)>...> is equivalent to X<T...>
// so this defines the member of the primary template.
template<typename ...T>
-void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{undeclared}}
+void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{use of undeclared identifier 'f'}}
template<typename ...T>
-int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{undeclared}}
+int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{use of undeclared identifier 'f'}}
struct Y {}; void f(Y);
@@ -25,6 +25,6 @@ void g() {
// Error, substitution fails; this should not be treated as a SFINAE-able
// condition, so we don't select X<void>::f(...).
- X<void>().f(0); // expected-note {{instantiation of}}
- X<void>::n = 1; // expected-note {{instantiation of}}
+ X<void>().f(0); // expected-note {{in instantiation of member function 'X<void>::f' requested here}}
+ X<void>::n = 1; // expected-note {{in instantiation of static data member 'X<void>::n' requested here}}
}
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 {
More information about the cfe-commits
mailing list