-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[Clang][Sema] qualifier should be transformed #94725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Qizhi Hu (jcsxky) ChangesFull diff: https://github.com/llvm/llvm-project/pull/94725.diff 6 Files Affected:
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 0681520764d9a..d30a9c2a2588f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -60,10 +60,9 @@ static bool SubstQualifier(Sema &SemaRef, const DeclT *OldDecl, DeclT *NewDecl,
!OldDecl->getLexicalDeclContext()->isDependentContext()) &&
"non-friend with qualified name defined in dependent context");
Sema::ContextRAII SavedContext(
- SemaRef,
- const_cast<DeclContext *>(NewDecl->getFriendObjectKind()
- ? NewDecl->getLexicalDeclContext()
- : OldDecl->getLexicalDeclContext()));
+ SemaRef, const_cast<DeclContext *>(NewDecl->getFriendObjectKind()
+ ? NewDecl->getLexicalDeclContext()
+ : NewDecl->getDeclContext()));
NestedNameSpecifierLoc NewQualifierLoc
= SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3bfda09d5f80f..b4d31cbbf0c7c 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/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..1f0f58d6a024e 100644
--- a/clang/test/SemaTemplate/instantiate-scope.cpp
+++ b/clang/test/SemaTemplate/instantiate-scope.cpp
@@ -2,7 +2,8 @@
template<typename ...T> struct X {
void f(int);
- void f(...);
+ void f(...); // expected-note {{member is declared here}} \
+ expected-note {{member is declared here}}
static int n;
};
@@ -11,11 +12,11 @@ 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 {{explicit qualification required to use member 'f' from dependent base class}} \
+ expected-error {{call to non-static member function without an object argument}}
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 {{explicit qualification required to use member 'f' from dependent base class}} \
+ expected-error {{call to non-static member function without an object argument}}
struct Y {}; void f(Y);
void g() {
@@ -25,6 +26,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..a62a1fc5ab39c 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}} \
+ cxx17-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; // cxx17-note{{referenced member 'arg' is declared here}}
};
- A<int>::C::x a;
+ A<int>::C::x a; // cxx17-note{{in instantiation of member class 'PR12884_original::A<int>::C' requested here}}
}
namespace PR12884_half_fixed {
template <typename T> struct A {
|
2977f65
to
a1754c5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
crash on trunk assertion.
I think this is missing one detail: We now have the same qualifier in two places: The elaborated type node attached to the TST, and in the name of the TST itself. While this is not ideal situation, I think it makes sense to just drop the TemplateName qualifier in the transform for now, so we don't keep transforming it twice, until we make the situation consistent again. Right now the NNS in the TST name is not printed, its only purpose there is to carry the template keyword information, which shouldn't be affected here. The fact that this change somehow affects program semantics is still unexpected and unexplained. As I said on the other PR, after we have built a TST, per current AST design, we shouldn't need the nested name specifier anymore beyond type sugar. So either we built this TST too early, as in it should have stayed as a DependentTemplateSpecializationType longer or some such, or there is something that needs to be rectified in the AST design, but I can't imagine what. If I had to take a guess, there is something wrong in the dependency computation for the NNS. Have you checked that? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs changes as discussed.
I am really appreciate for your guidance and I will check in the weekend. |
8327ee1
to
70928fc
Compare
@mizvekov After looking into the code, I think we should transform qualifier in TST. Consider the following code: template <typename T>
t1<T>::template t2<T> f1();
void f2() {
f1<bool>();
}
The case in
I didn't find some problems in dependency computation for the NNS. |
4b1d55c
to
8359bac
Compare
8359bac
to
4e9e322
Compare
So the NNS is already dependent, that's great. I still don't understand why you are saying we didn't or can't build a DependentTemplateSpecializationType instead. Yes, the template name needs to stay a DependentTemplateName for that. |
I mean we can transform template<typename T>
struct A<T*>::B<T*> |
But that goes against the natural flow of template instantiation. We can't go back from non-dependent into dependent. That's why I find this so confusing...
Can you elaborate on that? That still seems like the right path to me, you probably found another problem, that happens some times. |
Sorry, maybe I use the word 'transform' that makes you confused. Actually, what I did in llvm-project/clang/lib/Sema/SemaTemplate.cpp Line 4691 in e7622ab
llvm-project/clang/lib/Sema/SemaTemplate.cpp Lines 4741 to 4746 in e7622ab
I just tried to create llvm-project/clang/lib/Sema/SemaTemplate.cpp Lines 297 to 298 in e7622ab
|
Transform qualifier of
TemplateName
. Attempt to fix #91677 and some other issues.