llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Qizhi Hu (jcsxky) <details> <summary>Changes</summary> --- Full diff: https://github.com/llvm/llvm-project/pull/94725.diff 6 Files Affected: - (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+3-4) - (modified) clang/lib/Sema/TreeTransform.h (+18) - (modified) clang/test/SemaCXX/many-template-parameter-lists.cpp (+3-3) - (added) clang/test/SemaTemplate/PR91677.cpp (+14) - (modified) clang/test/SemaTemplate/instantiate-scope.cpp (+8-7) - (modified) clang/test/SemaTemplate/typename-specifier-3.cpp (+4-3) ``````````diff 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 { `````````` </details> https://github.com/llvm/llvm-project/pull/94725 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits