diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index dee335b526991..6ef2eec09ec02 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -7216,9 +7216,30 @@ TreeTransform::TransformElaboratedType(TypeLocBuilder &TLB, return QualType(); } - QualType NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc()); - if (NamedT.isNull()) - return QualType(); + QualType NamedT; + if (SemaRef.getLangOpts().CPlusPlus20 && QualifierLoc && + isa(TL.getNamedTypeLoc().getType())) { + TemplateSpecializationTypeLoc SpecTL = + TL.getNamedTypeLoc().castAs(); + const TemplateSpecializationType *TST = + SpecTL.getType()->castAs(); + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + if (TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) { + TemplateName InstName = getDerived().RebuildTemplateName( + SS, TL.getTemplateKeywordLoc(), *TD->getIdentifier(), + TL.getNamedTypeLoc().getBeginLoc(), /*ObjectType=*/QualType(), + /*FirstQualifierInScope=*/nullptr, /*AllowInjectedClassName=*/false); + if (InstName.isNull()) + return QualType(); + NamedT = TransformTemplateSpecializationType(TLB, SpecTL, InstName); + } + } + if (NamedT.isNull()) { + NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc()); + if (NamedT.isNull()) + return QualType(); + } // C++0x [dcl.type.elab]p2: // If the identifier resolves to a typedef-name or the simple-template-id diff --git a/clang/test/SemaCXX/PR91677.cpp b/clang/test/SemaCXX/PR91677.cpp new file mode 100644 index 0000000000000..cc8db60a438ea --- /dev/null +++ b/clang/test/SemaCXX/PR91677.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s +// expected-no-diagnostics + +template struct t1 { + template + struct t2 {}; +}; + +template +t1::template t2 f1(); + +void f2() { + f1(); +} 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 x; // precxx17-warning{{missing 'typename' prior to dependent type name B::X; implicit 'typename' is a C++20 extension}} + typedef B::X 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::B'}} }; }; template <> struct A::B { template struct X {}; - static const int arg = 0; + static const int arg = 0; // cxx17-note{{referenced member 'arg' is declared here}} }; - A::C::x a; + A::C::x a; // cxx17-note{{in instantiation of member class 'PR12884_original::A::C' requested here}} } namespace PR12884_half_fixed { template struct A {